From 1af3e8d34d0b3400f9b7adaad59105050b242971 Mon Sep 17 00:00:00 2001 From: Lorenz Diener Date: Fri, 15 Aug 2025 13:02:50 +0300 Subject: [PATCH] Add API version, warn if not present despite version >= 4.3.0 --- CHANGELOG.rst | 13 ++++++++----- mastodon/authentication.py | 33 ++++++++++++++++++++++++++------- mastodon/utility.py | 21 +++++++++++++++++---- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6308bfe..36bdc74 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,9 @@ v2.1.0 (IN PROGRESS) * Fixed to_json breaking on python 3.14 (Thanks @limburgher for the report) * Replaced pytest-vcr (deprecated) with pytest-recording (Thanks @CyberTailor) * Improved timeline documentation (Thanks @adamse) +* Improved docs for stream_healthy (thanks @codl) +* Add offset parameter to trending_tags and trending_links (Thanks @ghost) +* Added support for retrieving API version and a warning for if it is not present despite the mastodon version suggesting it should be. v2.0.1 ------ @@ -313,7 +316,7 @@ of things changed, since this release covers two Mastodon versions and then some !!!!! * Several small bug fixes (Thanks goldensuneur, bowlercaptain, joyeusenoelle) -* Improved stream error handling (Thanks codl) +* Improved stream error handling (thanks @codl) * Improvements to streaming: * Added on_abort() handler to streams * Added automatic reconnecting @@ -337,7 +340,7 @@ then some !!!!! v1.2.2 ------ -* Several small bugfixes (thanks codl) +* Several small bugfixes (thanks @codl) * Mastodon v2.1.2 compatibility * Added instance_activity() * Added instance_peers() @@ -371,17 +374,17 @@ v1.2.0 v1.1.2 ------ -* 2.0 id compatibility (thanks codl) +* 2.0 id compatibility (thanks @codl) * Added emoji support * Media alt-text support (thanks foozmeat) * Python2 fixes (thanks ragingscholar) -* General code cleanup and small fixes (thanks codl) +* General code cleanup and small fixes (thanks @codl) * Beginnings of better error handling (thanks Elizafox) * Various documentation updates v1.1.1 ------ -* Emergency fix to allow logging in to work (thanks codl) +* Emergency fix to allow logging in to work (thanks @codl) v1.1.0 ------ diff --git a/mastodon/authentication.py b/mastodon/authentication.py index cdba617..db0381b 100644 --- a/mastodon/authentication.py +++ b/mastodon/authentication.py @@ -237,10 +237,20 @@ class Mastodon(Internals): self.mastodon_major = 1 self.mastodon_minor = 0 self.mastodon_patch = 0 - self.version_check_worked = None - self.version_check_tried = False + + # new addition from 4.3.0 on: API versioning. + # For now, we retrieve and cache this along with the other version information, + # though do not use it to do version checks (yet). TBD on whether to go through + # the trouble of doing this for all new endpoints, we'll have to see if other + # API implementations start using this (fingers crossed). + # We also emit a warning if the version is >= 4.3.0 but no API version is found. + self.mastodon_api_version = 0 + + self.__version_check_worked = None + self.__version_check_tried = False + if not mastodon_version is None: - self.version_check_tried = True + self.__version_check_tried = True # Cached version check self.__streaming_base = None @@ -264,9 +274,10 @@ class Mastodon(Internals): * Mastodon version * Streaming base URL """ - self.version_check_worked = None - self.version_check_tried = False + self.__version_check_worked = None + self.__version_check_tried = False self.__streaming_base = None + self.__oauth_grant_info = None def auth_request_url(self, client_id: Optional[Union[str, PurePath]] = None, redirect_uris: str = "urn:ietf:wg:oauth:2.0:oob", scopes: List[str] =_DEFAULT_SCOPES, force_login: bool = False, state: Optional[str] = None, @@ -336,11 +347,18 @@ class Mastodon(Internals): Returns the access token as a string. """ + + # Is the version > 4.4.0? Throw on trying to log in with password with a more informative message than the API error + # This is left in here even though we check for available grant types above because that way + # we can give a more informative error message to the user ("not supported after version 4.4.0") instead of the + # generic one. if self.mastodon_major >= 4 and self.mastodon_minor >= 4 or self.mastodon_major > 4: if password is not None: raise MastodonIllegalArgumentError('Password flow is no longer supported in Mastodon 4.4.0 and later.') + # + if username is not None and password is not None: params = self.__generate_params(locals(), ['scopes', 'to_file', 'code', 'refresh_token']) params['grant_type'] = 'password' @@ -386,8 +404,9 @@ class Mastodon(Internals): token_file.write(self.persistable_login_credentials()) self.__logged_in_id = None - # Retry version check if needed (might be required in limited federation mode) - if not self.version_check_worked: + # Retry version check if needed (might be required in limited federation mode since + # if the API is locked down, we need to auth before we can get the version) + if not self.__version_check_worked: self.retrieve_mastodon_version() return response['access_token'] diff --git a/mastodon/utility.py b/mastodon/utility.py index 594545b..6903d58 100644 --- a/mastodon/utility.py +++ b/mastodon/utility.py @@ -4,6 +4,7 @@ import re import dateutil import datetime import copy +import warnings from mastodon.errors import MastodonAPIError, MastodonIllegalArgumentError from mastodon.compat import IMPL_HAS_BLURHASH, blurhash @@ -32,13 +33,25 @@ class Mastodon(Internals): """ try: version_str = self.__normalize_version_string(self.__instance()["version"]) - self.version_check_worked = True + self.__version_check_worked = True except Exception as e: # instance() was added in 1.1.0, so our best guess is 1.0.0. version_str = "1.0.0" - self.version_check_worked = False + self.__version_check_worked = False self.mastodon_major, self.mastodon_minor, self.mastodon_patch = parse_version_string(version_str) - self.version_check_tried = True + + # If the instance has an API version, we store that as well. + # If we have a version >= 4.3.0 but no API version, we throw a warning that this is a Weird Implementation, + # which might help with adoption of the API versioning or at least give us a better picture of how it is going. + found_api_version = False + if "api_versions" in self.__instance(): + if "mastodon" in self.__instance()["api_versions"]: + self.mastodon_api_version = int(self.__instance()["api_versions"]["mastodon"]) + found_api_version = True + if not found_api_version and self.mastodon_major >= 4 and self.mastodon_minor >= 3: + warnings.warn("Mastodon version is detected as >= 4.3.0, but no API version found. Please report this.") + + self.__version_check_tried = True return version_str def verify_minimum_version(self, version_str, cached=False): @@ -49,7 +62,7 @@ class Mastodon(Internals): Returns True if version requirement is satisfied, False if not. """ - if not cached or not self.version_check_tried: + if not cached or not self.__version_check_tried: self.retrieve_mastodon_version() major, minor, patch = parse_version_string(version_str) if major > self.mastodon_major: