diff --git a/requirements-dev.txt b/requirements-dev.txt index 8dcedb5..dcc25b8 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ # # pip-compile --output-file=requirements-dev.txt requirements-dev.in # -astroid==3.0.3 +astroid==3.1.0 # via pylint authlib==1.3.0 # via safety @@ -20,11 +20,11 @@ click==8.1.7 # typer codecov==2.1.13 # via -r requirements-dev.in -coverage==7.4.1 +coverage==7.4.3 # via # -r requirements-dev.in # codecov -cryptography==42.0.2 +cryptography==42.0.5 # via authlib dill==0.3.8 # via pylint @@ -46,7 +46,7 @@ markdown-it-py==3.0.0 # via rich markupsafe==2.1.5 # via jinja2 -marshmallow==3.20.2 +marshmallow==3.21.1 # via safety mccabe==0.7.0 # via @@ -54,13 +54,13 @@ mccabe==0.7.0 # pylint mdurl==0.1.2 # via markdown-it-py -mypy==1.8.0 +mypy==1.9.0 # via -r requirements-dev.in mypy-extensions==1.0.0 # via mypy nose2==0.14.1 # via -r requirements-dev.in -packaging==23.0 +packaging==24.0 # via # dparse # marshmallow @@ -80,9 +80,9 @@ pyflakes==3.2.0 # via flake8 pygments==2.17.2 # via rich -pylint==3.0.3 +pylint==3.1.0 # via -r requirements-dev.in -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via freezegun pytz==2024.1 # via -r requirements-dev.in @@ -90,9 +90,9 @@ requests==2.31.0 # via # codecov # safety -rich==13.7.0 +rich==13.7.1 # via safety -ruamel-yaml==0.18.5 +ruamel-yaml==0.18.6 # via # safety # safety-schemas @@ -100,24 +100,24 @@ ruamel-yaml-clib==0.2.8 # via ruamel-yaml safety==3.0.1 # via -r requirements-dev.in -safety-schemas==0.0.1 +safety-schemas==0.0.2 # via safety six==1.16.0 # via python-dateutil -testfixtures==7.2.2 +testfixtures==8.1.0 # via -r requirements-dev.in -tomlkit==0.12.3 +tomlkit==0.12.4 # via pylint typer==0.9.0 # via safety -typing-extensions==4.9.0 +typing-extensions==4.10.0 # via # mypy # pydantic # safety # safety-schemas # typer -urllib3==2.2.0 +urllib3==2.2.1 # via # requests # safety diff --git a/requirements.txt b/requirements.txt index 6aaf6b2..7c32978 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ oauthlib==3.2.2 # via requests-oauthlib py-trello==0.19.0 # via -r requirements.in -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via py-trello pytz==2024.1 # via py-trello @@ -22,9 +22,9 @@ requests==2.31.0 # via # py-trello # requests-oauthlib -requests-oauthlib==1.3.1 +requests-oauthlib==1.4.0 # via py-trello six==1.16.0 # via python-dateutil -urllib3==2.2.0 +urllib3==2.2.1 # via requests diff --git a/src/trello_manager.py b/src/trello_manager.py index 012d9fc..39f922c 100644 --- a/src/trello_manager.py +++ b/src/trello_manager.py @@ -1,23 +1,79 @@ +import json import os import re from typing import Optional, Union from datetime import datetime, timedelta from pytz import UTC -from trello import TrelloClient, Board, List, Card, Label +from trello import Board, List, Card, Label +import trello class TrelloExecption(Exception): pass +def patched_fetch_json(self, + uri_path, + http_method='GET', + headers=None, + query_params=None, + post_args=None, + files=None): + """ Fetch some JSON from Trello """ + + # explicit values here to avoid mutable default values + if headers is None: + headers = {} + if query_params is None: + query_params = {} + if post_args is None: + post_args = {} + + # if files specified, we don't want any data + data = None + if files is None and post_args != {}: + data = json.dumps(post_args) + + # set content type and accept headers to handle JSON + if http_method in ("POST", "PUT", "DELETE") and not files: + headers['Content-Type'] = 'application/json; charset=utf-8' + + headers['Accept'] = 'application/json' + + # construct the full URL without query parameters + if uri_path[0] == '/': + uri_path = uri_path[1:] + url = f'https://api.trello.com/1/{uri_path}' + + if self.oauth is None: + query_params['key'] = self.api_key + query_params['token'] = self.api_secret + + # perform the HTTP requests, if possible uses OAuth authentication + response = self.http_service.request(http_method, url, params=query_params, + headers=headers, data=data, + auth=self.oauth, files=files, + proxies=self.proxies) + + if response.status_code == 401: + raise trello.Unauthorized(f"{response.text} at {url}", response) + if response.status_code != 200: + raise trello.ResourceUnavailable(f"{response.text} at {url}", response) + + return response.json() + + +trello.TrelloClient.fetch_json = patched_fetch_json + + class TrelloManager: # pylint: disable=too-few-public-methods _board_name = None # type: str _key = "TRELLO_API_KEY" _secret = "TRELLO_API_SECRET" def __init__(self): - self.client: TrelloClient = TrelloClient( + self.client: trello.TrelloClient = trello.TrelloClient( api_key=os.environ[self._key], api_secret=os.environ[self._secret] )