Dynamic requests #72
1 changed files with 54 additions and 30 deletions
|
|
@ -13,7 +13,6 @@ __version__ = "1.6.0"
|
||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
import re
|
import re
|
||||||
import inspect
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
@ -51,20 +50,6 @@ except ImportError:
|
||||||
# Seriously wtf is wrong with you if you get this Exception.
|
# Seriously wtf is wrong with you if you get this Exception.
|
||||||
raise Exception("Twython requires the simplejson library (or Python 2.6) to work. http://www.undefined.org/python/")
|
raise Exception("Twython requires the simplejson library (or Python 2.6) to work. http://www.undefined.org/python/")
|
||||||
|
|
||||||
# Try and gauge the old OAuth2 library spec. Versions 1.5 and greater no longer have the callback
|
|
||||||
# url as part of the request object; older versions we need to patch for Python 2.5... ugh. ;P
|
|
||||||
OAUTH_CALLBACK_IN_URL = False
|
|
||||||
OAUTH_LIB_SUPPORTS_CALLBACK = False
|
|
||||||
if not hasattr(oauth, '_version') or float(oauth._version.manual_verstr) <= 1.4:
|
|
||||||
OAUTH_CLIENT_INSPECTION = inspect.getargspec(oauth.Client.request)
|
|
||||||
try:
|
|
||||||
OAUTH_LIB_SUPPORTS_CALLBACK = 'callback_url' in OAUTH_CLIENT_INSPECTION.args
|
|
||||||
except AttributeError:
|
|
||||||
# Python 2.5 doesn't return named tuples, so don't look for an args section specifically.
|
|
||||||
OAUTH_LIB_SUPPORTS_CALLBACK = 'callback_url' in OAUTH_CLIENT_INSPECTION
|
|
||||||
else:
|
|
||||||
OAUTH_CALLBACK_IN_URL = True
|
|
||||||
|
|
||||||
|
|
||||||
class TwythonError(AttributeError):
|
class TwythonError(AttributeError):
|
||||||
"""
|
"""
|
||||||
|
|
@ -78,8 +63,12 @@ class TwythonError(AttributeError):
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg, error_code=None):
|
def __init__(self, msg, error_code=None):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
if error_code == 400:
|
|
||||||
raise TwythonAPILimit(msg)
|
if error_code is not None:
|
||||||
|
self.msg = self.msg + ' Please see https://dev.twitter.com/docs/error-codes-responses for additional information.'
|
||||||
|
|
||||||
|
if error_code == 400 or error_code == 420:
|
||||||
|
raise TwythonAPILimit(self.msg)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return repr(self.msg)
|
return repr(self.msg)
|
||||||
|
|
@ -210,6 +199,9 @@ class Twython(object):
|
||||||
for key in api_table.keys():
|
for key in api_table.keys():
|
||||||
self.__dict__[key] = setFunc(key)
|
self.__dict__[key] = setFunc(key)
|
||||||
|
|
||||||
|
# create stash for last call intel
|
||||||
|
self._last_call = None
|
||||||
|
|
||||||
def _constructFunc(self, api_call, **kwargs):
|
def _constructFunc(self, api_call, **kwargs):
|
||||||
# Go through and replace any mustaches that are in our API url.
|
# Go through and replace any mustaches that are in our API url.
|
||||||
fn = api_table[api_call]
|
fn = api_table[api_call]
|
||||||
|
|
@ -228,7 +220,7 @@ class Twython(object):
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def _request(self, url, method='GET', params=None):
|
def _request(self, url, method='GET', params=None, api_call=None):
|
||||||
'''
|
'''
|
||||||
Internal response generator, not sense in repeating the same
|
Internal response generator, not sense in repeating the same
|
||||||
code twice, right? ;)
|
code twice, right? ;)
|
||||||
|
|
@ -243,22 +235,37 @@ class Twython(object):
|
||||||
|
|
||||||
func = getattr(self.client, method)
|
func = getattr(self.client, method)
|
||||||
response = func(url, data=myargs)
|
response = func(url, data=myargs)
|
||||||
|
content = response.content.decode('utf-8')
|
||||||
|
|
||||||
|
# create stash for last function intel
|
||||||
|
self._last_call = {
|
||||||
|
'api_call': api_call,
|
||||||
|
'api_error': None,
|
||||||
|
'cookies': response.cookies,
|
||||||
|
'error': response.error,
|
||||||
|
'headers': response.headers,
|
||||||
|
'status_code': response.status_code,
|
||||||
|
'url': response.url,
|
||||||
|
'content': content,
|
||||||
|
}
|
||||||
|
|
||||||
# Python 2.6 `json` will throw a ValueError if it
|
# Python 2.6 `json` will throw a ValueError if it
|
||||||
# can't load the string as valid JSON,
|
# can't load the string as valid JSON,
|
||||||
# `simplejson` will throw simplejson.decoder.JSONDecodeError
|
# `simplejson` will throw simplejson.decoder.JSONDecodeError
|
||||||
# But excepting just ValueError will work with both. o.O
|
# But excepting just ValueError will work with both. o.O
|
||||||
try:
|
try:
|
||||||
content = simplejson.loads(response.content.decode('utf-8'))
|
content = simplejson.loads(content)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise TwythonError('Response was not valid JSON, unable to decode.')
|
raise TwythonError('Response was not valid JSON, unable to decode.')
|
||||||
|
|
||||||
if response.status_code > 302:
|
if response.status_code > 304:
|
||||||
# Just incase there is no error message, let's set a default
|
# Just incase there is no error message, let's set a default
|
||||||
error_msg = 'An error occurred processing your request.'
|
error_msg = 'An error occurred processing your request.'
|
||||||
if content.get('error') is not None:
|
if content.get('error') is not None:
|
||||||
error_msg = content['error']
|
error_msg = content['error']
|
||||||
|
|
||||||
|
self._last_call = error_msg
|
||||||
|
|
||||||
raise TwythonError(error_msg, error_code=response.status_code)
|
raise TwythonError(error_msg, error_code=response.status_code)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
@ -280,7 +287,7 @@ class Twython(object):
|
||||||
else:
|
else:
|
||||||
url = '%s%s.json' % (self.api_url % version, endpoint)
|
url = '%s%s.json' % (self.api_url % version, endpoint)
|
||||||
|
|
||||||
content = self._request(url, method=method, params=params)
|
content = self._request(url, method=method, params=params, api_call=url)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
@ -298,16 +305,38 @@ class Twython(object):
|
||||||
|
|
||||||
# End Dynamic Request Methods
|
# End Dynamic Request Methods
|
||||||
|
|
||||||
|
def get_lastfunction_header(self, header):
|
||||||
|
"""
|
||||||
|
get_lastfunction_header(self)
|
||||||
|
|
||||||
|
returns the header in the last function
|
||||||
|
this must be called after an API call, as it returns header based information.
|
||||||
|
this will return None if the header is not present
|
||||||
|
|
||||||
|
most useful for the following header information:
|
||||||
|
x-ratelimit-limit
|
||||||
|
x-ratelimit-remaining
|
||||||
|
x-ratelimit-class
|
||||||
|
x-ratelimit-reset
|
||||||
|
"""
|
||||||
|
if self._last_call is None:
|
||||||
|
raise TwythonError('This function must be called after an API call. It delivers header information.')
|
||||||
|
if header in self._last_call['headers']:
|
||||||
|
return self._last_call['headers'][header]
|
||||||
|
return None
|
||||||
|
|
||||||
def get_authentication_tokens(self):
|
def get_authentication_tokens(self):
|
||||||
"""
|
"""
|
||||||
get_auth_url(self)
|
get_auth_url(self)
|
||||||
|
|
||||||
Returns an authorization URL for a user to hit.
|
Returns an authorization URL for a user to hit.
|
||||||
"""
|
"""
|
||||||
callback_url = self.callback_url or 'oob'
|
callback_url = self.callback_url
|
||||||
|
|
||||||
request_args = {}
|
request_args = {}
|
||||||
|
if callback_url:
|
||||||
request_args['oauth_callback'] = callback_url
|
request_args['oauth_callback'] = callback_url
|
||||||
|
|
||||||
method = 'get'
|
method = 'get'
|
||||||
|
|
||||||
func = getattr(self.client, method)
|
func = getattr(self.client, method)
|
||||||
|
|
@ -322,17 +351,12 @@ class Twython(object):
|
||||||
|
|
||||||
oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed') == 'true'
|
oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed') == 'true'
|
||||||
|
|
||||||
if not OAUTH_LIB_SUPPORTS_CALLBACK and callback_url != 'oob' and oauth_callback_confirmed:
|
|
||||||
import warnings
|
|
||||||
warnings.warn("oauth2 library doesn't support OAuth 1.0a type callback, but remote requires it")
|
|
||||||
oauth_callback_confirmed = False
|
|
||||||
|
|
||||||
auth_url_params = {
|
auth_url_params = {
|
||||||
'oauth_token': request_tokens['oauth_token'],
|
'oauth_token': request_tokens['oauth_token'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# Use old-style callback argument
|
# Use old-style callback argument if server didn't accept new-style
|
||||||
if OAUTH_CALLBACK_IN_URL or (callback_url != 'oob' and not oauth_callback_confirmed):
|
if callback_url and not oauth_callback_confirmed:
|
||||||
auth_url_params['oauth_callback'] = callback_url
|
auth_url_params['oauth_callback'] = callback_url
|
||||||
|
|
||||||
request_tokens['auth_url'] = self.authenticate_url + '?' + urllib.urlencode(auth_url_params)
|
request_tokens['auth_url'] = self.authenticate_url + '?' + urllib.urlencode(auth_url_params)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue