Merge remote-tracking branch 'refs/remotes/origin/master' into ratelimits
# Conflicts: # mastodon/Mastodon.py
This commit is contained in:
commit
ab58894041
S'han modificat 2 arxius amb 213 adicions i 80 eliminacions
117
docs/index.rst
117
docs/index.rst
|
@ -1,5 +1,7 @@
|
|||
Mastodon.py
|
||||
===========
|
||||
.. py:module:: mastodon
|
||||
.. py:class: Mastodon
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -37,14 +39,114 @@ as a single python module. By default, it talks to the
|
|||
`Mastodon flagship instance`_, but it can be set to talk to any
|
||||
node running Mastodon.
|
||||
|
||||
A note about IDs
|
||||
----------------
|
||||
Mastodons API uses IDs in several places: User IDs, Toot IDs, ...
|
||||
|
||||
While debugging, it might be tempting to copy-paste in IDs from the
|
||||
web interface into your code. This will not work, as the IDs on the web
|
||||
interface and in the URLs are not the same as the IDs used internally
|
||||
in the API, so don't do that.
|
||||
|
||||
Return values
|
||||
-------------
|
||||
Unless otherwise specified, all data is returned as python
|
||||
dictionaries, matching the JSON format used by the API.
|
||||
For complete documentation on what every function returns,
|
||||
check the `Mastodon API docs`_, or just play around a bit - the
|
||||
format of the data is generally very easy to understand.
|
||||
|
||||
.. py:module:: mastodon
|
||||
.. py:class: Mastodon
|
||||
User dicts
|
||||
~~~~~~~~~~
|
||||
.. code-block:: python
|
||||
|
||||
mastodon.account(<numerical id>)
|
||||
# Returns the following dictionary:
|
||||
{
|
||||
'display_name': The user's display name
|
||||
'acct': The user's account name as username@domain (@domain omitted for local users)
|
||||
'following_count': How many people they follow
|
||||
'url': Their URL; usually 'https://mastodon.social/users/<acct>'
|
||||
'statuses_count': How many statuses they have
|
||||
'followers_count': How many followers they have
|
||||
'avatar': URL for their avatar
|
||||
'note': Their bio
|
||||
'header': URL for their header image
|
||||
'id': Same as <numerical id>
|
||||
'username': The username (what you @ them with)
|
||||
}
|
||||
|
||||
Toot dicts
|
||||
~~~~~~~~~~
|
||||
.. code-block:: python
|
||||
|
||||
mastodon.toot("Hello from Python")
|
||||
# Returns the following dictionary:
|
||||
{
|
||||
'sensitive': Denotes whether the toot is marked sensitive
|
||||
'created_at': Creation time
|
||||
'mentions': A list of account dicts mentioned in the toot
|
||||
'uri': Descriptor for the toot
|
||||
EG 'tag:mastodon.social,2016-11-25:objectId=<id>:objectType=Status'
|
||||
'tags': A list of hashtag dicts used in the toot
|
||||
'in_reply_to_id': Numerical id of the toot this toot is in response to
|
||||
'id': Numerical id of this toot
|
||||
'reblogs_count': Number of reblogs
|
||||
'favourites_count': Number of favourites
|
||||
'reblog': Denotes whether the toot is a reblog
|
||||
'url': URL of the toot
|
||||
'content': Content of the toot, as HTML: '<p>Hello from Python</p>'
|
||||
'favourited': Denotes whether the logged in user has favourited this toot
|
||||
'account': Account dict for the logged in account
|
||||
}
|
||||
|
||||
Relationship dicts
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
.. code-block:: python
|
||||
|
||||
mastodon.account_follow(<numerical id>)
|
||||
# Returns the following dictionary:
|
||||
{
|
||||
'followed_by': Boolean denoting whether they follow you back
|
||||
'following': Boolean denoting whether you follow them
|
||||
'id': Numerical id (same one as <numerical id>)
|
||||
'blocking': Boolean denoting whether you are blocking them
|
||||
}
|
||||
|
||||
Notification dicts
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
.. code-block:: python
|
||||
|
||||
mastodon.notifications()[0]
|
||||
# Returns the following dictionary:
|
||||
{
|
||||
'id': id of the notification.
|
||||
'type': "mention", "reblog", "favourite" or "follow".
|
||||
'status': In case of "mention", the mentioning status.
|
||||
In case of reblog / favourite, the reblogged / favourited status.
|
||||
'account': User dict of the user from whom the notification originates.
|
||||
}
|
||||
|
||||
Context dicts
|
||||
~~~~~~~~~~~~~
|
||||
.. code-block:: python
|
||||
|
||||
mastodon.status_context(<numerical id>)
|
||||
# Returns the following dictionary:
|
||||
{
|
||||
'descendants': A list of toot dicts
|
||||
'ancestors': A list of toot dicts
|
||||
}
|
||||
|
||||
Media dicts
|
||||
~~~~~~~~~~~
|
||||
.. code-block:: python
|
||||
|
||||
mastodon.media_post("image.jpg", "image/jpeg")
|
||||
# Returns the following dictionary:
|
||||
{
|
||||
'text_url': The display text for the media (what shows up in toots)
|
||||
'preview_url': The URL for the media preview
|
||||
'type': Media type, EG 'image'
|
||||
'url': The URL for the media
|
||||
}
|
||||
|
||||
App registration and user authentication
|
||||
----------------------------------------
|
||||
|
@ -91,7 +193,6 @@ This function allows you to get information about a users notifications.
|
|||
|
||||
.. automethod:: Mastodon.notifications
|
||||
|
||||
|
||||
Reading data: Accounts
|
||||
----------------------
|
||||
These functions allow you to get information about accounts and
|
||||
|
@ -103,7 +204,6 @@ their relationships.
|
|||
.. automethod:: Mastodon.account_following
|
||||
.. automethod:: Mastodon.account_followers
|
||||
.. automethod:: Mastodon.account_relationships
|
||||
.. automethod:: Mastodon.account_suggestions
|
||||
.. automethod:: Mastodon.account_search
|
||||
|
||||
Writing data: Statuses
|
||||
|
@ -113,11 +213,11 @@ interact with already posted statuses.
|
|||
|
||||
.. automethod:: Mastodon.status_post
|
||||
.. automethod:: Mastodon.toot
|
||||
.. automethod:: Mastodon.status_delete
|
||||
.. automethod:: Mastodon.status_reblog
|
||||
.. automethod:: Mastodon.status_unreblog
|
||||
.. automethod:: Mastodon.status_favourite
|
||||
.. automethod:: Mastodon.status_unfavourite
|
||||
.. automethod:: Mastodon.status_delete
|
||||
|
||||
Writing data: Accounts
|
||||
----------------------
|
||||
|
@ -137,6 +237,7 @@ to attach media to statuses.
|
|||
|
||||
.. automethod:: Mastodon.media_post
|
||||
|
||||
|
||||
.. _Mastodon: https://github.com/Gargron/mastodon
|
||||
.. _Mastodon flagship instance: http://mastodon.social/
|
||||
.. _Mastodon api docs: https://github.com/Gargron/mastodon/wiki/API
|
||||
|
|
|
@ -29,7 +29,7 @@ class Mastodon:
|
|||
@staticmethod
|
||||
def create_app(client_name, scopes = ['read', 'write', 'follow'], redirect_uris = None, to_file = None, api_base_url = __DEFAULT_BASE_URL):
|
||||
"""
|
||||
Creates a new app with given client_name and scopes (read, write, follow)
|
||||
Create a new app with given client_name and scopes (read, write, follow)
|
||||
|
||||
Specify redirect_uris if you want users to be redirected to a certain page after authenticating.
|
||||
Specify to_file to persist your apps info to a file so you can use them in the constructor.
|
||||
|
@ -64,7 +64,7 @@ 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 = 0.9):
|
||||
"""
|
||||
Creates a new API wrapper instance based on the given client_secret and client_id. If you
|
||||
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.
|
||||
|
||||
You can also directly specify an access_token, directly or as a file.
|
||||
|
@ -108,15 +108,15 @@ class Mastodon:
|
|||
|
||||
def log_in(self, username, password, scopes = ['read', 'write', 'follow'], to_file = None):
|
||||
"""
|
||||
Logs in and sets access_token to what was returned. Note that your
|
||||
Log in and sets access_token to what was returned. Note that your
|
||||
username is the e-mail you use to log in into mastodon.
|
||||
|
||||
Can persist access token to file, to be used in the constructor.
|
||||
|
||||
Will throw an exception if username / password are wrong, scopes are not
|
||||
valid or granted scopes differ from requested.
|
||||
Will throw a MastodonIllegalArgumentError if username / password
|
||||
are wrong, scopes are not valid or granted scopes differ from requested.
|
||||
|
||||
Returns the access_token, as well.
|
||||
Returns the access_token.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
params['client_id'] = self.client_id
|
||||
|
@ -125,7 +125,7 @@ class Mastodon:
|
|||
params['scope'] = " ".join(scopes)
|
||||
|
||||
try:
|
||||
response = self.__api_request('POST', '/oauth/token', params)
|
||||
response = self.__api_request('POST', '/oauth/token', params, do_ratelimiting = False)
|
||||
self.access_token = response['access_token']
|
||||
except:
|
||||
raise MastodonIllegalArgumentError('Invalid user name, password or scopes.')
|
||||
|
@ -147,35 +147,45 @@ class Mastodon:
|
|||
##
|
||||
def timeline(self, timeline = "home", max_id = None, since_id = None, limit = None):
|
||||
"""
|
||||
Returns statuses, most recent ones first. Timeline can be home, mentions, public
|
||||
Fetch statuses, most recent ones first. Timeline can be home, mentions, public
|
||||
or tag/hashtag. See the following functions documentation for what those do.
|
||||
|
||||
The default timeline is the "home" timeline.
|
||||
|
||||
Returns a list of toot dicts.
|
||||
"""
|
||||
params = self.__generate_params(locals(), ['timeline'])
|
||||
return self.__api_request('GET', '/api/v1/timelines/' + timeline, params)
|
||||
|
||||
def timeline_home(self, max_id = None, since_id = None, limit = None):
|
||||
"""
|
||||
Returns the authenticated users home timeline (i.e. followed users and self).
|
||||
Fetch the authenticated users home timeline (i.e. followed users and self).
|
||||
|
||||
Returns a list of toot dicts.
|
||||
"""
|
||||
return self.timeline('home', max_id = max_id, since_id = since_id, limit = limit)
|
||||
|
||||
def timeline_mentions(self, max_id = None, since_id = None, limit = None):
|
||||
"""
|
||||
Returns the authenticated users mentions.
|
||||
Fetches the authenticated users mentions.
|
||||
|
||||
Returns a list of toot dicts.
|
||||
"""
|
||||
return self.timeline('mentions', max_id = max_id, since_id = since_id, limit = limit)
|
||||
|
||||
def timeline_public(self, max_id = None, since_id = None, limit = None):
|
||||
"""
|
||||
Returns the public / visible-network timeline.
|
||||
Fetches the public / visible-network timeline.
|
||||
|
||||
Returns a list of toot dicts.
|
||||
"""
|
||||
return self.timeline('public', max_id = max_id, since_id = since_id, limit = limit)
|
||||
|
||||
def timeline_hashtag(self, hashtag, max_id = None, since_id = None, limit = None):
|
||||
"""
|
||||
Returns all toots with a given hashtag.
|
||||
Fetch a timeline of toots with a given hashtag.
|
||||
|
||||
Returns a list of toot dicts.
|
||||
"""
|
||||
return self.timeline('tag/' + str(hashtag), max_id = max_id, since_id = since_id, limit = limit)
|
||||
|
||||
|
@ -184,25 +194,33 @@ class Mastodon:
|
|||
###
|
||||
def status(self, id):
|
||||
"""
|
||||
Returns a status.
|
||||
Fetch information about a single toot.
|
||||
|
||||
Returns a toot dict.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id))
|
||||
|
||||
def status_context(self, id):
|
||||
"""
|
||||
Returns ancestors and descendants of the status.
|
||||
Fetch information about ancestors and descendants of a toot.
|
||||
|
||||
Returns a context dict.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/context')
|
||||
|
||||
def status_reblogged_by(self, id):
|
||||
"""
|
||||
Returns a list of users that have reblogged a status.
|
||||
Fetch a list of users that have reblogged a status.
|
||||
|
||||
Returns a list of user dicts.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/reblogged_by')
|
||||
|
||||
def status_favourited_by(self, id):
|
||||
"""
|
||||
Returns a list of users that have favourited a status.
|
||||
Fetch a list of users that have favourited a status.
|
||||
|
||||
Returns a list of user dicts.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/favourited_by')
|
||||
|
||||
|
@ -211,8 +229,10 @@ class Mastodon:
|
|||
###
|
||||
def notifications(self):
|
||||
"""
|
||||
Returns notifications (mentions, favourites, reblogs, follows) for the authenticated
|
||||
Fetch notifications (mentions, favourites, reblogs, follows) for the authenticated
|
||||
user.
|
||||
|
||||
Returns a list of notification dicts.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/notifications')
|
||||
|
||||
|
@ -221,53 +241,61 @@ class Mastodon:
|
|||
###
|
||||
def account(self, id):
|
||||
"""
|
||||
Returns account.
|
||||
Fetch account information by user id.
|
||||
|
||||
Returns a user dict.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id))
|
||||
|
||||
def account_verify_credentials(self):
|
||||
"""
|
||||
Returns authenticated user's account.
|
||||
Fetch authenticated user's account information.
|
||||
|
||||
Returns a user dict.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/accounts/verify_credentials')
|
||||
|
||||
def account_statuses(self, id, max_id = None, since_id = None, limit = None):
|
||||
"""
|
||||
Returns statuses by user. Same options as timeline are permitted.
|
||||
Fetch statuses by user id. Same options as timeline are permitted.
|
||||
|
||||
Returns a list of toot dicts.
|
||||
"""
|
||||
params = self.__generate_params(locals(), ['id'])
|
||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/statuses', params)
|
||||
|
||||
def account_following(self, id):
|
||||
"""
|
||||
Returns users the given user is following.
|
||||
Fetch users the given user is following.
|
||||
|
||||
Returns a list of user dicts.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/following')
|
||||
|
||||
def account_followers(self, id):
|
||||
"""
|
||||
Returns users the given user is followed by.
|
||||
Fetch users the given user is followed by.
|
||||
|
||||
Returns a list of user dicts.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/followers')
|
||||
|
||||
def account_relationships(self, id):
|
||||
"""
|
||||
Returns relationships (following, followed_by, blocking) of the logged in user to
|
||||
Fetch relationships (following, followed_by, blocking) of the logged in user to
|
||||
a given account. id can be a list.
|
||||
|
||||
Returns a list of relationship dicts.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/accounts/relationships', params)
|
||||
|
||||
def account_suggestions(self):
|
||||
"""
|
||||
Returns accounts that the system suggests the authenticated user to follow.
|
||||
"""
|
||||
return self.__api_request('GET', '/api/v1/accounts/suggestions')
|
||||
|
||||
def account_search(self, q, limit = None):
|
||||
"""
|
||||
Returns matching accounts. Will lookup an account remotely if the search term is
|
||||
Fetch matching accounts. Will lookup an account remotely if the search term is
|
||||
in the username@domain format and not yet in the database.
|
||||
|
||||
Returns a list of user dicts.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/accounts/search', params)
|
||||
|
@ -277,10 +305,10 @@ class Mastodon:
|
|||
###
|
||||
def status_post(self, status, in_reply_to_id = None, media_ids = None):
|
||||
"""
|
||||
Posts a status. Can optionally be in reply to another status and contain
|
||||
Post a status. Can optionally be in reply to another status and contain
|
||||
up to four pieces of media (Uploaded via media_post()).
|
||||
|
||||
Returns the new status.
|
||||
Returns a toot dict with the new status.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('POST', '/api/v1/statuses', params)
|
||||
|
@ -288,41 +316,46 @@ class Mastodon:
|
|||
def toot(self, status):
|
||||
"""
|
||||
Synonym for status_post that only takes the status text as input.
|
||||
|
||||
Returns a toot dict with the new status.
|
||||
"""
|
||||
return self.status_post(status)
|
||||
|
||||
def status_delete(self, id):
|
||||
"""
|
||||
Deletes a status
|
||||
Delete a status
|
||||
|
||||
Returns an empty dict for good measure.
|
||||
"""
|
||||
return self.__api_request('DELETE', '/api/v1/statuses/' + str(id))
|
||||
|
||||
def status_reblog(self, id):
|
||||
"""Reblogs a status.
|
||||
"""Reblog a status.
|
||||
|
||||
Returns a new status that wraps around the reblogged one."""
|
||||
Returns a toot with with a new status that wraps around the reblogged one.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/reblog")
|
||||
|
||||
def status_unreblog(self, id):
|
||||
"""
|
||||
Un-reblogs a status.
|
||||
Un-reblog a status.
|
||||
|
||||
Returns the status that used to be reblogged.
|
||||
Returns a toot dict with the status that used to be reblogged.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/unreblog")
|
||||
|
||||
def status_favourite(self, id):
|
||||
"""
|
||||
Favourites a status.
|
||||
Favourite a status.
|
||||
|
||||
Returns the favourited status.
|
||||
Returns a toot dict with the favourited status.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/favourite")
|
||||
|
||||
def status_unfavourite(self, id):
|
||||
"""Favourites a status.
|
||||
"""Favourite a status.
|
||||
|
||||
Returns the un-favourited status.
|
||||
Returns a toot dict with the un-favourited status.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/statuses/' + str(id) + "/unfavourite")
|
||||
|
||||
|
@ -331,33 +364,33 @@ class Mastodon:
|
|||
###
|
||||
def account_follow(self, id):
|
||||
"""
|
||||
Follows a user.
|
||||
Follow a user.
|
||||
|
||||
Returns the updated relationship to the user.
|
||||
Returns a relationship dict containing the updated relationship to the user.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/follow")
|
||||
|
||||
def account_unfollow(self, id):
|
||||
"""
|
||||
Unfollows a user.
|
||||
Unfollow a user.
|
||||
|
||||
Returns the updated relationship to the user.
|
||||
Returns a relationship dict containing the updated relationship to the user.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unfollow")
|
||||
|
||||
def account_block(self, id):
|
||||
"""
|
||||
Blocks a user.
|
||||
Block a user.
|
||||
|
||||
Returns the updated relationship to the user.
|
||||
Returns a relationship dict containing the updated relationship to the user.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/block")
|
||||
|
||||
def account_unblock(self, id):
|
||||
"""
|
||||
Unblocks a user.
|
||||
Unblock a user.
|
||||
|
||||
Returns the updated relationship to the user.
|
||||
Returns a relationship dict containing the updated relationship to the user.
|
||||
"""
|
||||
return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unblock")
|
||||
|
||||
|
@ -366,20 +399,18 @@ class Mastodon:
|
|||
###
|
||||
def media_post(self, media_file, mime_type = None):
|
||||
"""
|
||||
Posts an image. media_file can either be image data or
|
||||
Post an image. media_file can either be image data or
|
||||
a file name. If image data is passed directly, the mime
|
||||
type has to be specified manually, otherwise, it is
|
||||
determined from the file name.
|
||||
|
||||
Returns the uploaded media metadata object. Importantly, this contains
|
||||
the ID that can then be used in status_post() to attach the media to
|
||||
a toot.
|
||||
|
||||
Throws a MastodonIllegalArgumentError if the mime type of the
|
||||
passed data or file can not be determined properly.
|
||||
|
||||
Returns a media dict. This contains the id that can be used in
|
||||
status_post to attach the media file to a toot.
|
||||
"""
|
||||
|
||||
if os.path.isfile(media_file):
|
||||
if os.path.isfile(media_file) and mime_type == None:
|
||||
mime_type = mimetypes.guess_type(media_file)[0]
|
||||
media_file = open(media_file, 'rb')
|
||||
|
||||
|
@ -395,7 +426,7 @@ class Mastodon:
|
|||
###
|
||||
# Internal helpers, dragons probably
|
||||
###
|
||||
def __api_request(self, method, endpoint, params = {}, files = {}):
|
||||
def __api_request(self, method, endpoint, params = {}, files = {}, do_ratelimiting = True):
|
||||
"""
|
||||
Internal API request helper.
|
||||
|
||||
|
@ -410,7 +441,7 @@ class Mastodon:
|
|||
|
||||
# "pace" mode ratelimiting: Assume constant rate of requests, sleep a little less long than it
|
||||
# would take to not hit the rate limit at that request rate.
|
||||
if self.ratelimit_method == "pace":
|
||||
if do_ratelimiting and self.ratelimit_method == "pace":
|
||||
if self.ratelimit_remaining == 0:
|
||||
to_next = self.ratelimit_reset - time.time()
|
||||
if to_next > 0:
|
||||
|
@ -472,20 +503,21 @@ class Mastodon:
|
|||
raise MastodonAPIError("Could not parse response as JSON, respose code was " + str(response_object.status_code))
|
||||
|
||||
# Handle rate limiting
|
||||
self.ratelimit_remaining = int(response_object.headers['X-RateLimit-Remaining'])
|
||||
self.ratelimit_limit = int(response_object.headers['X-RateLimit-Limit'])
|
||||
self.ratelimit_reset = (datetime.strptime(response_object.headers['X-RateLimit-Reset'], "%Y-%m-%dT%H:%M:%S.%fZ") - datetime(1970, 1, 1)).total_seconds()
|
||||
self.ratelimit_lastcall = time.time()
|
||||
|
||||
if "error" in response and response["error"] == "Throttled":
|
||||
if self.ratelimit_method == "throw":
|
||||
raise MastodonRatelimitError("Hit rate limit.")
|
||||
|
||||
if self.ratelimit_method == "wait" or self.ratelimit_method == "pace":
|
||||
to_next = self.ratelimit_reset - time.time()
|
||||
if to_next > 0:
|
||||
time.sleep(to_next)
|
||||
request_complete = False
|
||||
if 'X-RateLimit-Remaining' in response_object.headers and do_ratelimiting:
|
||||
self.ratelimit_remaining = int(response_object.headers['X-RateLimit-Remaining'])
|
||||
self.ratelimit_limit = int(response_object.headers['X-RateLimit-Limit'])
|
||||
self.ratelimit_reset = (datetime.strptime(response_object.headers['X-RateLimit-Reset'], "%Y-%m-%dT%H:%M:%S.%fZ") - datetime(1970, 1, 1)).total_seconds()
|
||||
self.ratelimit_lastcall = time.time()
|
||||
|
||||
if "error" in response and response["error"] == "Throttled":
|
||||
if self.ratelimit_method == "throw":
|
||||
raise MastodonRatelimitError("Hit rate limit.")
|
||||
|
||||
if self.ratelimit_method == "wait" or self.ratelimit_method == "pace":
|
||||
to_next = self.ratelimit_reset - time.time()
|
||||
if to_next > 0:
|
||||
time.sleep(to_next)
|
||||
request_complete = False
|
||||
|
||||
return response
|
||||
|
||||
|
|
Loading…
Referencia en una nova incidència