From 745d60057e81c0bdc79bcd890f6df81ccd241642 Mon Sep 17 00:00:00 2001 From: halcy Date: Sat, 15 Feb 2025 01:37:02 +0200 Subject: [PATCH] refactor id unpacking --- CHANGELOG.rst | 1 + mastodon/accounts.py | 22 ++---------------- mastodon/admin.py | 47 ++------------------------------------- mastodon/conversations.py | 9 -------- mastodon/favourites.py | 20 ----------------- mastodon/internals.py | 11 ++++++--- mastodon/lists.py | 12 +--------- mastodon/notifications.py | 16 ++++--------- mastodon/relationships.py | 36 ------------------------------ mastodon/search.py | 2 +- mastodon/statuses.py | 6 ++--- mastodon/timeline.py | 11 +-------- mastodon/types_base.py | 5 +++-- 13 files changed, 25 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0c9fb49..ed33241 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,6 +32,7 @@ v2.0.0 (IN PROGRESS) * Add forward_to_domains parameter to reports * Add `account_delete_avatar` and `account_delete_header` * Add `statuses` method to retrieve multiple statuses at once +* Add automatic conversion of datetime objects to flake IDs for min/max/since_id fields where appropriate v1.8.1 ------ diff --git a/mastodon/accounts.py b/mastodon/accounts.py index 94b8ebc..f093331 100644 --- a/mastodon/accounts.py +++ b/mastodon/accounts.py @@ -207,16 +207,7 @@ class Mastodon(Internals): Fetch users the given user is following. """ id = self.__unpack_id(id) - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - - params = self.__generate_params(locals(), ['id']) + params = self.__generate_params(locals(), ['id'], dateconv=True) return self.__api_request('GET', f'/api/v1/accounts/{id}/following', params) @api_version("1.0.0", "2.6.0", _DICT_VERSION_ACCOUNT) @@ -227,16 +218,7 @@ class Mastodon(Internals): Fetch users the given user is followed by. """ id = self.__unpack_id(id) - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - - params = self.__generate_params(locals(), ['id']) + params = self.__generate_params(locals(), ['id'], dateconv=True) return self.__api_request('GET', f'/api/v1/accounts/{id}/followers', params) @api_version("1.0.0", "1.4.0", _DICT_VERSION_RELATIONSHIP) diff --git a/mastodon/admin.py b/mastodon/admin.py index 8494e20..56b9512 100644 --- a/mastodon/admin.py +++ b/mastodon/admin.py @@ -38,15 +38,6 @@ class Mastodon(Internals): Pagination on this is a bit weird, so I would recommend not doing that and instead manually fetching. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - if role_ids is not None: if not isinstance(role_ids, list): role_ids = [role_ids] @@ -67,7 +58,7 @@ class Mastodon(Internals): if not by_domain is None: by_domain = self.__deprotocolize(by_domain) - params = self.__generate_params(locals()) + params = self.__generate_params(locals(), dateconv=True) return self.__api_request('GET', '/api/v2/admin/accounts', params) @api_version("2.9.1", "2.9.1", _DICT_VERSION_ADMIN_ACCOUNT) @@ -122,16 +113,7 @@ class Mastodon(Internals): Pagination on this is a bit weird, so I would recommend not doing that and instead manually fetching. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - - params = self.__generate_params(locals(), ['remote', 'status', 'staff_only']) + params = self.__generate_params(locals(), ['remote', 'status', 'staff_only'], dateconv=True) if remote: params["remote"] = True @@ -279,15 +261,6 @@ class Mastodon(Internals): Returns a list of :ref:`report dicts `. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - if account_id is not None: account_id = self.__unpack_id(account_id) @@ -388,15 +361,6 @@ class Mastodon(Internals): Returns a list of :ref:`admin domain block dicts `, raises a `MastodonAPIError` if the specified block does not exist. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - if id is not None: id = self.__unpack_id(id) return self.__api_request('GET', f'/api/v1/admin/domain_blocks/{id}') @@ -607,13 +571,6 @@ class Mastodon(Internals): The returned list may be paginated using max_id, min_id, and since_id. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - if min_id is not None: - min_id = self.__unpack_id(min_id) - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/admin/canonical_email_blocks', params) diff --git a/mastodon/conversations.py b/mastodon/conversations.py index 3db2a05..b42da0c 100644 --- a/mastodon/conversations.py +++ b/mastodon/conversations.py @@ -17,15 +17,6 @@ class Mastodon(Internals): """ Fetches a user's conversations. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', "/api/v1/conversations/", params) diff --git a/mastodon/favourites.py b/mastodon/favourites.py index 8d27b2f..c3ca14c 100644 --- a/mastodon/favourites.py +++ b/mastodon/favourites.py @@ -20,18 +20,7 @@ class Mastodon(Internals): This endpoint uses internal ids for pagination, passing status ids to `max_id`, `min_id`, or `since_id` will not work. - - Returns a list of :ref:`status dicts `. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/favourites', params) @@ -47,14 +36,5 @@ class Mastodon(Internals): This endpoint uses internal ids for pagination, passing status ids to `max_id`, `min_id`, or `since_id` will not work. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/bookmarks', params) diff --git a/mastodon/internals.py b/mastodon/internals.py index 1bba642..4f9a768 100644 --- a/mastodon/internals.py +++ b/mastodon/internals.py @@ -480,7 +480,7 @@ class Mastodon(): with closing(connection) as r: listener.handle_stream(r) - def __generate_params(self, params, exclude=[]): + def __generate_params(self, params, exclude=[], dateconv=False): """ Internal named-parameters-to-dict helper. @@ -509,6 +509,13 @@ class Mastodon(): params[key + "[]"] = params[key] del params[key] + # Unpack min/max/since_id fields, since that is a very common operation + # and we basically always want it + for key in param_keys: + if key in ['min_id', 'max_id', 'since_id']: + print("Unpacking", key) + params[key] = self.__unpack_id(params[key], dateconv = dateconv, listify = False) + return params def __unpack_id(self, id, dateconv = False, listify = False, field = "id"): @@ -520,8 +527,6 @@ class Mastodon(): the id straight. Also unpacks datetimes to snowflake IDs if requested. - - TODO: Rework this to use the new type system. """ if id is None: return None diff --git a/mastodon/lists.py b/mastodon/lists.py index 68411b8..cd7f46f 100644 --- a/mastodon/lists.py +++ b/mastodon/lists.py @@ -35,17 +35,7 @@ class Mastodon(Internals): Get the accounts that are on the given list. """ id = self.__unpack_id(id) - - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - - params = self.__generate_params(locals(), ['id']) + params = self.__generate_params(locals(), ['id'], dateconv=True) return self.__api_request('GET', f'/api/v1/lists/{id}/accounts', params) ### diff --git a/mastodon/notifications.py b/mastodon/notifications.py index b214f8d..307a9aa 100644 --- a/mastodon/notifications.py +++ b/mastodon/notifications.py @@ -29,8 +29,9 @@ class Mastodon(Internals): * `poll` - A poll the logged in user created or voted in has ended * `update` - A status the logged in user has reblogged (and only those, as of 4.0.0) has been edited * `status` - A user that the logged in user has enabned notifications for has enabled `notify` (see :ref:`account_follow() `) - * `admin.sign_up` - For accounts with appropriate permissions (TODO: document which those are when adding the permission API): A new user has signed up - * `admin.report` - For accounts with appropriate permissions (TODO: document which those are when adding the permission API): A new report has been received + * `admin.sign_up` - For accounts with appropriate permissions: A new user has signed up + * `admin.report` - For accounts with appropriate permissions: A new report has been received + * TODO: document the rest Parameters `exclude_types` and `types` are array of these types, specifying them will in- or exclude the types of notifications given. It is legal to give both parameters at the same tine, the result will then be the intersection of the results of both filters. Specifying `mentions_only` is a deprecated way to set @@ -51,20 +52,11 @@ class Mastodon(Internals): raise MastodonIllegalArgumentError('Cannot specify exclude_types/types when mentions_only is present') del mentions_only - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - if account_id is not None: account_id = self.__unpack_id(account_id) if id is None: - params = self.__generate_params(locals(), ['id']) + params = self.__generate_params(locals(), ['id'], dateconv=True) return self.__api_request('GET', '/api/v1/notifications', params) else: id = self.__unpack_id(id) diff --git a/mastodon/relationships.py b/mastodon/relationships.py index ea76971..e3b399c 100644 --- a/mastodon/relationships.py +++ b/mastodon/relationships.py @@ -17,15 +17,6 @@ class Mastodon(Internals): """ Fetch a list of users muted by the logged-in user. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/mutes', params) @@ -35,15 +26,6 @@ class Mastodon(Internals): """ Fetch a list of users blocked by the logged-in user. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/blocks', params) @@ -56,15 +38,6 @@ class Mastodon(Internals): """ Fetch the logged-in user's incoming follow requests. """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/follow_requests', params) @@ -79,15 +52,6 @@ class Mastodon(Internals): Returns a list of blocked domain URLs (as strings, without protocol specifier). """ - if max_id is not None: - max_id = self.__unpack_id(max_id) - - if min_id is not None: - min_id = self.__unpack_id(min_id) - - if since_id is not None: - since_id = self.__unpack_id(since_id) - params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/domain_blocks', params) diff --git a/mastodon/search.py b/mastodon/search.py index 3d3240b..74e29ac 100644 --- a/mastodon/search.py +++ b/mastodon/search.py @@ -82,7 +82,7 @@ class Mastodon(Internals): Returns a :ref:`search result dict `. """ self.__ensure_search_params_acceptable(account_id, offset, min_id, max_id) - params = self.__generate_params(locals()) + params = self.__generate_params(locals(), dateconv=True) if not resolve: del params["resolve"] diff --git a/mastodon/statuses.py b/mastodon/statuses.py index eb4a702..06eab45 100644 --- a/mastodon/statuses.py +++ b/mastodon/statuses.py @@ -100,10 +100,8 @@ class Mastodon(Internals): """ Fetch a list of scheduled statuses """ - max_id = self.__unpack_id(max_id) - min_id = self.__unpack_id(min_id) - since_id = self.__unpack_id(since_id) - return self.__api_request('GET', '/api/v1/scheduled_statuses') + params = self.__generate_params(locals()) + return self.__api_request('GET', '/api/v1/scheduled_statuses', params) @api_version("2.7.0", "2.7.0", _DICT_VERSION_SCHEDULED_STATUS) def scheduled_status(self, id: Union[ScheduledStatus, IdType]) -> ScheduledStatus: diff --git a/mastodon/timeline.py b/mastodon/timeline.py index 88a6668..58a19e7 100644 --- a/mastodon/timeline.py +++ b/mastodon/timeline.py @@ -28,15 +28,6 @@ class Mastodon(Internals): May or may not require authentication depending on server settings and what is specifically requested. """ - if max_id is not None: - max_id = self.__unpack_id(max_id, dateconv=True) - - if min_id is not None: - min_id = self.__unpack_id(min_id, dateconv=True) - - if since_id is not None: - since_id = self.__unpack_id(since_id, dateconv=True) - params_initial = locals() if not local: @@ -52,7 +43,7 @@ class Mastodon(Internals): timeline = "public" params_initial['local'] = True - params = self.__generate_params(params_initial, ['timeline']) + params = self.__generate_params(params_initial, ['timeline'], dateconv=True) return self.__api_request('GET', f'/api/v1/timelines/{timeline}', params) @api_version("1.0.0", "3.1.4", _DICT_VERSION_STATUS) diff --git a/mastodon/types_base.py b/mastodon/types_base.py index dd42795..666b017 100644 --- a/mastodon/types_base.py +++ b/mastodon/types_base.py @@ -464,10 +464,11 @@ class PaginationInfo(OrderedDict): """ pass -IdType = Union[PrimitiveIdType, MaybeSnowflakeIdType] +IdType = Union[PrimitiveIdType, MaybeSnowflakeIdType, datetime] """ IDs returned from Mastodon.py ar either primitive (int or str) or snowflake -(still int or str, but potentially convertible to datetime). +(still int or str, but potentially convertible to datetime), but also +a datetime (which will get converted to a snowflake id). """ T = TypeVar('T')