From e9d7a3e24a0564bee307f1fdfd00f1dcafbe080c Mon Sep 17 00:00:00 2001 From: Lorenz Diener Date: Thu, 14 Dec 2017 00:27:34 +0100 Subject: Add last-changed versioning --- docs/index.rst | 19 +++--- mastodon/Mastodon.py | 169 ++++++++++++++++++++++++++++----------------------- 2 files changed, 105 insertions(+), 83 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 4dd6403..3e6682e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -56,7 +56,7 @@ Mastodon.py has three modes for dealing with rate limiting that you can pass to the constructor, "throw", "wait" and "pace", "wait" being the default. In "throw" mode, Mastodon.py makes no attempt to stick to rate limits. When -a request hits the rate limit, it simply throws a MastodonRateLimitError. This is +a request hits the rate limit, it simply throws a `MastodonRateLimitError`. This is for applications that need to handle all rate limiting themselves (i.e. interactive apps), or applications wanting to use Mastodon.py in a multi-threaded context ("wait" and "pace" modes are not thread safe). @@ -148,6 +148,8 @@ does not exist). `MastodonRatelimitError` is raised when you hit an API rate limit. You should try again after a while (see the rate limiting section above). +`MastodonVersionError` is raised when a version check for an API call fails. + Return values ------------- Unless otherwise specified, all data is returned as python dictionaries, matching @@ -451,13 +453,14 @@ Versioning ---------- Mastodon.py will check if a certain endpoint is available before doing API calls. By default, it checks against the version of Mastodon retrieved on -init(), or the version you specified. With these functions, you can make -Mastodon.py re-check the server version or explicitly determine if a -specific minimum Version is available. - -Note that the automatic version checks check for the version in which the -endpoint was first added, not the version in which it was last changed. The -latter check may be added to Mastodon.py at a later date. +init(), or the version you specified. Mastodon.py can be set (in the +constructor) to either check if an endpoint is available at all or to check +if the endpoint is available and behaves as in the newest Mastodon version +(this is the default). Version checking can also be disabled altogether. +If a version check fails, Mastodon.py throws a `MastodonVersionError`. + +With the following functions, you can make Mastodon.py re-check the server +version or explicitly determine if a specific minimum Version is available. .. automethod:: Mastodon.retrieve_mastodon_version .. automethod:: Mastodon.verify_minimum_version diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index f15ee23..f6551f0 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -38,19 +38,24 @@ def parse_version_string(version_string): ] return version_parts -def api_version(version): +def api_version(created_ver, last_changed_ver): """Version check decorator. Currently only checks Bigger Than.""" def api_min_version_decorator(function): def wrapper(function, self, *args, **kwargs): + if not self.version_check_mode == "none": + if self.version_check_mode == "created": + version = created_version + else: + version = last_changed_ver major, minor, patch = parse_version_string(version) if major > self.mastodon_major: - raise MastodonVersionError("Specified version does not support this API endpoint (Available from " + version + ")") + raise MastodonVersionError("Version check failed (Need version " + version + ")") elif major == self.mastodon_major and minor > self.mastodon_minor: - raise MastodonVersionError("Specified version does not support this API endpoint (Available from " + version + ")") + raise MastodonVersionError("Version check failed (Need version " + version + ")") elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch: - raise MastodonVersionError("Specified version does not support this API endpoint (Available from " + version + ")") + raise MastodonVersionError("Version check failed (Need version " + version + ")") return function(self, *args, **kwargs) - function.__doc__ = function.__doc__ + "\n\n *Minumum Mastodon version: " + version + "*" + function.__doc__ = function.__doc__ + "\n\n *Added: Mastodon v" + created_ver + ", last changed: Mastodon v" + last_changed_ver + "*" return decorate(function, wrapper) return api_min_version_decorator @@ -116,7 +121,8 @@ class Mastodon: def __init__(self, client_id, client_secret=None, access_token=None, api_base_url=__DEFAULT_BASE_URL, debug_requests=False, ratelimit_method="wait", ratelimit_pacefactor=1.1, - request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None): + request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None, + version_check_mode = "changed"): """ Create a new API wrapper instance based on the given `client_secret` and `client_id`. If you give a `client_id` and it is not a file, you must also give a secret. @@ -142,6 +148,12 @@ class Mastodon: expect to be installed on the server. The function will throw an error if an unparseable Version is specified. If no version is specified, Mastodon.py will set `mastodon_version` to the detected version. + + The version check mode can be set to "created", "changed" (the default behaviour) or "none". If set to + "created", Mastodon.py will throw an error if the version of Mastodon it is connected to is too old + to have an endpoint. If it is set to "changed", it will throw an error if the endpoints behaviour has + changed after the version of Mastodon that is connected has been released. If it is set to "none", + version checking is disabled. """ self.api_base_url = Mastodon.__protocolize(api_base_url) self.client_id = client_id @@ -169,6 +181,10 @@ class Mastodon: except: raise MastodonVersionError("Bad version specified") + if not version_check_mode in ["created", "changed", "none"]: + raise MastodonIllegalArgumentError("Invalid version check method.") + self.version_check_mode = version_check_mode + # Ratelimiting parameter check if ratelimit_method not in ["throw", "wait", "pace"]: raise MastodonIllegalArgumentError("Invalid ratelimit method.") @@ -301,7 +317,7 @@ class Mastodon: ### # Reading data: Instances ### - @api_version("1.1.0") + @api_version("1.1.0", "1.4.2") def instance(self): """ Retrieve basic information about the instance, including the URI and administrative contact email. @@ -321,7 +337,7 @@ class Mastodon: ### # Reading data: Timelines ## - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def timeline(self, timeline="home", max_id=None, since_id=None, limit=None): """ Fetch statuses, most recent ones first. `timeline` can be 'home', 'local', 'public', @@ -348,7 +364,7 @@ class Mastodon: url = '/api/v1/timelines/{0}'.format(timeline) return self.__api_request('GET', url, params) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def timeline_home(self, max_id=None, since_id=None, limit=None): """ Fetch the logged-in users home timeline (i.e. followed users and self). @@ -358,7 +374,7 @@ class Mastodon: return self.timeline('home', max_id=max_id, since_id=since_id, limit=limit) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def timeline_local(self, max_id=None, since_id=None, limit=None): """ Fetches the local / instance-wide timeline, not including replies. @@ -368,7 +384,7 @@ class Mastodon: return self.timeline('local', max_id=max_id, since_id=since_id, limit=limit) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def timeline_public(self, max_id=None, since_id=None, limit=None): """ Fetches the public / visible-network timeline, not including replies. @@ -378,7 +394,7 @@ class Mastodon: return self.timeline('public', max_id=max_id, since_id=since_id, limit=limit) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def timeline_hashtag(self, hashtag, local=False, max_id=None, since_id=None, limit=None): """ Fetch a timeline of toots with a given hashtag. The hashtag parameter @@ -407,7 +423,7 @@ class Mastodon: return self.__api_request('GET', url, params) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def timeline_list(self, id, max_id=None, since_id=None, limit=None): """ Fetches a timeline containing all the toots by users in a given list. @@ -421,7 +437,7 @@ class Mastodon: ### # Reading data: Statuses ### - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def status(self, id): """ Fetch information about a single toot. @@ -434,7 +450,7 @@ class Mastodon: url = '/api/v1/statuses/{0}'.format(str(id)) return self.__api_request('GET', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def status_card(self, id): """ Fetch a card associated with a status. A card describes an object (such as an @@ -448,7 +464,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/card'.format(str(id)) return self.__api_request('GET', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def status_context(self, id): """ Fetch information about ancestors and descendants of a toot. @@ -461,7 +477,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/context'.format(str(id)) return self.__api_request('GET', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def status_reblogged_by(self, id): """ Fetch a list of users that have reblogged a status. @@ -474,7 +490,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/reblogged_by'.format(str(id)) return self.__api_request('GET', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def status_favourited_by(self, id): """ Fetch a list of users that have favourited a status. @@ -490,7 +506,7 @@ class Mastodon: ### # Reading data: Notifications ### - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def notifications(self, id=None, max_id=None, since_id=None, limit=None): """ Fetch notifications (mentions, favourites, reblogs, follows) for the logged-in @@ -517,7 +533,7 @@ class Mastodon: ### # Reading data: Accounts ### - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def account(self, id): """ Fetch account information by user `id`. @@ -528,7 +544,7 @@ class Mastodon: url = '/api/v1/accounts/{0}'.format(str(id)) return self.__api_request('GET', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.5.0") def account_verify_credentials(self): """ Fetch logged-in user's account information. @@ -537,14 +553,18 @@ class Mastodon: """ return self.__api_request('GET', '/api/v1/accounts/verify_credentials') - @api_version("1.0.0") - def account_statuses(self, id, max_id=None, since_id=None, limit=None): + @api_version("1.0.0", "2.0.0") + def account_statuses(self, id, only_media=False, pinned=False, exclude_replies=False, max_id=None, since_id=None, limit=None): """ Fetch statuses by user `id`. Same options as `timeline()`_ are permitted. Returned toots are from the perspective of the logged-in user, i.e. all statuses visible to the logged-in user (including DMs) are included. + If `only_media` is set, return only statuses with media attachments. + If `pinned` is set, return only statuses that have been pinned. + If `exclude_replies` is set, filter out all statuses that are replies. + Returns a list of `toot dicts`_. """ id = self.__unpack_id(id) @@ -558,7 +578,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/statuses'.format(str(id)) return self.__api_request('GET', url, params) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def account_following(self, id, max_id=None, since_id=None, limit=None): """ Fetch users the given user is following. @@ -576,7 +596,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/following'.format(str(id)) return self.__api_request('GET', url, params) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def account_followers(self, id, max_id=None, since_id=None, limit=None): """ Fetch users the given user is followed by. @@ -594,7 +614,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/followers'.format(str(id)) return self.__api_request('GET', url, params) - @api_version("1.0.0") + @api_version("1.0.0", "1.4.0") def account_relationships(self, id): """ Fetch relationship (following, followed_by, blocking, follow requested) of @@ -607,7 +627,7 @@ class Mastodon: return self.__api_request('GET', '/api/v1/accounts/relationships', params) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def account_search(self, q, limit=None): """ Fetch matching accounts. Will lookup an account remotely if the search term is @@ -618,7 +638,7 @@ class Mastodon: params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/accounts/search', params) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def account_lists(self, id): """ Get all of the logged in users lists which the specified user is @@ -633,7 +653,7 @@ class Mastodon: ### # Reading data: Searching ### - @api_version("1.1.0") + @api_version("1.1.0", "2.1.0") def search(self, q, resolve=False): """ Fetch matching hashtags, accounts and statuses. Will search federated @@ -647,7 +667,7 @@ class Mastodon: ### # Reading data: Lists ### - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def lists(self): """ Fetch a list of all the Lists by the logged-in user. @@ -656,7 +676,7 @@ class Mastodon: """ return self.__api_request('GET', '/api/v1/lists') - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list(self, id): """ Fetch info about a specific list. @@ -666,7 +686,7 @@ class Mastodon: id = self.__unpack_id(id) return self.__api_request('GET', '/api/v1/lists/{0}'.format(id)) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list_accounts(self, id, max_id=None, since_id=None, limit=None): """ Get the accounts that are on the given list. A `limit` of 0 can @@ -688,7 +708,7 @@ class Mastodon: ### # Reading data: Mutes and Blocks ### - @api_version("1.1.0") + @api_version("1.1.0", "1.1.0") def mutes(self, max_id=None, since_id=None, limit=None): """ Fetch a list of users muted by the logged-in user. @@ -704,7 +724,7 @@ class Mastodon: params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/mutes', params) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def blocks(self, max_id=None, since_id=None, limit=None): """ Fetch a list of users blocked by the logged-in user. @@ -723,7 +743,7 @@ class Mastodon: ### # Reading data: Reports ### - @api_version("1.1.0") + @api_version("1.1.0", "1.1.0") def reports(self): """ Fetch a list of reports made by the logged-in user. @@ -738,7 +758,7 @@ class Mastodon: ### # Reading data: Favourites ### - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def favourites(self, max_id=None, since_id=None, limit=None): """ Fetch the logged-in user's favourited statuses. @@ -757,7 +777,7 @@ class Mastodon: ### # Reading data: Follow requests ### - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def follow_requests(self, max_id=None, since_id=None, limit=None): """ Fetch the logged-in user's incoming follow requests. @@ -776,7 +796,7 @@ class Mastodon: ### # Reading data: Domain blocks ### - @api_version("1.4.0") + @api_version("1.4.0", "1.4.0") def domain_blocks(self, max_id=None, since_id=None, limit=None): """ Fetch the logged-in user's blocked domains. @@ -795,7 +815,7 @@ class Mastodon: ### # Reading data: Emoji ### - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def custom_emojis(self): """ Fetch the list of custom emoji the instance has installed. @@ -810,7 +830,7 @@ class Mastodon: ### # Writing data: Statuses ### - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def status_post(self, status, in_reply_to_id=None, media_ids=None, sensitive=False, visibility='', spoiler_text=None): """ @@ -872,7 +892,7 @@ class Mastodon: params = self.__generate_params(params_initial) return self.__api_request('POST', '/api/v1/statuses', params) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def toot(self, status): """ Synonym for `status_post()`_ that only takes the status text as input. @@ -883,7 +903,7 @@ class Mastodon: """ return self.status_post(status) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def status_delete(self, id): """ Delete a status @@ -892,7 +912,7 @@ class Mastodon: url = '/api/v1/statuses/{0}'.format(str(id)) self.__api_request('DELETE', url) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def status_reblog(self, id): """ Reblog a status. @@ -903,7 +923,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/reblog'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def status_unreblog(self, id): """ Un-reblog a status. @@ -914,7 +934,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/unreblog'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def status_favourite(self, id): """ Favourite a status. @@ -925,7 +945,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/favourite'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def status_unfavourite(self, id): """ Un-favourite a status. @@ -936,7 +956,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/unfavourite'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.4.0") + @api_version("1.4.0", "2.0.0") def status_mute(self, id): """ Mute notifications for a status. @@ -947,7 +967,7 @@ class Mastodon: url = '/api/v1/statuses/{0}/mute'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.4.0") + @api_version("1.4.0", "2.0.0") def status_unmute(self, id): """ Unmute notifications for a status. @@ -961,7 +981,7 @@ class Mastodon: ### # Writing data: Notifications ### - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def notifications_clear(self): """ Clear out a users notifications @@ -969,7 +989,7 @@ class Mastodon: self.__api_request('POST', '/api/v1/notifications/clear') - @api_version("1.3.0") + @api_version("1.3.0", "1.3.0") def notifications_dismiss(self, id): """ Deletes a single notification @@ -981,7 +1001,7 @@ class Mastodon: ### # Writing data: Accounts ### - @api_version("1.0.0") + @api_version("1.0.0", "1.4.0") def account_follow(self, id): """ Follow a user. @@ -992,7 +1012,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/follow'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def follows(self, uri): """ Follow a remote user by uri (username@domain). @@ -1002,7 +1022,7 @@ class Mastodon: params = self.__generate_params(locals()) return self.__api_request('POST', '/api/v1/follows', params) - @api_version("1.0.0") + @api_version("1.0.0", "1.4.0") def account_unfollow(self, id): """ Unfollow a user. @@ -1013,7 +1033,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/unfollow'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.4.0") def account_block(self, id): """ Block a user. @@ -1024,7 +1044,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/block'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.4.0") def account_unblock(self, id): """ Unblock a user. @@ -1035,7 +1055,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/unblock'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.1.0") + @api_version("1.1.0", "1.4.0") def account_mute(self, id): """ Mute a user. @@ -1046,7 +1066,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/mute'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.1.0") + @api_version("1.1.0", "1.4.0") def account_unmute(self, id): """ Unmute a user. @@ -1057,7 +1077,7 @@ class Mastodon: url = '/api/v1/accounts/{0}/unmute'.format(str(id)) return self.__api_request('POST', url) - @api_version("1.1.1") + @api_version("1.1.1", "1.6.0") def account_update_credentials(self, display_name=None, note=None, avatar=None, header=None): """ @@ -1076,7 +1096,7 @@ class Mastodon: ### # Writing data: Lists ### - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list_create(self, title): """ Create a new list with the given `title`. @@ -1086,7 +1106,7 @@ class Mastodon: params = self.__generate_params(locals()) return self.__api_request('POST', '/api/v1/lists', params) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list_update(self, id, title): """ Update info about a list, where "info" is really the lists `title`. @@ -1097,7 +1117,7 @@ class Mastodon: params = self.__generate_params(locals(), ['id']) return self.__api_request('PUT', '/api/v1/lists/{0}'.format(id), params) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list_delete(self, id): """ Delete a list. @@ -1105,7 +1125,7 @@ class Mastodon: id = self.__unpack_id(id) self.__api_request('DELETE', '/api/v1/lists/{0}'.format(id)) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list_accounts_add(self, id, account_ids): """ Add the account(s) given in `account_ids` to the list. @@ -1119,7 +1139,7 @@ class Mastodon: params = self.__generate_params(locals(), ['id']) self.__api_request('POST', '/api/v1/lists/{0}/accounts'.format(id), params) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def list_accounts_delete(self, id, account_ids): """ Remove the account(s) given in `account_ids` from the list. @@ -1136,7 +1156,7 @@ class Mastodon: ### # Writing data: Reports ### - @api_version("1.1.0") + @api_version("1.1.0", "1.1.0") def report(self, account_id, status_ids, comment): """ Report statuses to the instances administrators. @@ -1157,7 +1177,7 @@ class Mastodon: ### # Writing data: Follow requests ### - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def follow_request_authorize(self, id): """ Accept an incoming follow request. @@ -1166,7 +1186,7 @@ class Mastodon: url = '/api/v1/follow_requests/{0}/authorize'.format(str(id)) self.__api_request('POST', url) - @api_version("1.0.0") + @api_version("1.0.0", "1.0.0") def follow_request_reject(self, id): """ Reject an incoming follow request. @@ -1178,7 +1198,7 @@ class Mastodon: ### # Writing data: Media ### - @api_version("1.0.0") + @api_version("1.0.0", "2.0.0") def media_post(self, media_file, mime_type=None, description=None): """ Post an image. `media_file` can either be image data or @@ -1213,7 +1233,7 @@ class Mastodon: ### # Writing data: Domain blocks ### - @api_version("1.4.0") + @api_version("1.4.0", "1.4.0") def domain_block(self, domain=None): """ Add a block for all statuses originating from the specified domain for the logged-in user. @@ -1221,7 +1241,7 @@ class Mastodon: params = self.__generate_params(locals()) self.__api_request('POST', '/api/v1/domain_blocks', params) - @api_version("1.4.0") + @api_version("1.4.0", "1.4.0") def domain_unblock(self, domain=None): """ Remove a domain block for the logged-in user. @@ -1302,7 +1322,7 @@ class Mastodon: ### # Streaming ### - @api_version("1.1.0") + @api_version("1.1.0", "1.4.2") def stream_user(self, listener, async=False): """ Streams events that are relevant to the authorized user, i.e. home @@ -1310,21 +1330,21 @@ class Mastodon: """ return self.__stream('/api/v1/streaming/user', listener, async=async) - @api_version("1.1.0") + @api_version("1.1.0", "1.4.2") def stream_public(self, listener, async=False): """ Streams public events. """ return self.__stream('/api/v1/streaming/public', listener, async=async) - @api_version("1.1.0") + @api_version("1.1.0", "1.4.2") def stream_local(self, listener, async=False): """ Streams local public events. """ return self.__stream('/api/v1/streaming/public/local', listener, async=async) - @api_version("1.1.0") + @api_version("1.1.0", "1.4.2") def stream_hashtag(self, tag, listener, async=False): """ Stream for all public statuses for the hashtag 'tag' seen by the connected @@ -1334,7 +1354,7 @@ class Mastodon: raise MastodonIllegalArgumentError("Tag parameter should omit leading #") return self.__stream("/api/v1/streaming/hashtag?tag={}".format(tag), listener) - @api_version("2.1.0") + @api_version("2.1.0", "2.1.0") def stream_list(self, id, listener, async=False): """ Stream events for the current user, restricted to accounts on the given @@ -1706,7 +1726,6 @@ class Mastodon: class MastodonError(Exception): """Base class for Mastodon.py exceptions""" - class MastodonVersionError(MastodonError): """Raised when a function is called that the version of Mastodon for which Mastodon.py was instantiated does not support""" -- cgit v1.2.3