{"id":9098,"library":"mastodon-py","title":"Python wrapper for the Mastodon API","description":"Mastodon.py is an actively maintained Python wrapper for the Mastodon API, providing a feature-complete client for interacting with Mastodon instances. It is currently at version 2.2.1 and receives regular updates to support new Mastodon API features and fix bugs.","status":"active","version":"2.2.1","language":"en","source_language":"en","source_url":"https://github.com/halcy/Mastodon.py","tags":["mastodon","social media","api client","fediverse"],"install":[{"cmd":"pip install Mastodon.py","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Switched from 'grapheme' in v2.2.0 for better maintenance in grapheme cluster handling.","package":"graphemeu","optional":false}],"imports":[{"symbol":"Mastodon","correct":"from mastodon import Mastodon"}],"quickstart":{"code":"import os\nfrom mastodon import Mastodon\n\n# --- App Registration (Run once per server/app) ---\n# client_id, client_secret = Mastodon.create_app(\n#     'MyPythonApp',\n#     api_base_url = 'https://mastodon.social',\n#     to_file = 'pytooter_clientcred.secret'\n# )\n\n# --- User Login (Run once per user/app) ---\n# mastodon = Mastodon(client_id = 'pytooter_clientcred.secret')\n# # print(mastodon.auth_request_url())\n# # code = input(\"Enter the OAuth authorization code: \")\n# # mastodon.log_in(code=code, to_file=\"pytooter_usercred.secret\")\n\n# --- Usage with existing credentials ---\n# It's recommended to store sensitive tokens securely (e.g., environment variables).\n# For quick testing, you can load from file if previously saved.\n# ACCESS_TOKEN_FILE = 'pytooter_usercred.secret'\n# if os.path.exists(ACCESS_TOKEN_FILE):\n#     api_base_url = None # Will be loaded from file if present\n#     with open(ACCESS_TOKEN_FILE, 'r') as f:\n#         # Simple parsing for demo, real-world might use better config handling\n#         lines = f.readlines()\n#         for line in lines:\n#             if 'api_base_url' in line:\n#                 api_base_url = line.split('=')[1].strip()\n#                 break\n#     mastodon = Mastodon(access_token=ACCESS_TOKEN_FILE, api_base_url=api_base_url)\n# else:\nMASTODON_ACCESS_TOKEN = os.environ.get('MASTODON_ACCESS_TOKEN', '')\nMASTODON_API_BASE_URL = os.environ.get('MASTODON_API_BASE_URL', 'https://mastodon.social')\n\nif not MASTODON_ACCESS_TOKEN:\n    print(\"Error: MASTODON_ACCESS_TOKEN environment variable not set. Please set it or uncomment app registration/login code.\")\n    exit(1)\n\nprint(f\"Connecting to Mastodon instance: {MASTODON_API_BASE_URL}\")\nmastodon = Mastodon(\n    access_token=MASTODON_ACCESS_TOKEN,\n    api_base_url=MASTODON_API_BASE_URL\n)\n\ntry:\n    # Get current authenticated user's account details\n    me = mastodon.account_verify_credentials()\n    print(f\"Successfully authenticated as @{me.acct}\")\n\n    # Post a status (toot)\n    status = mastodon.status_post('Hello from mastodon-py! #python #mastodonpy')\n    print(f\"Tooted: {status.url}\")\n\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")","lang":"python","description":"This quickstart demonstrates how to authenticate with a Mastodon instance using an access token and post a status (toot). It assumes you have already registered an application and obtained a user access token. For production, store your `MASTODON_ACCESS_TOKEN` and `MASTODON_API_BASE_URL` as environment variables. The commented-out sections show the `create_app` and `log_in` steps for initial setup."},"warnings":[{"fix":"Thoroughly test your application after upgrading to v2.0.0 or later, especially if you rely on specific dict-like access patterns or type checks. Review the new entity classes and type hints in the documentation.","message":"Version 2.0.0 introduced a 'massive rework of entities and typing', converting return values to proper classes instead of just AttribAccessDict. While backward compatibility was attempted, it's advised to 'be extra careful about upgrading'.","severity":"breaking","affected_versions":"2.0.0 and above"},{"fix":"Always explicitly provide the `api_base_url` when calling `Mastodon.create_app()` and when initializing the `Mastodon` client instance, e.g., `api_base_url='https://example.social'`.","message":"In versions prior to 1.7.0, `api_base_url` had a default value (`mastodon.social`), but this was removed. Failing to explicitly pass `api_base_url` to `Mastodon.create_app()` or `Mastodon()` constructor will now raise an error.","severity":"breaking","affected_versions":"1.7.0 and above"},{"fix":"Ensure you are using `mastodon-py` version 2.1.3 or newer to benefit from internal handling of these deprecation warnings. Keep your `mastodon-py` library updated.","message":"The library might internally encounter deprecation warnings from the Mastodon API itself due to the older v1 instance API being deprecated. Version 2.1.3 included a fix to handle these warnings, adding a fallback.","severity":"deprecated","affected_versions":"Prior to 2.1.3 (warnings from Mastodon API itself)"},{"fix":"If encountering `invalid_grant` errors during login, temporarily disable 2FA or use an application-specific password if available (check your instance's settings). Ensure the email address used for login is in all lowercase.","message":"Two-factor authentication (2FA) on your Mastodon account can prevent `mastodon-py` from logging in successfully via password flow, resulting in an `invalid_grant` error. Additionally, case sensitivity in the login email address can cause the same error.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Configure `ratelimit_method` when initializing `Mastodon`. The default is 'wait', which will pause. For immediate errors, set `ratelimit_method='throw'` and implement custom retry logic with exponential backoff. Monitor `ratelimit_remaining` and `ratelimit_reset` attributes.","message":"API rate limits can be hit, especially with frequent requests, leading to `MastodonRatelimitError`. While `mastodon-py` provides mechanisms to handle this, improper configuration can still lead to errors.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Verify the `access_token` is correct and hasn't expired. If using OAuth, ensure the `redirect_uri` and `scopes` passed to `log_in()` match those used in `create_app()` and the authorization URL. If 2FA is enabled on your Mastodon account, consider generating an application-specific password or temporarily disabling 2FA for bot accounts if appropriate, or ensure your OAuth flow is correctly handling the authorization code.","cause":"This error often indicates issues with user authentication, such as an incorrect access token, mismatched OAuth parameters (scopes, redirect URI), or two-factor authentication being enabled on the user's account.","error":"MastodonAPIError: (400, 'Bad Request', 'invalid_grant')"},{"fix":"Double-check the ID or URL of the resource you are trying to access. Ensure the `api_base_url` is correct for the instance. Verify that the authenticated user's scope and permissions allow access to the specific API endpoint and resource.","cause":"The requested resource (e.g., account, status, media) does not exist on the Mastodon instance or the authenticated user does not have permission to access it.","error":"MastodonAPIError: (404, 'Not Found', 'Record not found')"},{"fix":"Always explicitly pass the `api_base_url` parameter when initializing `Mastodon` or calling `Mastodon.create_app()`. Example: `mastodon = Mastodon(api_base_url='https://example.social', ...)`.","cause":"This typically happens when a required argument like `api_base_url` is `None` when a method expects a string, often because `api_base_url` was omitted when creating the `Mastodon` client or `create_app()`.","error":"TypeError: 'NoneType' object is not callable"},{"fix":"By default, `mastodon-py` will wait. If you configured `ratelimit_method='throw'`, you need to implement your own retry logic with a delay. Check the `ratelimit_reset` attribute on the `Mastodon` object to know when to retry, or use `time.sleep()` for the duration indicated in the error message.","cause":"Your application has exceeded the number of API requests allowed by the Mastodon instance within a given timeframe.","error":"MastodonRatelimitError: Rate limit hit, try again in X seconds"}]}