diff --git a/trello/attachments.py b/trello/attachments.py index daeff872..50c2b49e 100644 --- a/trello/attachments.py +++ b/trello/attachments.py @@ -1,12 +1,15 @@ # -*- coding: utf-8 -*- from dateutil import parser as dateparser +from trello import TrelloBase -class Attachments(object): + +class Attachments(TrelloBase): """ https://developers.trello.com/advanced-reference/card#get-1-cards-card-id-or-shortlink-attachments """ def __init__(self, id, bytes, date, edge_color, idMember, is_upload, mime_type, name, previews, url): + super().__init__() self.id = id self.bytes = bytes self.date = dateparser.parse(date) @@ -36,15 +39,6 @@ def from_json(json_obj): def __repr__(self): return u"".format(self.name) - def __hash__(self): - class_name = type(self).__name__ - return hash(class_name) ^ hash(self.id) - - def __eq__(self, other): - if isinstance(other, type(self)): - return hash(self) == hash(other) - raise NotImplementedError - class AttachmentsPreview(object): def __init__(self, bytes, url, width, height, is_scaled): diff --git a/trello/base.py b/trello/base.py new file mode 100644 index 00000000..8684445b --- /dev/null +++ b/trello/base.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + + +class TrelloBase(object): + def __init__(self): + self.id = None + + def __hash__(self): + class_name = type(self).__name__ + return hash(class_name) ^ hash(self.id) + + def __eq__(self, other): + if isinstance(other, type(self)): + return hash(self) == hash(other) + raise NotImplementedError diff --git a/trello/board.py b/trello/board.py index f4c062c8..392bb03c 100644 --- a/trello/board.py +++ b/trello/board.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import with_statement, print_function, absolute_import + +from trello.base import TrelloBase from trello.member import Member from trello.card import Card from trello.compat import force_str @@ -9,396 +11,388 @@ from dateutil import parser as dateparser -class Board(object): - """ - Class representing a Trello board. Board attributes are stored as normal - Python attributes; access to all sub-objects, however, is always - an API call (Lists, Cards). - """ - - def __init__(self, client=None, board_id=None, organization=None, name=''): - """ - :trello: Reference to a Trello object - :board_id: ID for the board - - Alternative Constructor - - :organization: reference to the parent organization - :board_id: ID for this board - - """ - if organization is None: - self.client = client - else: - self.organization = organization - self.client = organization.client - self.id = board_id - self.name = name - - self.date_last_activity = None - - @classmethod - def from_json(cls, trello_client=None, organization=None, json_obj=None): - """ - Deserialize the board json object to a Board object - - :trello_client: the trello client - :json_obj: the board json object - - Alternative contrustraction: - - Deserialize the board json object to a board object - - :organization: the organization object that the board belongs to - :json_obj: the json board object - """ - if organization is None: - board = Board(client=trello_client, board_id=json_obj['id'], name=json_obj['name']) - else: - board = Board(organization=organization, board_id=json_obj['id'], name=json_obj['name']) - - board.description = json_obj.get('desc', '') - board.closed = json_obj['closed'] - board.url = json_obj['url'] - - try: - board.date_last_activity = dateparser.parse(json_obj['dateLastActivity']) - except: - pass - - return board - - def __repr__(self): - return force_str(u'' % self.name) - - def __hash__(self): - class_name = type(self).__name__ - return hash(class_name) ^ hash(self.id) - - def __eq__(self, other): - if isinstance(other, type(self)): - return hash(self) == hash(other) - raise NotImplementedError - - def fetch(self): - """Fetch all attributes for this board""" - json_obj = self.client.fetch_json('/boards/' + self.id) - self.name = json_obj['name'] - self.description = json_obj.get('desc', '') - self.closed = json_obj['closed'] - self.url = json_obj['url'] - try: - self.date_last_activity = dateparser.parse(json_obj['dateLastActivity']) - except: - self.date_last_activity = None - - # Saves a Trello Board - def save(self): - json_obj = self.client.fetch_json( - '/boards/', - http_method='POST', - post_args={'name': self.name, "desc": self.description, "defaultLists": False}, ) - # Set initial data from Trello - self.from_json(json_obj=json_obj) - self.id = json_obj["id"] - - def set_name(self, name): - self.client.fetch_json( - '/boards/{board_id}/name'.format(board_id=self.id), - http_method='PUT', - post_args={'value': name}) - self.name = name - - def set_description(self, desc): - self.client.fetch_json( - '/boards/{board_id}/desc'.format(board_id=self.id), - http_method='PUT', - post_args={'value': desc}) - self.description = desc - - def close(self): - self.client.fetch_json( - '/boards/' + self.id + '/closed', - http_method='PUT', - post_args={'value': 'true', }, ) - self.closed = True - - def open(self): - self.client.fetch_json( - '/boards/' + self.id + '/closed', - http_method='PUT', - post_args={'value': 'false', }, ) - self.closed = False - - def get_list(self, list_id): - """Get list - - :rtype: List - """ - obj = self.client.fetch_json('/lists/' + list_id) - return List.from_json(board=self, json_obj=obj) - - def all_lists(self): - """Returns all lists on this board - - :rtype: list of List - """ - return self.get_lists('all') - - def open_lists(self): - """Returns all open lists on this board - - :rtype: list of List - """ - return self.get_lists('open') - - def closed_lists(self): - """Returns all closed lists on this board - - :rtype: list of List - """ - return self.get_lists('closed') - - def get_lists(self, list_filter): - """Get lists from filter - - :rtype: list of List - """ - # error checking - json_obj = self.client.fetch_json( - '/boards/' + self.id + '/lists', - query_params={'cards': 'none', 'filter': list_filter}) - return [List.from_json(board=self, json_obj=obj) for obj in json_obj] - - def list_lists(self, list_filter='all'): - """Get lists from filter - - :rtype: list of List - """ - return self.get_lists(list_filter=list_filter) - - def get_labels(self, fields='all', limit=50): - """Get label - - :rtype: list of Label - """ - json_obj = self.client.fetch_json( - '/boards/' + self.id + '/labels', - query_params={'fields': fields, 'limit': limit}) - return Label.from_json_list(self, json_obj) - - def get_checklists(self, cards='all'): - """Get checklists - - :rtype: list of Checklist - """ - checklists = [] - json_obj = self.client.fetch_json( - '/boards/' + self.id + '/checklists', - query_params={'cards': cards}) - json_obj = sorted(json_obj, key=lambda checklist: checklist['pos']) - for cl in json_obj: - checklists.append(Checklist(self.client, cl.get('checkItemStates',[]), cl, - trello_card=cl.get('idCard'))) - return checklists - - def add_list(self, name, pos=None): - """Add a list to this board - - :name: name for the list - :pos: position of the list: "bottom", "top" or a positive number - :return: the list - :rtype: List - """ - arguments = {'name': name, 'idBoard': self.id} - if pos: - arguments["pos"] = pos - obj = self.client.fetch_json( - '/lists', - http_method='POST', - post_args=arguments, ) - return List.from_json(board=self, json_obj=obj) - - def add_label(self, name, color): - """Add a label to this board - - :name: name of the label - :color: the color, either green, yellow, orange - red, purple, blue, sky, lime, pink, or black - :return: the label - :rtype: Label - """ - obj = self.client.fetch_json( - '/labels', - http_method='POST', - post_args={'name': name, 'idBoard': self.id, 'color': color},) - return Label.from_json(board=self, json_obj=obj) - - def all_cards(self): - """Returns all cards on this board - - :rtype: list of Card - """ - filters = { - 'filter': 'all', - 'fields': 'all' - } - return self.get_cards(filters) - - def open_cards(self): - """Returns all open cards on this board - - :rtype: list of Card - """ - filters = { - 'filter': 'open', - 'fields': 'all' - } - return self.get_cards(filters) - - def closed_cards(self): - """Returns all closed cards on this board - - :rtype: list of Card - """ - filters = { - 'filter': 'closed', - 'fields': 'all' - } - return self.get_cards(filters) - - def get_cards(self, filters=None, card_filter=""): - """ - :filters: dict containing query parameters. Eg. {'fields': 'all'} - :card_filter: filters on card status ('open', 'closed', 'all') - - More info on card queries: - https://trello.com/docs/api/board/index.html#get-1-boards-board-id-cards - - :rtype: list of Card - """ - json_obj = self.client.fetch_json( - '/boards/' + self.id + '/cards/' + card_filter, - query_params=filters - ) - - return list([Card.from_json(self, json) for json in json_obj]) - - def all_members(self): - """Returns all members on this board - - :rtype: list of Member - """ - filters = { - 'filter': 'all', - 'fields': 'all' - } - return self.get_members(filters) - - def normal_members(self): - """Returns all normal members on this board - - :rtype: list of Member - """ - filters = { - 'filter': 'normal', - 'fields': 'all' - } - return self.get_members(filters) - - def admin_members(self): - """Returns all admin members on this board - - :rtype: list of Member - """ - filters = { - 'filter': 'admins', - 'fields': 'all' - } - return self.get_members(filters) - - def owner_members(self): - """Returns all owner members on this board - - :rtype: list of Member - """ - filters = { - 'filter': 'owners', - 'fields': 'all' - } - return self.get_members(filters) - - def get_members(self, filters=None): - """Get members with filter - - :filters: dict containing query parameters. - Eg. {'fields': 'all', 'filter': 'admins'} - - More info on possible filters: - https://developers.trello.com/advanced-reference/board#get-1-boards-board-id-members - - :rtype: list of Member - """ - json_obj = self.client.fetch_json( - '/boards/' + self.id + '/members', - query_params=filters) - members = list() - for obj in json_obj: - m = Member(self.client, obj['id']) - m.status = obj.get('status', '') - m.id = obj.get('id', '') - m.bio = obj.get('bio', '') - m.url = obj.get('url', '') - m.username = obj['username'] - m.full_name = obj['fullName'] - m.initials = obj.get('initials', '') - m.member_type = obj.get('memberType', '') - members.append(m) - - return members - - # Add a member to a board - def add_member(self, member, member_type="normal"): - json_obj = self.client.fetch_json( - '/boards/{0}/members/{1}'.format(self.id, member.id), - http_method='PUT', - post_args={'idMember': member.id, "type": member_type}, - ) - return json_obj - - # Removes an existing member of a board - def remove_member(self, member): - json_obj = self.client.fetch_json( - '/boards/{0}/members/{1}'.format(self.id, member.id), - http_method='DELETE', - post_args={'idMember': member.id}, - ) - return json_obj - - def fetch_actions(self, action_filter, action_limit=50, before=None, since=None): - """Returns all actions that conform to the given filters. - - :action_filter: str of possible actions separated by comma - ie. 'createCard,updateCard' - :action_limit: int of max items returned - :before: datetime obj - :since: datetime obj - - More info on action filter values: - https://developers.trello.com/advanced-reference/board#get-1-boards-board-id-actions - - :rtype: json list of past actions - """ - query_params = {'filter': action_filter, 'limit': action_limit} - - if since: - query_params["since"] = since - - if before: - query_params["before"] = before - - json_obj = self.client.fetch_json('/boards/' + self.id + '/actions', - query_params=query_params) - - self.actions = json_obj - return self.actions +class Board(TrelloBase): + """ + Class representing a Trello board. Board attributes are stored as normal + Python attributes; access to all sub-objects, however, is always + an API call (Lists, Cards). + """ + + def __init__(self, client=None, board_id=None, organization=None, name=''): + """ + :trello: Reference to a Trello object + :board_id: ID for the board + + Alternative Constructor + + :organization: reference to the parent organization + :board_id: ID for this board + + """ + super().__init__() + if organization is None: + self.client = client + else: + self.organization = organization + self.client = organization.client + self.id = board_id + self.name = name + + self.date_last_activity = None + + @classmethod + def from_json(cls, trello_client=None, organization=None, json_obj=None): + """ + Deserialize the board json object to a Board object + + :trello_client: the trello client + :json_obj: the board json object + + Alternative contrustraction: + + Deserialize the board json object to a board object + + :organization: the organization object that the board belongs to + :json_obj: the json board object + """ + if organization is None: + board = Board(client=trello_client, board_id=json_obj['id'], name=json_obj['name']) + else: + board = Board(organization=organization, board_id=json_obj['id'], name=json_obj['name']) + + board.description = json_obj.get('desc', '') + board.closed = json_obj['closed'] + board.url = json_obj['url'] + + try: + board.date_last_activity = dateparser.parse(json_obj['dateLastActivity']) + except: + pass + + return board + + def __repr__(self): + return force_str(u'' % self.name) + + def fetch(self): + """Fetch all attributes for this board""" + json_obj = self.client.fetch_json('/boards/' + self.id) + self.name = json_obj['name'] + self.description = json_obj.get('desc', '') + self.closed = json_obj['closed'] + self.url = json_obj['url'] + try: + self.date_last_activity = dateparser.parse(json_obj['dateLastActivity']) + except: + self.date_last_activity = None + + # Saves a Trello Board + def save(self): + json_obj = self.client.fetch_json( + '/boards/', + http_method='POST', + post_args={'name': self.name, "desc": self.description, "defaultLists": False}, ) + # Set initial data from Trello + self.from_json(json_obj=json_obj) + self.id = json_obj["id"] + + def set_name(self, name): + self.client.fetch_json( + '/boards/{board_id}/name'.format(board_id=self.id), + http_method='PUT', + post_args={'value': name}) + self.name = name + + def set_description(self, desc): + self.client.fetch_json( + '/boards/{board_id}/desc'.format(board_id=self.id), + http_method='PUT', + post_args={'value': desc}) + self.description = desc + + def close(self): + self.client.fetch_json( + '/boards/' + self.id + '/closed', + http_method='PUT', + post_args={'value': 'true', }, ) + self.closed = True + + def open(self): + self.client.fetch_json( + '/boards/' + self.id + '/closed', + http_method='PUT', + post_args={'value': 'false', }, ) + self.closed = False + + def get_list(self, list_id): + """Get list + + :rtype: List + """ + obj = self.client.fetch_json('/lists/' + list_id) + return List.from_json(board=self, json_obj=obj) + + def all_lists(self): + """Returns all lists on this board + + :rtype: list of List + """ + return self.get_lists('all') + + def open_lists(self): + """Returns all open lists on this board + + :rtype: list of List + """ + return self.get_lists('open') + + def closed_lists(self): + """Returns all closed lists on this board + + :rtype: list of List + """ + return self.get_lists('closed') + + def get_lists(self, list_filter): + """Get lists from filter + + :rtype: list of List + """ + # error checking + json_obj = self.client.fetch_json( + '/boards/' + self.id + '/lists', + query_params={'cards': 'none', 'filter': list_filter}) + return [List.from_json(board=self, json_obj=obj) for obj in json_obj] + + def list_lists(self, list_filter='all'): + """Get lists from filter + + :rtype: list of List + """ + return self.get_lists(list_filter=list_filter) + + def get_labels(self, fields='all', limit=50): + """Get label + + :rtype: list of Label + """ + json_obj = self.client.fetch_json( + '/boards/' + self.id + '/labels', + query_params={'fields': fields, 'limit': limit}) + return Label.from_json_list(self, json_obj) + + def get_checklists(self, cards='all'): + """Get checklists + + :rtype: list of Checklist + """ + checklists = [] + json_obj = self.client.fetch_json( + '/boards/' + self.id + '/checklists', + query_params={'cards': cards}) + json_obj = sorted(json_obj, key=lambda checklist: checklist['pos']) + for cl in json_obj: + checklists.append(Checklist(self.client, cl.get('checkItemStates', []), cl, + trello_card=cl.get('idCard'))) + return checklists + + def add_list(self, name, pos=None): + """Add a list to this board + + :name: name for the list + :pos: position of the list: "bottom", "top" or a positive number + :return: the list + :rtype: List + """ + arguments = {'name': name, 'idBoard': self.id} + if pos: + arguments["pos"] = pos + obj = self.client.fetch_json( + '/lists', + http_method='POST', + post_args=arguments, ) + return List.from_json(board=self, json_obj=obj) + + def add_label(self, name, color): + """Add a label to this board + + :name: name of the label + :color: the color, either green, yellow, orange + red, purple, blue, sky, lime, pink, or black + :return: the label + :rtype: Label + """ + obj = self.client.fetch_json( + '/labels', + http_method='POST', + post_args={'name': name, 'idBoard': self.id, 'color': color}, ) + return Label.from_json(board=self, json_obj=obj) + + def all_cards(self): + """Returns all cards on this board + + :rtype: list of Card + """ + filters = { + 'filter': 'all', + 'fields': 'all' + } + return self.get_cards(filters) + + def open_cards(self): + """Returns all open cards on this board + + :rtype: list of Card + """ + filters = { + 'filter': 'open', + 'fields': 'all' + } + return self.get_cards(filters) + + def closed_cards(self): + """Returns all closed cards on this board + + :rtype: list of Card + """ + filters = { + 'filter': 'closed', + 'fields': 'all' + } + return self.get_cards(filters) + + def get_cards(self, filters=None, card_filter=""): + """ + :filters: dict containing query parameters. Eg. {'fields': 'all'} + :card_filter: filters on card status ('open', 'closed', 'all') + + More info on card queries: + https://trello.com/docs/api/board/index.html#get-1-boards-board-id-cards + + :rtype: list of Card + """ + json_obj = self.client.fetch_json( + '/boards/' + self.id + '/cards/' + card_filter, + query_params=filters + ) + + return list([Card.from_json(self, json) for json in json_obj]) + + def all_members(self): + """Returns all members on this board + + :rtype: list of Member + """ + filters = { + 'filter': 'all', + 'fields': 'all' + } + return self.get_members(filters) + + def normal_members(self): + """Returns all normal members on this board + + :rtype: list of Member + """ + filters = { + 'filter': 'normal', + 'fields': 'all' + } + return self.get_members(filters) + + def admin_members(self): + """Returns all admin members on this board + + :rtype: list of Member + """ + filters = { + 'filter': 'admins', + 'fields': 'all' + } + return self.get_members(filters) + + def owner_members(self): + """Returns all owner members on this board + + :rtype: list of Member + """ + filters = { + 'filter': 'owners', + 'fields': 'all' + } + return self.get_members(filters) + + def get_members(self, filters=None): + """Get members with filter + + :filters: dict containing query parameters. + Eg. {'fields': 'all', 'filter': 'admins'} + + More info on possible filters: + https://developers.trello.com/advanced-reference/board#get-1-boards-board-id-members + + :rtype: list of Member + """ + json_obj = self.client.fetch_json( + '/boards/' + self.id + '/members', + query_params=filters) + members = list() + for obj in json_obj: + m = Member(self.client, obj['id']) + m.status = obj.get('status', '') + m.id = obj.get('id', '') + m.bio = obj.get('bio', '') + m.url = obj.get('url', '') + m.username = obj['username'] + m.full_name = obj['fullName'] + m.initials = obj.get('initials', '') + m.member_type = obj.get('memberType', '') + members.append(m) + + return members + + # Add a member to a board + def add_member(self, member, member_type="normal"): + json_obj = self.client.fetch_json( + '/boards/{0}/members/{1}'.format(self.id, member.id), + http_method='PUT', + post_args={'idMember': member.id, "type": member_type}, + ) + return json_obj + + # Removes an existing member of a board + def remove_member(self, member): + json_obj = self.client.fetch_json( + '/boards/{0}/members/{1}'.format(self.id, member.id), + http_method='DELETE', + post_args={'idMember': member.id}, + ) + return json_obj + + def fetch_actions(self, action_filter, action_limit=50, before=None, since=None): + """Returns all actions that conform to the given filters. + + :action_filter: str of possible actions separated by comma + ie. 'createCard,updateCard' + :action_limit: int of max items returned + :before: datetime obj + :since: datetime obj + + More info on action filter values: + https://developers.trello.com/advanced-reference/board#get-1-boards-board-id-actions + + :rtype: json list of past actions + """ + query_params = {'filter': action_filter, 'limit': action_limit} + + if since: + query_params["since"] = since + + if before: + query_params["before"] = before + + json_obj = self.client.fetch_json('/boards/' + self.id + '/actions', + query_params=query_params) + + self.actions = json_obj + return self.actions diff --git a/trello/card.py b/trello/card.py index 1008ca95..c9f62f94 100644 --- a/trello/card.py +++ b/trello/card.py @@ -6,6 +6,7 @@ import pytz from dateutil import parser as dateparser +from trello import TrelloBase from trello.attachments import Attachments from trello.checklist import Checklist from trello.compat import force_str @@ -13,7 +14,7 @@ from trello.organization import Organization -class Card(object): +class Card(TrelloBase): """ Class representing a Trello card. Card attributes are stored on the object @@ -120,6 +121,7 @@ def __init__(self, parent, card_id, name=''): :parent: reference to the parent trello list :card_id: ID for this card """ + super().__init__() if isinstance(parent, List): self.trello_list = parent self.board = parent.board @@ -171,15 +173,6 @@ def from_json(cls, parent, json_obj): def __repr__(self): return force_str(u'' % self.name) - def __hash__(self): - class_name = type(self).__name__ - return hash(class_name) ^ hash(self.id) - - def __eq__(self, other): - if isinstance(other, type(self)): - return hash(self) == hash(other) - raise NotImplementedError - def fetch(self, eager=True): """ Fetch all attributes for this card diff --git a/trello/checklist.py b/trello/checklist.py index a9b7d7c8..775d1d9e 100644 --- a/trello/checklist.py +++ b/trello/checklist.py @@ -1,14 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import with_statement, print_function, absolute_import + +from trello import TrelloBase from trello.compat import force_str -class Checklist(object): +class Checklist(TrelloBase): """ Class representing a Trello checklist. """ def __init__(self, client, checked, obj, trello_card=None): + super().__init__() self.client = client self.trello_card = trello_card self.id = obj['id'] @@ -130,12 +133,3 @@ def _get_item_index(self, name): def __repr__(self): return force_str(u'' % self.id) - - def __hash__(self): - class_name = type(self).__name__ - return hash(class_name) ^ hash(self.id) - - def __eq__(self, other): - if isinstance(other, type(self)): - return hash(self) == hash(other) - raise NotImplementedError diff --git a/trello/label.py b/trello/label.py index 17e5d2d8..4e193a79 100644 --- a/trello/label.py +++ b/trello/label.py @@ -1,13 +1,16 @@ # -*- coding: utf-8 -*- from __future__ import with_statement, print_function, absolute_import + +from trello import TrelloBase from trello.compat import force_str -class Label(object): +class Label(TrelloBase): """ Class representing a Trello Label. """ def __init__(self, client, label_id, name, color=""): + super().__init__() self.client = client self.id = label_id self.name = name @@ -34,15 +37,6 @@ def from_json_list(cls, board, json_objs): def __repr__(self): return force_str(u'