Merge branch 'master' into cleanup-methods

This commit is contained in:
Lorenz Diener 2017-11-21 13:50:57 +01:00 cometido por GitHub
commit 0610b07682
No se encontró ninguna clave conocida en la base de datos para esta firma
ID de clave GPG: 4AEE18F83AFDEB23

Veure arxiu

@ -16,7 +16,10 @@ import dateutil.parser
import re
import copy
import threading
from urllib.parse import urlparse
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
class Mastodon:
@ -569,7 +572,7 @@ class Mastodon:
def toot(self, status):
"""
Synonym for status_post that only takes the status text as input.
Usage in production code is not recommended.
Returns a toot dict with the new status.
@ -901,7 +904,7 @@ class Mastodon:
If async is False, this method blocks forever.
If async is True, 'listener' will listen on another thread and this method
If async is True, 'listener' will listen on another thread and this method
will return a handle corresponding to the open connection. The
connection may be closed at any time by calling its close() method.
"""
@ -914,7 +917,7 @@ class Mastodon:
If async is False, this method blocks forever.
If async is True, 'listener' will listen on another thread and this method
If async is True, 'listener' will listen on another thread and this method
will return a handle corresponding to the open connection. The
connection may be closed at any time by calling its close() method.
"""
@ -927,7 +930,7 @@ class Mastodon:
If async is False, this method blocks forever.
If async is True, 'listener' will listen on another thread and this method
If async is True, 'listener' will listen on another thread and this method
will return a handle corresponding to the open connection. The
connection may be closed at any time by calling its close() method.
"""
@ -941,12 +944,12 @@ class Mastodon:
If async is False, this method blocks forever.
If async is True, 'listener' will listen on another thread and this method
If async is True, 'listener' will listen on another thread and this method
will return a handle corresponding to the open connection. The
connection may be closed at any time by calling its close() method.
"""
return self.__stream("/api/v1/streaming/hashtag?tag={}".format(tag), listener)
###
# Internal helpers, dragons probably
###
@ -982,7 +985,7 @@ class Mastodon:
except:
raise MastodonAPIError('Encountered invalid date.')
return json_object
def __api_request(self, method, endpoint, params={}, files={}, do_ratelimiting=True):
"""
Internal API request helper.
@ -1037,6 +1040,28 @@ class Mastodon:
except Exception as e:
raise MastodonNetworkError("Could not complete request: %s" % e)
if response_object is None:
raise MastodonIllegalArgumentError("Illegal request.")
# Parse rate limiting headers
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'])
try:
ratelimit_reset_datetime = dateutil.parser.parse(response_object.headers['X-RateLimit-Reset'])
self.ratelimit_reset = self.__datetime_to_epoch(ratelimit_reset_datetime)
# Adjust server time to local clock
if 'Date' in response_object.headers:
server_time_datetime = dateutil.parser.parse(response_object.headers['Date'])
server_time = self.__datetime_to_epoch(server_time_datetime)
server_time_diff = time.time() - server_time
self.ratelimit_reset += server_time_diff
self.ratelimit_lastcall = time.time()
except Exception as e:
raise MastodonRatelimitError("Rate limit time calculations failed: %s" % e)
# Handle response
if self.debug_requests:
print('Mastodon: Response received with code ' + str(response_object.status_code) + '.')
@ -1048,16 +1073,29 @@ class Mastodon:
response = response_object.json()
except:
raise MastodonAPIError('Endpoint not found.')
if isinstance(response, dict) and 'error' in response:
raise MastodonAPIError("Mastodon API returned error: " + str(response['error']))
else:
raise MastodonAPIError('Endpoint not found.')
if response_object.status_code == 500:
raise MastodonAPIError('General API problem.')
# Handle rate limiting
if response_object.status_code == 429:
if self.ratelimit_method == 'throw' or not do_ratelimiting:
raise MastodonRatelimitError('Hit rate limit.')
elif self.ratelimit_method in ('wait', 'pace'):
to_next = self.ratelimit_reset - time.time()
if to_next > 0:
# As a precaution, never sleep longer than 5 minutes
to_next = min(to_next, 5 * 60)
time.sleep(to_next)
request_complete = False
continue
try:
response = response_object.json(object_hook=self.__json_date_parse)
except:
@ -1065,11 +1103,11 @@ class Mastodon:
"Could not parse response as JSON, response code was %s, "
"bad json content was '%s'" % (response_object.status_code,
response_object.content))
# See if the returned dict is an error dict even though status is 200
if isinstance(response, dict) and 'error' in response:
raise MastodonAPIError("Mastodon API returned error: " + str(response['error']))
# Parse link headers
if isinstance(response, list) and \
'Link' in response_object.headers and \
@ -1108,36 +1146,6 @@ class Mastodon:
del prev_params['max_id']
response[0]['_pagination_prev'] = prev_params
# Handle rate limiting
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'])
try:
ratelimit_reset_datetime = dateutil.parser.parse(response_object.headers['X-RateLimit-Reset'])
self.ratelimit_reset = self.__datetime_to_epoch(ratelimit_reset_datetime)
# Adjust server time to local clock
if 'Date' in response_object.headers:
server_time_datetime = dateutil.parser.parse(response_object.headers['Date'])
server_time = self.__datetime_to_epoch(server_time_datetime)
server_time_diff = time.time() - server_time
self.ratelimit_reset += server_time_diff
self.ratelimit_lastcall = time.time()
except Exception as e:
raise MastodonRatelimitError("Rate limit time calculations failed: %s" % e)
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:
# As a precaution, never sleep longer than 5 minutes
to_next = min(to_next, 5 * 60)
time.sleep(to_next)
request_complete = False
return response