From 19dbb4594ec4fe47c3e9704c8b9365e3834764c2 Mon Sep 17 00:00:00 2001 From: Aljoscha Rittner Date: Thu, 16 Jun 2022 14:52:15 +0200 Subject: [PATCH] Changes the storage for pagination information fixes #232 --- mastodon/Mastodon.py | 34 +++++++++++++++++++------ tests/cassettes/test_domain_blocks.yaml | 7 +++-- tests/test_pagination.py | 12 ++++----- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 98ac72a..c22cabe 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -120,10 +120,27 @@ class AttribAccessDict(dict): raise AttributeError("Attribute-style access is read only") super(AttribAccessDict, self).__setattr__(attr, val) + +### +# List helper class. +# Defined at top level so it can be pickled. +### +class AttribAccessList(list): + def __getattr__(self, attr): + if attr in self: + return self[attr] + else: + raise AttributeError("Attribute not found: " + str(attr)) + + def __setattr__(self, attr, val): + if attr in self: + raise AttributeError("Attribute-style access is read only") + super(AttribAccessList, self).__setattr__(attr, val) + + ### # The actual Mastodon class ### - class Mastodon: """ Thorough and easy to use Mastodon @@ -3040,8 +3057,8 @@ class Mastodon: Returns the next page or None if no further data is available. """ if isinstance(previous_page, list) and len(previous_page) != 0: - if hasattr(previous_page[-1], '_pagination_next'): - params = copy.deepcopy(previous_page[-1]._pagination_next) + if hasattr(previous_page, '_pagination_next'): + params = copy.deepcopy(previous_page._pagination_next) else: return None else: @@ -3064,8 +3081,8 @@ class Mastodon: Returns the previous page or None if no further data is available. """ if isinstance(next_page, list) and len(next_page) != 0: - if hasattr(next_page[0], '_pagination_prev'): - params = copy.deepcopy(next_page[0]._pagination_prev) + if hasattr(next_page, '_pagination_prev'): + params = copy.deepcopy(next_page._pagination_prev) else: return None else: @@ -3443,6 +3460,7 @@ class Mastodon: if isinstance(response, list) and \ 'Link' in response_object.headers and \ response_object.headers['Link'] != "": + response = AttribAccessList(response) tmp_urls = requests.utils.parse_header_links( response_object.headers['Link'].rstrip('>').replace('>,<', ',<')) for url in tmp_urls: @@ -3467,7 +3485,7 @@ class Mastodon: del next_params['since_id'] if "min_id" in next_params: del next_params['min_id'] - response[-1]._pagination_next = next_params + response._pagination_next = next_params if url['rel'] == 'prev': # Be paranoid and extract since_id or min_id specifically @@ -3486,7 +3504,7 @@ class Mastodon: prev_params['since_id'] = since_id if "max_id" in prev_params: del prev_params['max_id'] - response[0]._pagination_prev = prev_params + response._pagination_prev = prev_params # New and fantastico (post-2.6.0): min_id pagination matchgroups = re.search(r"[?&]min_id=([^&]+)", prev_url) @@ -3501,7 +3519,7 @@ class Mastodon: prev_params['min_id'] = min_id if "max_id" in prev_params: del prev_params['max_id'] - response[0]._pagination_prev = prev_params + response._pagination_prev = prev_params return response diff --git a/tests/cassettes/test_domain_blocks.yaml b/tests/cassettes/test_domain_blocks.yaml index 8889bb1..041541e 100644 --- a/tests/cassettes/test_domain_blocks.yaml +++ b/tests/cassettes/test_domain_blocks.yaml @@ -10,10 +10,13 @@ interactions: method: GET uri: http://localhost:3000/api/v1/domain_blocks response: - body: {string: '[]'} + body: {string: '["example.com"]'} headers: Cache-Control: ['no-cache, no-store'] Content-Type: [application/json; charset=utf-8] + Link: ['; + rel="next", ; + rel="prev"'] Referrer-Policy: [strict-origin-when-cross-origin] Transfer-Encoding: [chunked] Vary: ['Accept-Encoding, Origin'] @@ -24,6 +27,6 @@ interactions: X-Request-Id: [79ec8c37-a374-47e4-a698-a8b8511ca20f] X-Runtime: ['0.098492'] X-XSS-Protection: [1; mode=block] - content-length: ['2'] + content-length: ['15'] status: {code: 200, message: OK} version: 1 diff --git a/tests/test_pagination.py b/tests/test_pagination.py index 72ac06e..8a85ccb 100644 --- a/tests/test_pagination.py +++ b/tests/test_pagination.py @@ -39,9 +39,9 @@ def test_fetch_next_previous_from_pagination_info(api): account = api.account_verify_credentials() with many_statuses(api): statuses = api.account_statuses(account['id'], limit=5) - next_statuses = api.fetch_next(statuses[-1]._pagination_next) + next_statuses = api.fetch_next(statuses._pagination_next) assert next_statuses - previous_statuses = api.fetch_previous(next_statuses[0]._pagination_prev) + previous_statuses = api.fetch_previous(next_statuses._pagination_prev) assert previous_statuses def test_fetch_next_previous_old_pagination(api): @@ -61,9 +61,9 @@ def test_fetch_next_previous_from_pagination_info_old_pagination(api): with many_statuses(api): statuses = api.account_statuses(account['id'], limit=5) - next_statuses = api.fetch_next(statuses[-1]._pagination_next) + next_statuses = api.fetch_next(statuses._pagination_next) assert next_statuses - previous_statuses = api.fetch_previous(next_statuses[0]._pagination_prev) + previous_statuses = api.fetch_previous(next_statuses._pagination_prev) assert previous_statuses @pytest.mark.vcr() @@ -86,5 +86,5 @@ def test_link_headers(api): }) resp = api.timeline_hashtag(UNLIKELY_HASHTAG) - assert resp[0]._pagination_next['max_id'] == _id - assert resp[0]._pagination_prev['since_id'] == _id + assert resp._pagination_next['max_id'] == _id + assert resp._pagination_prev['since_id'] == _id