From b15cb85a2329c5152b84cf5aa301c069d918d37d Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Tue, 22 Nov 2022 09:51:09 +0100 Subject: [PATCH] Standardize http request method parameters This allows setting either json or data. Until now we were always using data and this is not enough for some endpoints. --- tests/test_api.py | 6 +++--- tests/test_console.py | 8 ++++---- toot/api.py | 16 ++++++++-------- toot/http.py | 34 ++++++++++++++++++---------------- toot/logging.py | 9 +++++++-- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 7bbe8eb..de3da73 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -17,7 +17,7 @@ def test_create_app(mock_post): create_app('bigfish.software') - mock_post.assert_called_once_with('https://bigfish.software/api/v1/apps', { + mock_post.assert_called_once_with('https://bigfish.software/api/v1/apps', json={ 'website': CLIENT_WEBSITE, 'client_name': CLIENT_NAME, 'scopes': SCOPES, @@ -48,7 +48,7 @@ def test_login(mock_post): login(app, 'user', 'pass') mock_post.assert_called_once_with( - 'https://bigfish.software/oauth/token', data, allow_redirects=False) + 'https://bigfish.software/oauth/token', data=data, allow_redirects=False) @mock.patch('toot.http.anon_post') @@ -70,4 +70,4 @@ def test_login_failed(mock_post): login(app, 'user', 'pass') mock_post.assert_called_once_with( - 'https://bigfish.software/oauth/token', data, allow_redirects=False) + 'https://bigfish.software/oauth/token', data=data, allow_redirects=False) diff --git a/tests/test_console.py b/tests/test_console.py index 86fb48a..cd26670 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -38,10 +38,10 @@ def test_post_defaults(mock_post, mock_uuid, capsys): console.run_command(app, user, 'post', ['Hello world']) - mock_post.assert_called_once_with(app, user, '/api/v1/statuses', { + mock_post.assert_called_once_with(app, user, '/api/v1/statuses', json={ 'status': 'Hello world', 'visibility': 'public', - 'media_ids[]': [], + 'media_ids': [], 'sensitive': "false", 'spoiler_text': None, 'in_reply_to_id': None, @@ -74,9 +74,9 @@ def test_post_with_options(mock_post, mock_uuid, capsys): console.run_command(app, user, 'post', args) - mock_post.assert_called_once_with(app, user, '/api/v1/statuses', { + mock_post.assert_called_once_with(app, user, '/api/v1/statuses', json={ 'status': 'Hello world', - 'media_ids[]': [], + 'media_ids': [], 'visibility': 'unlisted', 'sensitive': "true", 'spoiler_text': "Spoiler!", diff --git a/toot/api.py b/toot/api.py index 3b2ffcf..8ce9fad 100644 --- a/toot/api.py +++ b/toot/api.py @@ -27,14 +27,14 @@ def _status_action(app, user, status_id, action): def create_app(domain, scheme='https'): url = '{}://{}/api/v1/apps'.format(scheme, domain) - data = { + json = { 'client_name': CLIENT_NAME, 'redirect_uris': 'urn:ietf:wg:oauth:2.0:oob', 'scopes': SCOPES, 'website': CLIENT_WEBSITE, } - return http.anon_post(url, data).json() + return http.anon_post(url, json=json).json() def login(app, username, password): @@ -49,7 +49,7 @@ def login(app, username, password): 'scope': SCOPES, } - response = http.anon_post(url, data, allow_redirects=False) + response = http.anon_post(url, data=data, allow_redirects=False) # If auth fails, it redirects to the login page if response.is_redirect: @@ -79,7 +79,7 @@ def request_access_token(app, authorization_code): 'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', } - return http.anon_post(url, data, allow_redirects=False).json() + return http.anon_post(url, data=data, allow_redirects=False).json() def post_status( @@ -104,9 +104,9 @@ def post_status( # if the request is retried. headers = {"Idempotency-Key": uuid.uuid4().hex} - params = { + json = { 'status': status, - 'media_ids[]': media_ids, + 'media_ids': media_ids, 'visibility': visibility, 'sensitive': str_bool(sensitive), 'spoiler_text': spoiler_text, @@ -116,9 +116,9 @@ def post_status( } if content_type: - params['content_type'] = content_type + json['content_type'] = content_type - return http.post(app, user, '/api/v1/statuses', params, headers=headers).json() + return http.post(app, user, '/api/v1/statuses', json=json, headers=headers).json() def delete_status(app, user, status_id): diff --git a/toot/http.py b/toot/http.py index 6aff9a7..51286ef 100644 --- a/toot/http.py +++ b/toot/http.py @@ -47,9 +47,11 @@ def process_response(response): return response -def get(app, user, url, params=None): - url = app.base_url + url - headers = {"Authorization": "Bearer " + user.access_token} +def get(app, user, path, params=None, headers=None): + url = app.base_url + path + + headers = headers or {} + headers["Authorization"] = f"Bearer {user.access_token}" request = Request('GET', url, headers, params=params) response = send_request(request) @@ -64,29 +66,29 @@ def anon_get(url, params=None): return process_response(response) -def post(app, user, url, data=None, files=None, allow_redirects=True, headers={}): - url = app.base_url + url +def post(app, user, path, headers=None, files=None, data=None, json=None, allow_redirects=True): + url = app.base_url + path - headers["Authorization"] = "Bearer " + user.access_token + headers = headers or {} + headers["Authorization"] = f"Bearer {user.access_token}" - request = Request('POST', url, headers, files, data) - response = send_request(request, allow_redirects) - - return process_response(response) + return anon_post(url, headers=headers, files=files, data=data, json=json, allow_redirects=allow_redirects) -def delete(app, user, url, data=None): - url = app.base_url + url - headers = {"Authorization": "Bearer " + user.access_token} +def delete(app, user, path, data=None, headers=None): + url = app.base_url + path - request = Request('DELETE', url, headers=headers, data=data) + headers = headers or {} + headers["Authorization"] = f"Bearer {user.access_token}" + + request = Request('DELETE', url, headers=headers, json=data) response = send_request(request) return process_response(response) -def anon_post(url, data=None, files=None, allow_redirects=True): - request = Request('POST', url, {}, files, data) +def anon_post(url, headers=None, files=None, data=None, json=None, allow_redirects=True): + request = Request(method="POST", url=url, headers=headers, files=files, data=data, json=json) response = send_request(request, allow_redirects) return process_response(response) diff --git a/toot/logging.py b/toot/logging.py index 9730cca..e612020 100644 --- a/toot/logging.py +++ b/toot/logging.py @@ -1,3 +1,5 @@ +import json + from logging import getLogger logger = getLogger('toot') @@ -22,6 +24,9 @@ def log_request(request): if request.data: logger.debug(">>> DATA: \033[33m{}\033[0m".format(request.data)) + if request.json: + logger.debug(">>> JSON: \033[33m{}\033[0m".format(json.dumps(request.json))) + if request.files: logger.debug(">>> FILES: \033[33m{}\033[0m".format(request.files)) @@ -32,10 +37,10 @@ def log_request(request): def log_response(response): if response.ok: logger.debug("<<< \033[32m{}\033[0m".format(response)) - logger.debug("<<< \033[33m{}\033[0m".format(response.content)) + logger.debug("<<< \033[33m{}\033[0m".format(response.content.decode())) else: logger.debug("<<< \033[31m{}\033[0m".format(response)) - logger.debug("<<< \033[31m{}\033[0m".format(response.content)) + logger.debug("<<< \033[31m{}\033[0m".format(response.content.decode())) def log_debug(*msgs):