diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 00000000..bdaab28a --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,39 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/MANIFEST.in b/MANIFEST.in index 9561fb10..bb3ec5f0 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include README.rst +include README.md diff --git a/README.rst b/README.md similarity index 70% rename from README.rst rename to README.md index 41874d94..4c7cab56 100644 --- a/README.rst +++ b/README.md @@ -4,15 +4,12 @@ are cached, but the child objects are not. This can possibly be improved when the API allows for notification subscriptions; this would allow caching (assuming a connection was available to invalidate the cache as appropriate). -I've created a `Trello Board `_ -for feature requests, discussion and some development tracking. - Install ======= :: - pip install py-trello + pip install ha-py-trello Usage ===== @@ -92,12 +89,30 @@ To run the tests, run ``python -m unittest discover``. Four environment variable * ``TRELLO_API_KEY``: your Trello API key * ``TRELLO_TOKEN``: your Trello OAuth token -* ``TRELLO_TEST_BOARD_COUNT``: the number of boards in your Trello account -* ``TRELLO_TEST_BOARD_NAME``: name of the board to test card manipulation on. Must be unique, or the first match will be used -* ``TRELLO_TEST_STAR_COUNT``: the number of stars on your test Trello board -*WARNING*: The tests will delete all cards on the board called `TRELLO_TEST_BOARD_NAME`! +*NOTE*: **It's recommended to create a separate Trello account for testing. While the tests try to only modify or delete +resources they've created, to remove all possibility of unintentional data loss, we recommend not using a personal +Trello account with existing data.** To run tests across various Python versions, `tox `_ is supported. Install it -and simply run ``tox`` from the ``py-trello`` directory. +and simply run ``tox`` from the ``ha-py-trello`` directory. + +## Publishing +To publish, simply create a release on GitHub and a workflow will kick off to publish to PyPI. If you'd like to publish +locally, follow the below instructions. + +First ensure the appropriate tools are installed locally: +```shell +python3 -m pip install --upgrade build +python3 -m pip install --upgrade twine +``` +Then build and publish: +```shell +python3 -m build +python3 -m twine upload dist/* +``` +For more information see the [official packaging and publishing docs](https://packaging.python.org/en/latest/tutorials/packaging-projects). + +--- +*Forked from original: https://github.com/sarumont/py-trello* diff --git a/setup.py b/setup.py index 8513c22b..41844838 100755 --- a/setup.py +++ b/setup.py @@ -3,15 +3,15 @@ from setuptools import setup, find_packages setup( - name="py-trello", - version="0.20.1", + name="ha-py-trello", + version="0.24.1", - description='Python wrapper around the Trello API', - long_description=open('README.rst').read(), - author='Richard Kolkovich', - author_email='richard@sigil.org', - url='https://trello.com/board/py-trello/4f145d87b2f9f15d6d027b53', - download_url='https://github.com/sarumont/py-trello', + description='Python wrapper around the Trello API (Home Assistant specific)', + long_description=open('README.md').read(), + author='Scott Giminiani (originally Richard Kolkovich)', + author_email='scottg489@gmail.com', + url='https://github.com/ScottG489/ha-py-trello', + download_url='https://github.com/ScottG489/ha-py-trello', keywords='python', license='BSD License', classifiers=[ diff --git a/test/test_board.py b/test/test_board.py index 1582c537..72ec2148 100644 --- a/test/test_board.py +++ b/test/test_board.py @@ -13,17 +13,33 @@ class TrelloBoardTestCase(unittest.TestCase): independently. """ + _test_board_guid = "c0b8eaf5-d63e-4586-a2be-5d1567e22cc9" + @classmethod def setUpClass(cls): - cls._trello = TrelloClient(os.environ['TRELLO_API_KEY'], - token=os.environ['TRELLO_TOKEN']) - for b in cls._trello.list_boards(): - if b.name == os.environ['TRELLO_TEST_BOARD_NAME']: - cls._board = b - break - if not cls._board: - cls.fail("Couldn't find test board") - cls._list = cls._board.add_list(str(datetime.now())) + cls.clean_boards() + + @classmethod + def tearDownClass(cls): + cls.clean_boards() + + @classmethod + def clean_boards(cls): + trello = TrelloClient(os.environ['TRELLO_API_KEY'], + token=os.environ['TRELLO_TOKEN']) + for board in trello.list_boards(): + if cls._test_board_guid in board.name: + board.delete() + + def setUp(self): + self._trello = TrelloClient(os.environ['TRELLO_API_KEY'], + token=os.environ['TRELLO_TOKEN']) + self._board = self._trello.add_board(f"TEST BOARD ({TrelloBoardTestCase._test_board_guid})") + self._list = self._board.add_list(str(datetime.now())) + self._add_card("test_card") + + def tearDown(self): + self._board.delete() def _add_card(self, name, description=None): try: @@ -142,36 +158,28 @@ def test90_get_board(self): self.assertEqual(self._board.name, board.name) def test100_add_board(self): - test_board = self._trello.add_board("test_create_board") - test_list = test_board.add_list("test_list") + test_list = self._board.add_list("test_list") test_list.add_card("test_card") - open_boards = self._trello.list_boards(board_filter="open") - self.assertEqual(len([x for x in open_boards if x.name == "test_create_board"]), 1) + self.assertEqual(self._trello.get_board(self._board.id).id, self._board.id) def test110_copy_board(self): - boards = self._trello.list_boards(board_filter="open") - source_board = next( x for x in boards if x.name == "test_create_board") - self._trello.add_board("copied_board", source_board=source_board) - listed_boards = self._trello.list_boards(board_filter="open") - copied_board = next(iter([x for x in listed_boards if x.name == "copied_board"]), None) + copied_board = self._trello.add_board("Copied " + self._board.name, source_board=self._board) self.assertIsNotNone(copied_board) open_lists = copied_board.open_lists() self.assertEqual(len(open_lists), 4) # default lists plus mine test_list = open_lists[0] self.assertEqual(len(test_list.list_cards()), 1) - test_card = next ( iter([ x for x in test_list.list_cards() if x.name == "test_card"]), None ) + test_card = next(iter([x for x in test_list.list_cards() if x.name == "test_card"]), None) self.assertIsNotNone(test_card) + copied_board.delete() def test120_close_board(self): boards = self._trello.list_boards(board_filter="open") open_count = len(boards) - test_create_board = next( x for x in boards if x.name == "test_create_board") # type: Board - copied_board = next( x for x in boards if x.name == "copied_board") # type: Board - test_create_board.close() - copied_board.close() + self._board.close() still_open_boards = self._trello.list_boards(board_filter="open") still_open_count = len(still_open_boards) - self.assertEqual(still_open_count, open_count - 2) + self.assertEqual(still_open_count, open_count - 1) def test130_get_checklists_board(self): chklists = self._board.get_checklists(cards = 'open') diff --git a/test/test_card.py b/test/test_card.py index 575e48f5..8f799f32 100644 --- a/test/test_card.py +++ b/test/test_card.py @@ -13,18 +13,20 @@ class TrelloCardTestCase(unittest.TestCase): independently. """ + _trello = None + _board = None + @classmethod def setUpClass(cls): cls._trello = TrelloClient(os.environ['TRELLO_API_KEY'], token=os.environ['TRELLO_TOKEN']) - for b in cls._trello.list_boards(): - if b.name == os.environ['TRELLO_TEST_BOARD_NAME']: - cls._board = b - break - if not cls._board: - cls.fail("Couldn't find test board") + cls._board = cls._trello.add_board("TEST BOARD") cls._list = cls._board.add_list(str(datetime.now())) + @classmethod + def tearDownClass(cls): + cls._board.delete() + def _add_card(self, name, description=None): try: card = self._list.add_card(name, description) diff --git a/test/test_checklist.py b/test/test_checklist.py index b37d8bbe..433ecb5e 100644 --- a/test/test_checklist.py +++ b/test/test_checklist.py @@ -13,18 +13,20 @@ class TrelloChecklistTestCase(unittest.TestCase): independently. """ + _trello = None + _board = None + @classmethod def setUpClass(cls): cls._trello = TrelloClient(os.environ['TRELLO_API_KEY'], token=os.environ['TRELLO_TOKEN']) - for b in cls._trello.list_boards(): - if b.name == os.environ['TRELLO_TEST_BOARD_NAME']: - cls._board = b - break - if not cls._board: - cls.fail("Couldn't find test board") + cls._board = cls._trello.add_board("TEST BOARD") cls._list = cls._board.add_list(str(datetime.now())) + @classmethod + def tearDownClass(cls): + cls._board.delete() + def _add_card(self, name, description=None): try: card = self._list.add_card(name, description) diff --git a/test/test_trello_client.py b/test/test_trello_client.py index 904e7700..7a6ad243 100644 --- a/test/test_trello_client.py +++ b/test/test_trello_client.py @@ -3,7 +3,9 @@ import os import unittest from datetime import datetime -from trello import TrelloClient, Unauthorized, ResourceUnavailable +from trello import TrelloClient, Unauthorized, ResourceUnavailable, Board, List +from trello.batch.board import Board as BatchBoard +from trello.batch.batcherror import BatchError class TrelloClientTestCase(unittest.TestCase): @@ -19,10 +21,38 @@ def setUp(self): self._trello = TrelloClient(os.environ['TRELLO_API_KEY'], token=os.environ['TRELLO_TOKEN']) + def test_fetch_batch(self): + board = self._trello.add_board("TEST BOARD") + + batch_responses = self._trello.fetch_batch([ + BatchBoard.GetLists(board.id, ['id', 'name'], 'open', ['idCard']), + BatchBoard.GetBoard(board.id, ['id', 'name']), + BatchBoard.GetLists('123', ['name']) + ]) + board_lists = batch_responses[0] + boards = batch_responses[1] + batch_error = batch_responses[2] + + self.assertTrue(board_lists.success) + self.assertIsInstance(board_lists.payload[0], List) + self.assertEqual(len(board_lists.payload), 3) + + self.assertTrue(boards.success) + self.assertIsInstance(boards.payload, Board) + self.assertEqual(boards.payload.name, "TEST BOARD") + + self.assertFalse(batch_error.success) + self.assertIsInstance(batch_error.payload, BatchError) + self.assertEqual(batch_error.payload.message, "invalid id") + + board.delete() + def test01_list_boards(self): - self.assertEqual( - len(self._trello.list_boards(board_filter="open")), - int(os.environ['TRELLO_TEST_BOARD_COUNT'])) + board = self._trello.add_board("TEST BOARD") + boards = self._trello.list_boards(board_filter="open") + self.assertGreater(len(boards), 0) + self.assertIn(board, boards) + board.delete() def test10_board_attrs(self): boards = self._trello.list_boards() @@ -111,23 +141,18 @@ def test54_resource_unavailable(self): self.assertRaises(ResourceUnavailable, self._trello.get_card, '0') - def test_list_stars(self): - """ - Test trello client star list - """ - self.assertEqual(len(self._trello.list_stars()), int(os.environ["TRELLO_TEST_STAR_COUNT"]), "Number of stars does not match TRELLO_TEST_STAR_COUNT") - def test_add_delete_star(self): """ Test add and delete star to/from test board """ - test_board_id = self._trello.search(os.environ["TRELLO_TEST_BOARD_NAME"])[0].id - new_star = self._trello.add_star(test_board_id) + board = self._trello.add_board("TEST BOARD") + new_star = self._trello.add_star(board.id) star_list = self._trello.list_stars() self.assertTrue(new_star in star_list, "Star id was not added in list of starred boards") deleted_star = self._trello.delete_star(new_star) star_list = self._trello.list_stars() self.assertFalse(deleted_star in star_list, "Star id was not deleted from list of starred boards") + board.delete() class TrelloClientTestCaseWithoutOAuth(unittest.TestCase): """ diff --git a/trello/batch/__init__.py b/trello/batch/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trello/batch/batcherror.py b/trello/batch/batcherror.py new file mode 100644 index 00000000..145cf417 --- /dev/null +++ b/trello/batch/batcherror.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import with_statement, print_function, absolute_import + +from trello import TrelloBase +from trello.compat import force_str +from trello.member import Member + + +class BatchError: + """ + Class representing a BatchError + """ + def __init__(self, status_code, name, message): + super(BatchError, self).__init__() + self.status_code = status_code + self.name = name + self.message = message + + @classmethod + def from_json(cls, json_obj): + return BatchError(json_obj['statusCode'], json_obj['name'], json_obj['message']) + + def __repr__(self): + return force_str(u'' % self.name) diff --git a/trello/batch/batchresponse.py b/trello/batch/batchresponse.py new file mode 100644 index 00000000..4558d3a4 --- /dev/null +++ b/trello/batch/batchresponse.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import with_statement, print_function, absolute_import + +from trello import TrelloBase +from trello.compat import force_str +from trello.member import Member + + +class BatchResponse: + """ + Class representing a BatchError + """ + def __init__(self, payload, success): + super(BatchResponse, self).__init__() + self.payload = payload + self.success = success + + def __repr__(self): + return force_str(u'' % self.success) diff --git a/trello/batch/board.py b/trello/batch/board.py new file mode 100644 index 00000000..a9c0e8b0 --- /dev/null +++ b/trello/batch/board.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +from __future__ import with_statement, print_function, absolute_import + +from trello import Board as TrelloBoard +from trello.trellolist import List +import urllib.parse + + +class Board: + """ + 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). + """ + class GetLists: + def __init__(self, board_id, fields=None, cards=None, card_fields=None): + self.board_id = board_id + self.fields = fields if fields is not None else [] + self.cards = cards + self.card_fields = card_fields if card_fields is not None else [] + + def path(self): + path = f"/boards/{self.board_id}/lists" + params = {} + if self.fields: + fields = ','.join(field for field in self.fields) + params['fields'] = fields + if self.cards: + params['cards'] = self.cards + if self.card_fields: + params['card_fields'] = ','.join(field for field in self.card_fields) + path += "?" + urllib.parse.urlencode(params) if params else "" + return path + + def parse(self, json): + board = TrelloBoard(self.board_id) + lists = [] + for list_ in json: + lists.append(List.from_json(board, list_)) + return lists + + class GetBoard: + def __init__(self, board_id, fields=None): + self.board_id = board_id + self.fields = fields if fields is not None else [] + + def path(self): + path = f"/boards/{self.board_id}" + params = {} + if self.fields: + fields = ','.join(field for field in self.fields) + params['fields'] = fields + path += "?" + urllib.parse.urlencode(params) if params else "" + return path + + def parse(self, json): + return TrelloBoard.from_json(json_obj=json) diff --git a/trello/board.py b/trello/board.py index f6fa4166..e8a47972 100644 --- a/trello/board.py +++ b/trello/board.py @@ -57,13 +57,13 @@ def from_json(cls, trello_client=None, organization=None, json_obj=None): :json_obj: the json board object """ if organization is None: - board = Board(client=trello_client, board_id=json_obj['id'], name=json_obj['name']) + board = Board(client=trello_client, board_id=json_obj['id'], name=json_obj.get('name', None)) else: - board = Board(organization=organization, board_id=json_obj['id'], name=json_obj['name']) + board = Board(organization=organization, board_id=json_obj['id'], name=json_obj.get('name', None)) board.description = json_obj.get('desc', '') - board.closed = json_obj['closed'] - board.url = json_obj['url'] + board.closed = json_obj.get('closed', None) + board.url = json_obj.get('url', None) return board @@ -123,7 +123,7 @@ def open(self): http_method='PUT', post_args={'value': 'false', }, ) self.closed = False - + def delete(self): self.client.fetch_json( '/boards/' + self.id, @@ -192,7 +192,7 @@ def add_custom_field_definition(self, name, type, options=None, display_on_card= :name: name for the field :type: type of field: "checkbox", "list", "number", "text", "date" :options: list of options for field, only valid for "list" type - :display_on_card: boolean whether this field should be shown on the front of cards + :display_on_card: boolean whether this field should be shown on the front of cards :pos: position of the list: "bottom", "top" or a positive number :return: the custom_field_definition :rtype: CustomFieldDefinition @@ -215,7 +215,7 @@ def update_custom_field_definition(self, custom_field_definition_id, name=None, :custom_field_definition_id: the ID of the CustomFieldDefinition to update. :name: new name for the field - :display_on_card: boolean whether this field should be shown on the front of cards + :display_on_card: boolean whether this field should be shown on the front of cards :pos: position of the list: "bottom", "top" or a positive number :return: the custom_field_definition :rtype: CustomFieldDefinition @@ -227,7 +227,7 @@ def update_custom_field_definition(self, custom_field_definition_id, name=None, arguments["display/cardFront"] = u"true" if display_on_card else u"false" if pos: arguments["pos"] = pos - + json_obj = self.client.fetch_json( '/customFields/{0}'.format(custom_field_definition_id), http_method='PUT', @@ -245,7 +245,7 @@ def delete_custom_field_definition(self, custom_field_definition_id): '/customFields/{0}'.format(custom_field_definition_id), http_method='DELETE', ) return json_obj - + def get_custom_field_list_options(self,custom_field_definition_id,values_only=False): """Get custom field definition list options on this board @@ -278,7 +278,7 @@ def add_custom_field_list_option(self,custom_field_definition_id,new_option): post_args={'value': {'text':new_option}, }, ) return json_obj - + def get_custom_field_list_option(self,custom_field_definition_id,option_id): """Get a specific custom field definition list option on this board @@ -322,7 +322,7 @@ def get_labels(self, fields='all', limit=50): '/boards/' + self.id + '/labels', query_params={'fields': fields, 'limit': limit}) return Label.from_json_list(self, json_obj) - + def get_label(self, label_id): """ :label_id: str label id @@ -332,7 +332,7 @@ def get_label(self, label_id): json_obj = self.client.fetch_json( '/boards/' + self.id + '/labels/' + label_id ) - + return Label.from_json(self, json_obj) def get_checklists(self, cards='all'): @@ -458,7 +458,7 @@ def get_cards(self, filters=None, card_filter=""): ) return list([Card.from_json(self, json) for json in json_obj]) - + def get_card(self, card_id): """ :card_id: str card id. diff --git a/trello/card.py b/trello/card.py index c69a77d8..da95f2c3 100644 --- a/trello/card.py +++ b/trello/card.py @@ -139,27 +139,30 @@ def from_json(cls, parent, json_obj): raise Exception("key 'id' is not in json_obj") card = cls(parent, json_obj['id'], - name=json_obj['name']) + name=json_obj.get('name')) card._json_obj = json_obj card.desc = json_obj.get('desc', '') card.due = json_obj.get('due', '') - card.is_due_complete = json_obj['dueComplete'] - card.closed = json_obj['closed'] - card.url = json_obj['url'] - card.pos = json_obj['pos'] - card.shortUrl = json_obj['shortUrl'] - card.idMembers = json_obj['idMembers'] - card.member_ids = json_obj['idMembers'] - card.idLabels = json_obj['idLabels'] - card.idBoard = json_obj['idBoard'] - card.idList = json_obj['idList'] - card.idShort = json_obj['idShort'] - card.badges = json_obj['badges'] + card.is_due_complete = json_obj.get('dueComplete') + card.closed = json_obj.get('closed') + card.url = json_obj.get('url') + card.pos = json_obj.get('pos') + card.shortUrl = json_obj.get('shortUrl') + card.idMembers = json_obj.get('idMembers') + card.member_ids = json_obj.get('idMembers') + card.idLabels = json_obj.get('idLabels') + card.idBoard = json_obj.get('idBoard') + card.idList = json_obj.get('idList') + card.idShort = json_obj.get('idShort') + card.badges = json_obj.get('badges') card.customFields = card.fetch_custom_fields(json_obj=json_obj) - card.countCheckItems = json_obj['badges']['checkItems'] - card.countCheckLists = len(json_obj['idChecklists']) - card._labels = Label.from_json_list(card.board, json_obj['labels']) - card.dateLastActivity = dateparser.parse(json_obj['dateLastActivity']) + if json_obj.get('badges'): + card.countCheckItems = json_obj['badges']['checkItems'] + if json_obj.get('idChecklists'): + card.countCheckLists = len(json_obj['idChecklists']) + card._labels = Label.from_json_list(card.board, json_obj.get('labels', [])) + if json_obj.get('dateLastActivity'): + card.dateLastActivity = dateparser.parse(json_obj.get('dateLastActivity')) if "attachments" in json_obj: card._attachments = [] for attachment_json in json_obj["attachments"]: @@ -242,9 +245,6 @@ def get_comments(self): def fetch_checklists(self): - if self.countCheckLists == 0: - return [] - checklists = [] json_obj = self.client.fetch_json( '/cards/' + self.id + '/checklists', ) diff --git a/trello/checklist.py b/trello/checklist.py index 881a1f60..3d9d8a64 100644 --- a/trello/checklist.py +++ b/trello/checklist.py @@ -59,7 +59,7 @@ def clear(self): """Clear checklist by removing all checklist items""" # copy item list to prevent modifying while iterating, which would break # for-loops behaviour - old_items = items[:] + old_items = self.items[:] for item in old_items: self.delete_checklist_item(item) diff --git a/trello/trelloclient.py b/trello/trelloclient.py index 022ec649..048048a1 100644 --- a/trello/trelloclient.py +++ b/trello/trelloclient.py @@ -3,6 +3,9 @@ import json import requests from requests_oauthlib import OAuth1 + +from trello.batch.batcherror import BatchError +from trello.batch.batchresponse import BatchResponse from trello.board import Board from trello.card import Card from trello.trellolist import List @@ -198,6 +201,20 @@ def get_label(self, label_id, board_id): label_json = self.fetch_json('/labels/' + label_id) return Label.from_json(board, label_json) + def fetch_batch(self, batch_requests: list): + batch_responses = self.fetch_json( + "batch", + query_params={"urls": ",".join(batch_request.path() for batch_request in batch_requests)}) + + items = [] + for response, request in zip(batch_responses, batch_requests): + if "200" in response: + item = BatchResponse(request.parse(response['200']), True) + else: + item = BatchResponse(BatchError.from_json(response), False) + items.append(item) + return items + def fetch_json( self, uri_path, diff --git a/trello/trellolist.py b/trello/trellolist.py index 3b180280..e7dc9704 100644 --- a/trello/trellolist.py +++ b/trello/trellolist.py @@ -25,6 +25,7 @@ def __init__(self, board, list_id, name=''): self.closed = None self.pos = None self.subscribed = None + self.cards = [] @classmethod def from_json(cls, board, json_obj): @@ -34,13 +35,15 @@ def from_json(cls, board, json_obj): :board: the board object that the list belongs to :json_obj: the json list object """ - list = List(board, json_obj['id'], name=json_obj['name']) - list.closed = json_obj['closed'] - list.pos = json_obj['pos'] + list_ = List(board, json_obj['id'], name=json_obj.get('name', None)) + list_.closed = json_obj.get('closed', None) + list_.pos = json_obj.get('pos', None) #this method is also called from board.py with a different json object, so we need to make sure 'subscribed' is there if 'subscribed' in json_obj: - list.subscribed = json_obj['subscribed'] - return list + list_.subscribed = json_obj['subscribed'] + if 'cards' in json_obj: + list_.cards = [Card.from_json(list_, card) for card in json_obj['cards']] + return list_ def __repr__(self): return force_str(u'' % self.name) diff --git a/trello/util.py b/trello/util.py index 7c43ea46..3088f9db 100755 --- a/trello/util.py +++ b/trello/util.py @@ -31,7 +31,7 @@ def create_oauth_token(expiration=None, scope=None, key=None, secret=None, name= scope = scope or os.environ.get('TRELLO_SCOPE', 'read,write') trello_key = key or os.environ['TRELLO_API_KEY'] trello_secret = secret or os.environ['TRELLO_API_SECRET'] - name = name or os.environ.get('TRELLO_NAME', 'py-trello') + name = name or os.environ.get('TRELLO_NAME', 'ha-py-trello') # Step 1: Get a request token. This is a temporary token that is used for # having the user authorize an access token and to sign the request to obtain