diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aa9deee..d108fe2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,10 @@ v2.0.0 (IN PROGRESS) * Document `media` (Thanks LunarLambda for the report) * Added json serialization and deserialization for returned entities * Added missing event types and a catch-all event for streaming API +* Add v1 and v2 variants for `instance` +* Add canonical domain block support (`admin_canonical_email_blocks`, `admin_canonical_email_block`, `admin_canonical_email_block_create`, `admin_canonical_email_block_delete`) +* Add trending link timeline (`timeline_link`) +* Update suggestions endpoint and return value v1.8.1 ------ diff --git a/mastodon/timeline.py b/mastodon/timeline.py index 8b1b76a..88a6668 100644 --- a/mastodon/timeline.py +++ b/mastodon/timeline.py @@ -19,7 +19,7 @@ class Mastodon(Internals): remote: bool = False) -> PaginatableList[Status]: """ Fetch statuses, most recent ones first. `timeline` can be 'home', 'local', 'public', - 'tag/hashtag' or 'list/id'. See the following functions documentation for what those do. + 'tag/' or 'link/'. See the following functions documentation for what those do. The default timeline is the "home" timeline. @@ -103,3 +103,15 @@ class Mastodon(Internals): """ id = self.__unpack_id(id) return self.timeline(f'list/{id}', max_id=max_id, min_id=min_id, since_id=since_id, limit=limit, only_media=only_media, local=local, remote=remote) + + def timeline_link(self, url: str, local: bool = False, max_id: Optional[Union[Status, IdType, datetime]] = None, min_id: Optional[Union[Status, IdType, datetime]] = None, + since_id: Optional[Union[Status, IdType, datetime]] = None, limit: Optional[int] = None, only_media: bool = False, + remote: bool = False) -> PaginatableList[Status]: + """ + Convenience method: Fetch a timeline of toots linking to a given trending URL. Params as in `timeline()`. + + Note: The URL must be *exactly* the same as one fron `trending_links()`, including the protocol and potentially trailing slash. + + Raises a MastodonNotFoundError if the URL is not currently trending. + """ + return self.timeline(f'link?url={url}', max_id=max_id, min_id=min_id, since_id=since_id, limit=limit, only_media=only_media, local=local, remote=remote) \ No newline at end of file diff --git a/srcgen/return_types.json b/srcgen/return_types.json index 87db77d..4aad2c9 100644 --- a/srcgen/return_types.json +++ b/srcgen/return_types.json @@ -8688,7 +8688,7 @@ { "name": "Suggestion", "python_name": "Suggestion", - "func_call": "TODO_TO_BE_IMPLEMENTED", + "func_call": "mastodon.suggestions()[0]", "func_call_real": null, "func_call_additional": null, "func_alternate_acc": null, @@ -8703,13 +8703,39 @@ [ "3.4.0", "added" + ], + [ + "4.3.0", + "deprecated" ] ], "field_type": "str", "field_subtype": null, "field_structuretype": null, "is_optional": false, - "is_nullable": false + "is_nullable": false, + "is_deprecated": true + }, + "sources": { + "description": "The reasons this account is being suggested.", + "version_history": [ + [ + "4.3.0", + "added" + ] + ], + "field_type": "NonPaginatableList", + "field_subtype": "str", + "field_structuretype": "SuggestionSourceEnum", + "is_optional": false, + "is_nullable": false, + "enum": { + "featured": "Manually recommended by the instance staff", + "most_followed": "Account has many active local followers", + "most_interactions": "Account had many reblogs and favourites within the last 30 days", + "similar_to_recently_followed": "Acounts profile is similar in some way to the logged in users most recent follows", + "friends_of_friends": "Account is followed by people the logged in user follows." + } }, "account": { "description": "The account being recommended to follow.", diff --git a/tests/cassettes/test_timeline_link_fails.yaml b/tests/cassettes/test_timeline_link_fails.yaml new file mode 100644 index 0000000..dfecc28 --- /dev/null +++ b/tests/cassettes/test_timeline_link_fails.yaml @@ -0,0 +1,59 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN + Connection: + - keep-alive + User-Agent: + - tests/v311 + method: GET + uri: http://localhost:3000/api/v1/timelines/link?url=http://example.com/ + response: + body: + string: '{"error":"Record not found"}' + headers: + Cache-Control: + - private, no-store + Content-Length: + - '28' + Content-Security-Policy: + - default-src 'none'; frame-ancestors 'none'; form-action 'none' + Content-Type: + - application/json; charset=utf-8 + Referrer-Policy: + - strict-origin-when-cross-origin + Server-Timing: + - cache_read.active_support;dur=0.26, sql.active_record;dur=12.37, cache_generate.active_support;dur=25.97, + cache_write.active_support;dur=0.67, instantiation.active_record;dur=2.23, + start_processing.action_controller;dur=0.01, render.active_model_serializers;dur=0.16, + process_action.action_controller;dur=49.28 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-RateLimit-Limit: + - '300' + X-RateLimit-Remaining: + - '299' + X-RateLimit-Reset: + - '2025-02-14T21:25:00.035924Z' + X-Request-Id: + - e70e0187-3493-44c4-b6ee-4454d962875d + X-Runtime: + - '0.238071' + X-XSS-Protection: + - '0' + vary: + - Authorization, Origin + status: + code: 404 + message: Not Found +version: 1 diff --git a/tests/test_timeline.py b/tests/test_timeline.py index 552a779..36bf03e 100644 --- a/tests/test_timeline.py +++ b/tests/test_timeline.py @@ -1,6 +1,6 @@ import pytest import time -from mastodon.Mastodon import MastodonAPIError, MastodonIllegalArgumentError, MastodonUnauthorizedError +from mastodon.Mastodon import MastodonAPIError, MastodonIllegalArgumentError, MastodonUnauthorizedError, MastodonNotFoundError import datetime import pickle import os @@ -102,3 +102,9 @@ def test_min_max_id_datetimes(api, status): tl = api.timeline_home(min_id = the_future, max_id = the_far_future) assert not any(st["id"] == status["id"] for st in tl) + +@pytest.mark.vcr() +def test_timeline_link_fails(api): + with pytest.raises(MastodonNotFoundError): + api.timeline_link("http://example.com/") + \ No newline at end of file