Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

oops

  • Loading branch information...
commit 88eb98fbabc2e3dbbacb29820296724f72cc17f2 1 parent 411282a
@maxcountryman maxcountryman authored
Showing with 817 additions and 0 deletions.
  1. +9 −0 rauth/__init__.py
  2. +161 −0 rauth/hook.py
  3. +185 −0 rauth/oauth.py
  4. +462 −0 rauth/service.py
View
9 rauth/__init__.py
@@ -0,0 +1,9 @@
+''''
+ rauth
+ -----
+
+ OAuth 1.0/a and 2.0 wrapped around Python Requests.
+'''
+
+
+__version__ = '0.2.2'
View
161 rauth/hook.py
@@ -0,0 +1,161 @@
+'''
+ rauth.hook
+ ----------
+
+ A hook for the Python Requests package that provides OAuth 1.0/a client
+ support.
+'''
+
+import time
+import random
+
+from hashlib import sha1
+from urllib import quote
+
+from rauth.oauth import HmacSha1Signature, Token, Consumer
+
+
+class OAuth1Hook(object):
+ '''Provides a pre-request hook into requests for OAuth 1.0/a services.
+
+ This package is built on the excellent Python Requests package. It
+ functions by "hooking" into a request and appending various attributes to
+ it which allow a client to interact with a standardized OAuth 1.0/a
+ provider.
+
+ You might intialize :class:`OAuthHook` something like this::
+
+ oauth = OAuthHook(consumer_key=1234,
+ consumer_secret=5678)
+ oauth_session = requests.session(hooks={'pre_request': oauth})
+
+ This establishes a requests session that is wrapped if the OAuth-capable
+ hook. Using this session, an OAuth provider may be interacted with and
+ will receive the proper formatting for requests.
+
+ Note that this is normally used as a starting from which a request token
+ would be generated whereupon an access token is received. Once such a token
+ has been received, the wrapper should be reinitalized with this token::
+
+ # we provide our consumer pair as well as the access pair as returned
+ # by the provider endpoint
+ oauth = OAuthHook(consumer_key=1234,
+ consumer_secret=5678,
+ access_token=4321,
+ access_token_secret=8765)
+ oauth_session = requests.session(hooks={'pre_request': oauth})
+
+ The session is now ready to make calls to the endpoints made available by
+ the provider.
+
+ Additionally some services will make use of header authentication. This is
+ provided by passing :class:`__init__` the `auth_header` parameter as
+ `True`.
+
+ :param consumer_key: Client consumer key.
+ :param consumer_secret: Client consumer secret.
+ :param access_token: Access token key.
+ :param access_token_secret: Access token secret.
+ :param header_auth: Authenication via header, defauls to False.
+ :param signature: A signature method used to sign request parameters.
+ Defaults to None. If None the `HmacSha1Signature` method is used as
+ default.
+ '''
+ OAUTH_VERSION = '1.0'
+
+ def __init__(self, consumer_key, consumer_secret, access_token=None,
+ access_token_secret=None, header_auth=False, signature=None):
+ self.consumer = Consumer(consumer_key, consumer_secret)
+
+ # intitialize the token and then set it if possible
+ self.token = None
+ if not None in (access_token, access_token_secret):
+ self.token = Token(access_token, access_token_secret)
+
+ self.header_auth = header_auth
+
+ self.signature = HmacSha1Signature()
+
+ # override the default signature object if available
+ if signature is not None:
+ self.signature = signature
+
+ def __call__(self, request):
+ # this is a workaround for a known bug that will be patched
+ if isinstance(request.params, list):
+ request.params = dict(request.params)
+ if isinstance(request.data, list):
+ request.data = dict(request.data)
+
+ # generate the necessary request params
+ request.oauth_params = self.oauth_params
+
+ # here we append an oauth_callback parameter if any
+ if 'oauth_callback' in request.data:
+ request.oauth_params['oauth_callback'] = \
+ request.data.pop('oauth_callback')
+ if 'oauth_callback' in request.params:
+ request.oauth_params['oauth_callback'] = \
+ request.params.pop('oauth_callback')
+
+ # this is used in the Normalize Request Parameters step
+ request.params_and_data = request.oauth_params.copy()
+
+ # sign and add the signature to the request params
+ self.signature.sign(request, self.consumer, self.token)
+
+ if self.header_auth:
+ # authenticate in the header
+ #
+ # TODO: implement the realm parameter
+ request.headers['Authorization'] = \
+ self.auth_header(request.params_and_data)
+ elif request.method == 'POST':
+ # HACK: override the param encoding process
+ #
+ # BUG: body can't be recalculated in a pre-request hook; this is a
+ # known issue: https://github.com/kennethreitz/requests/issues/445
+ request.data, request._enc_data = \
+ request._encode_params(request.params_and_data)
+ request.body = request._enc_data
+ request.headers['Content-Type'] = \
+ 'application/x-www-form-urlencoded'
+ else:
+ # HACK: override the param encoding process
+ request.params, request._enc_params = \
+ request._encode_params(request.params_and_data)
+
+ # we're done with these now
+ del request.params_and_data
+
+ @property
+ def oauth_params(self):
+ '''This method handles generating the necessary URL parameters the
+ OAuth provider will expect.'''
+ oauth_params = {}
+
+ oauth_params['oauth_consumer_key'] = self.consumer.key
+ oauth_params['oauth_timestamp'] = int(time.time())
+ oauth_params['oauth_nonce'] = sha1(str(random.random())).hexdigest()
+ oauth_params['oauth_version'] = self.OAUTH_VERSION
+
+ if self.token:
+ oauth_params['oauth_token'] = self.token.key
+ # this must be set upon recieving a verifier
+ oauth_params['oauth_verifier'] = self.token.verifier or ''
+
+ oauth_params['oauth_signature_method'] = self.signature.NAME
+ return oauth_params
+
+ def auth_header(self, oauth_params, realm=None):
+ '''This method constructs an authorization header.
+
+ :param oauth_params: The OAuth parameters to be added to the header.
+ :param realm: The authentication realm. Defaults to None.
+ '''
+ auth_header = 'OAuth realm="{0}"'.format(realm)
+ params = ''
+ for k, v in oauth_params.items():
+ params += ',{0}="{1}"'.format(k, quote(str(v)))
+ auth_header += params
+ return auth_header
View
185 rauth/oauth.py
@@ -0,0 +1,185 @@
+'''
+ rauth.oauth
+ -----------
+
+ A module providing various OAuth related containers.
+'''
+
+import base64
+import hmac
+
+from hashlib import sha1
+from urlparse import parse_qsl, urlsplit, urlunsplit
+from urllib import quote, urlencode
+
+
+class OAuthObject(object):
+ '''A base class for OAuth token objects.'''
+ verifier = None
+
+ def __init__(self, key, secret):
+ self.key = key
+ self.secret = secret
+
+
+class Consumer(OAuthObject):
+ '''The consumer token object.'''
+ pass
+
+
+class Token(OAuthObject):
+ '''The access token object.'''
+ pass
+
+
+class SignatureMethod(object):
+ '''A base class for signature methods providing a set of common methods.'''
+ def _encode_utf8(self, s):
+ if isinstance(s, unicode):
+ return s.encode('utf-8')
+ return unicode(s, 'utf-8').encode('utf-8')
+
+ def _escape(self, s):
+ '''Escapes a string, ensuring it is encoded as a UTF-8 octet.
+
+ :param s: A string to be encoded.
+ '''
+ return quote(self._encode_utf8(s), safe='~')
+
+ def _remove_qs(self, url):
+ '''Removes a query string from a URL before signing.
+
+ :param url: The URL to strip.
+ '''
+ # split 'em up
+ scheme, netloc, path, query, fragment = urlsplit(url)
+
+ # the query string can't be sign as per the spec, kill it
+ query = ''
+
+ # and return our query-string-less URL!
+ return urlunsplit((scheme, netloc, path, query, fragment))
+
+ def _normalize_request_parameters(self, request):
+ '''The OAuth 1.0/a specs indicate that parameter and body data must be
+ normalized. The specifics of this operation are detailed in the
+ respective specs.
+
+ Here we have to ensure that parameter and body data is properly
+ handled. This means that the case of params or data being strings is
+ taken care of.
+
+ Essentially this is achieved by checking that `request.data` and
+ `request.params` are not strings. This being the case we can then
+ construct a unified list of tuples from them.
+
+ Otherwise we build a series intermediary lists of tuples depending on
+ the type of `request.params` and `request.data`.
+
+ :param request: The request object that will be normalized.
+ '''
+ if type(request.params) != str and type(request.data) != str:
+ # if neither params nor data are a string, i.e. both are dicts
+
+ # we concatenate the respective dicts
+ params_and_data = \
+ dict(request.params.items() + request.data.items())
+
+ normalized = []
+ for k, v in params_and_data.items():
+ normalized += [(k, v)]
+ elif type(request.params) == str and type(request.data) == str:
+ # if both params and data are strings
+ params = parse_qsl(request.params)
+ data = parse_qsl(request.data)
+ normalized = params + data
+ elif type(request.params) == str:
+ # parse the string into a list of tuples
+ normalized = parse_qsl(request.params)
+
+ # extract any data
+ for k, v in request.data.items():
+ normalized += [(k, v)]
+ elif type(request.data) == str:
+ # and we do the same if data
+ normalized = parse_qsl(request.data)
+
+ # extract any params
+ for k, v in request.params.items():
+ normalized += [(k, v)]
+
+ # extract values from our list of tuples
+ all_normalized = []
+ for t in normalized:
+ k, v = t
+
+ # save key/value pairs to the request and our list
+ request.params_and_data[k] = v
+ all_normalized += [(k, v)]
+
+ # add in the params from data_and_params for signing
+ for k, v in request.params_and_data.items():
+ if (k, v) in all_normalized:
+ continue
+ all_normalized += [(k, v)]
+
+ # sort the params as per the OAuth 1.0/a spec
+ all_normalized.sort()
+
+ # finally encode the params as a string
+ return urlencode(all_normalized)
+
+
+class HmacSha1Signature(SignatureMethod):
+ '''HMAC-SHA1 Signature Method.
+
+ This is a signature method, as per the OAuth 1.0/a and 2.0 specs. As the
+ name might suggest, this method signs parameters with HMAC using SHA1.
+ '''
+ NAME = 'HMAC-SHA1'
+
+ def sign(self, request, consumer, token=None):
+ '''Sign request parameters.
+
+ :param request: The request to sign.
+ :param consumer: The consumer token object.
+ :param token: The access token object.
+ '''
+
+ # the necessary parameters we'll sign
+ url = self._remove_qs(request.url)
+ params_and_data = self._normalize_request_parameters(request)
+ parameters = [self._escape(request.method),
+ self._escape(url),
+ self._escape(params_and_data)]
+
+ # set our key
+ key = self._escape(consumer.secret) + '&'
+ if token is not None:
+ key += self._escape(token.secret)
+
+ # build a Signature Base String
+ signature_base_string = '&'.join(parameters)
+
+ # hash the string with HMAC-SHA1
+ hashed = hmac.new(key, signature_base_string, sha1)
+
+ # add the signature to the request
+ request.params_and_data['oauth_signature'] = \
+ base64.b64encode(hashed.digest())
+
+
+class RsaSha1Signature(SignatureMethod):
+ '''RSA-SHA1 Signature Method. (Not implemented)'''
+ NAME = 'RSA-SHA1'
+
+ def __init__(self):
+ raise NotImplementedError
+
+
+class PlaintextSignature(SignatureMethod):
+ '''PLAINTEXT Signature Method. (Not implemented)'''
+ NAME = 'PLAINTEXT'
+
+ def __init__(self):
+ raise NotImplementedError
View
462 rauth/service.py
@@ -0,0 +1,462 @@
+'''
+ rauth.service
+ -------------
+
+ Provides OAuth 1.0/a, 2.0 and Ofly service containers.
+'''
+
+import requests
+import json
+import hashlib
+
+from rauth.hook import OAuth1Hook
+
+from urllib import quote, urlencode
+from urlparse import parse_qsl, urlsplit
+from datetime import datetime
+
+
+def _parse_response(response):
+ '''Attempts to parse response.content. Returns a `Response` object.
+
+ :param response: A Requests response object.
+ '''
+ if isinstance(response.content, str):
+ try:
+ content = json.loads(response.content)
+ except ValueError:
+ content = dict(parse_qsl(response.content))
+ else:
+ content = response.content
+ return Response(content=content, response=response)
+
+
+class Response(object):
+ '''A service response container.
+
+ :param content: The possibly parsed content from a request.
+ :param response: The unaltered response object from Requests.
+ '''
+ def __init__(self, content, response):
+ self.content = content
+ self.response = response
+
+
+class OflyService(object):
+ '''An Ofly Service container.
+
+ This class wraps an Ofly service. Most commonly, Shutterfly. The process
+ is similar to that of OAuth 1.0 but simplified. Here we use Requests
+ directly rather than relying on a hook.
+
+ You might intialize :class:`OflyService` something like this::
+
+ service = OflyService(name='example',
+ consumer_key='123',
+ consumer_secret='456',
+ authorize_url='http://example.com/authorize')
+
+ A signed authorize URL is then produced via calling
+ `service.get_authorize_url`. Once this has been visited by the client and
+ assuming the client authorizes the request, subsequent API calls may be
+ made through `service.request`.
+
+ .. admonition:: Additional Signing Options
+
+ The signing process here only supports SHA1 although the specification
+ allows for RSA1 as well. This could be implemented in the future. For
+ more information please see:
+ http://www.shutterfly.com/documentation/OflyCallSignature.sfly
+
+ :param name: The service name.
+ :param consumer_key: Client consumer key.
+ :param consumer_secret: Client consumer secret.
+ :param authorize_url: Authorize endpoint.
+ '''
+ TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%M:%S.{0}Z'
+ MICRO_MILLISECONDS_DELTA = 1000
+
+ def __init__(self, name, consumer_key, consumer_secret, authorize_url):
+ self.name = name
+
+ self.consumer_key = consumer_key
+ self.consumer_secret = consumer_secret
+
+ self.authorize_url = authorize_url
+
+ def _micro_to_milliseconds(self, microseconds):
+ return microseconds / self.MICRO_MILLISECONDS_DELTA
+
+ def _sort_params(self, params):
+ def sorting():
+ for k in sorted(params.keys()):
+ yield '='.join((k, params[k]))
+ return '&'.join(sorting())
+
+ def _sha1_sign_params(self, url, header_auth=False, **params):
+ now = datetime.utcnow()
+ milliseconds = self._micro_to_milliseconds(now.microsecond)
+ time_format = self.TIMESTAMP_FORMAT.format(milliseconds)
+ ofly_params = \
+ {'oflyAppId': self.consumer_key,
+ 'oflyHashMeth': 'SHA1',
+ 'oflyTimestamp': now.strftime(time_format)}
+
+ # select only the path for signing
+ url_path = urlsplit(url).path
+
+ signature_base_string = self.consumer_secret \
+ + url_path \
+ + '?' \
+ + self._sort_params(params) \
+ + '&' \
+ + self._sort_params(ofly_params)
+
+ params['oflyApiSig'] = hashlib.sha1(signature_base_string).hexdigest()
+
+ if not header_auth:
+ # don't use header authentication
+ params = dict(params.items() + ofly_params.items())
+ return self._sort_params(params)
+ else:
+ # return the raw ofly_params for use in the header
+ return self._sort_params(params), ofly_params
+
+ def get_authorize_url(self, remote_user=None, redirect_uri=None, **params):
+ '''Returns a proper authorize URL.
+
+ :param remote_user: This is the oflyRemoteUser param. Defaults to None.
+ :param redirect_uri: This is the oflyCallbackUrl. Defaults to None.
+ :param params: Additional keyworded arguments to be added to the
+ request querystring.
+ '''
+ if remote_user is not None:
+ params.update({'oflyRemoteUser': remote_user})
+
+ if redirect_uri is not None:
+ params.update({'oflyCallbackUrl': redirect_uri})
+
+ params = '?' + self._sha1_sign_params(self.authorize_url, **params)
+ return self.authorize_url + params
+
+ def request(self, http_method, url, header_auth=False, params=None,
+ data=None):
+ '''Sends a request to an Ofly endpoint, properly wrapped around
+ requests.
+
+ :param http_method: A string representation of the HTTP method to be
+ used.
+ :param url: The resource to be requested.
+ :param header_auth: Authenication via header, defaults to False.
+ :param params: Additional arguments to be added to the request
+ querystring.
+ :param data: Additional data to be included in the request body.
+ '''
+ if params is None:
+ params = {}
+
+ if header_auth:
+ params, headers = self._sha1_sign_params(url,
+ header_auth=True,
+ **params)
+
+ response = requests.request(http_method,
+ url + '?' + params,
+ headers=headers)
+ else:
+ params = self._sha1_sign_params(url, **params)
+
+ response = requests.request(http_method,
+ url + '?' + params,
+ data=data)
+
+ return _parse_response(response)
+
+
+class OAuth2Service(object):
+ '''An OAuth 2.0 Service container.
+
+ This class is similar in nature to the OAuth1Service container but does
+ not make use of a request hook. Instead the OAuth 2.0 spec is currently
+ simple enough that we can wrap it around requests directly.
+
+ You might intialize :class:`OAuth2Service` something like this::
+
+ service = OAuth2Service(
+ name='example',
+ consumer_key='123',
+ consumer_secret='456',
+ access_token_url='http://example.com/token',
+ authorize_url='http://example.com/authorize')
+
+ Given the simplicity of OAuth 2.0 now this object `service` can be used to
+ retrieve an access token in two steps::
+
+ # the return URL is used to validate the request
+ url = service.get_authorize_url(redirect_uri='http://example.com/',
+ response_type='code')
+
+ # once the above URL is consumed by a client we can ask for an access
+ # token. note that the code is retrieved from the redirect URL above,
+ # as set by the provider
+ token = service.get_access_token(code='foobar',
+ grant_type='authorization_code',
+ redirect_uri='http://example.com/')
+
+ :param name: The service name.
+ :param consumer_key: Client consumer key.
+ :param consumer_secret: Client consumer secret.
+ :param access_token_url: Access token endpoint.
+ :param authorize_url: Authorize endpoint.
+ :param access_token: An access token, defaults to None.
+ '''
+ def __init__(self, name, consumer_key, consumer_secret, access_token_url,
+ authorize_url, access_token=None):
+ self.name = name
+
+ self.consumer_key = consumer_key
+ self.consumer_secret = consumer_secret
+
+ self.access_token_url = access_token_url
+ self.authorize_url = authorize_url
+
+ self.access_token = None
+ if access_token is not None:
+ self.access_token = access_token
+
+ def get_authorize_url(self, response_type='code', **params):
+ '''Returns a proper authorize URL.
+
+ :param reponse_type: The response type. Defaults to 'code'.
+ :param params: Additional keyworded arguments to be added to the
+ request querystring.
+ '''
+ params.update({'client_id': self.consumer_key,
+ 'response_type': response_type})
+ params = '?' + urlencode(params)
+ return self.authorize_url + params
+
+ def get_access_token(self, grant_type='authorization_code', **data):
+ '''Retrieves the access token.
+
+ :param grant_type: The grant type. Deaults to 'authorization_code'.
+ :param data: Keyworded arguments to be passed in the body of the
+ request.
+ '''
+ data.update({'grant_type': grant_type})
+
+ data.update(dict(client_id=self.consumer_key,
+ client_secret=self.consumer_secret))
+
+ response = requests.post(self.access_token_url,
+ data=data)
+
+ return _parse_response(response)
+
+ def request(self, http_method, url, access_token=None, params=None,
+ data=None):
+ '''Sends a request to an OAuth 2.0 endpoint, properly wrapped around
+ requests.
+
+ The first time an access token is provided it will be saved on the
+ object for convenience.
+
+ :param http_method: A string representation of the HTTP method to be
+ used.
+ :param url: The resource to be requested.
+ :param access_token: The access token as returned by
+ :class:`get_access_token`.
+ :param params: Additional arguments to be added to the request
+ querystring.
+ :param data: Additional data to be included in the request body.
+ '''
+ if access_token is None and self.access_token is None:
+ raise ValueError('Access token must be set!')
+ elif access_token is not None:
+ self.access_token = access_token
+
+ if params is None:
+ params = {}
+
+ params.update({'access_token': self.access_token})
+
+ response = requests.request(http_method, url, params=params, data=data)
+
+ return _parse_response(response)
+
+
+class OAuth1Service(object):
+ '''An OAuth 1.0/a Service container.
+
+ This class provides a container for an OAuth Service provider. It utilizes
+ the OAuthHook object which in turn is hooked into Python Requests. This
+ object can be used to streamline the process of authenticating with and
+ using an OAuth 1.0/a service provider.
+
+ You might intialize :class:`OAuth1Service` something like this::
+
+ service = OAuth1Service(
+ name='example',
+ consumer_key='123',
+ consumer_secret='456',
+ request_token_url='http://example.com/request_token',
+ access_token_url='http://example.com/access_token',
+ authorize_url='http://example.com/authorize')
+
+ Now the request token should be retrieved::
+
+ request_token, request_token_secret = service.get_request_token()
+
+ At this point it is usually necessary to redirect the client to the
+ authorize URI. This URI is retrieved as follows::
+
+ authorize_url = service.get_authorize_url(request_token)
+
+ Once the client has authorized the request it is not possible to retrieve
+ an access token. Do so as follows::
+
+ response = service.get_access_token(request_token,
+ request_token_secret,
+ http_method='GET')
+
+ # access tokens are returned in the response dictionary
+ response['oauth_token']
+ response['oauth_key']
+
+ Finally the :class:`get_authenticated_session` method returns a wrapped
+ session and can be used once the access token has been made available.
+ This provides simple access to the providers endpoints.
+
+ :param name: The service name.
+ :param consumer_key: Client consumer key.
+ :param consumer_secret: Client consumer secret.
+ :param request_token_url: Request token endpoint.
+ :param access_token_url: Access token endpoint.
+ :param authorize_url: Authorize endpoint.
+ :param header_auth: Authenication via header, defaults to False.
+ '''
+ def __init__(self, name, consumer_key, consumer_secret, request_token_url,
+ access_token_url, authorize_url, header_auth=False):
+ self.name = name
+
+ self.consumer_key = consumer_key
+ self.consumer_secret = consumer_secret
+
+ # authorization endpoints
+ self.request_token_url = request_token_url
+ self.access_token_url = access_token_url
+ self.authorize_url = authorize_url
+
+ # set to True to use header authentication for this service
+ self.header_auth = header_auth
+
+ def _construct_session(self, **kwargs):
+ '''Construct the request session, supplying the consumer key and
+ secret.
+
+ :param kwargs: Extra keyworded arguments to be passed to the
+ OAuth1Hook constructor.
+ '''
+ hook = OAuth1Hook(consumer_key=self.consumer_key,
+ consumer_secret=self.consumer_secret,
+ **kwargs)
+ return requests.session(hooks={'pre_request': hook})
+
+ def get_request_token(self, http_method, **data):
+ '''Gets a request token from the request token endpoint.
+
+ :param http_method: A string representation of the HTTP method to be
+ used.
+ :param data: Keyworded arguments to be passed in the body of the
+ request.
+ '''
+ auth_session = \
+ self._construct_session(header_auth=self.header_auth)
+
+ response = auth_session.request(http_method,
+ self.request_token_url,
+ data=data)
+
+ response.raise_for_status()
+
+ data = dict(parse_qsl(response.content))
+ return data['oauth_token'], data['oauth_token_secret']
+
+ def get_authorize_url(self, request_token, **params):
+ '''Returns a proper authorize URL.
+
+ :param request_token: The request token as returned by
+ :class:`get_request_token`.
+ :param params: Additional keyworded arguments to be added to the
+ request querystring.
+ '''
+ params.update({'oauth_token': quote(request_token)})
+ params = '?' + urlencode(params)
+ return self.authorize_url + params
+
+ def get_access_token(self, request_token, request_token_secret,
+ http_method, **params):
+ '''Retrieves the access token.
+
+ :param request_token: The request token as returned by
+ :class:`get_request_token`.
+ :param request_token_secret: The request token secret as returned by
+ :class:`get_request_token`.
+ :param http_method: A string representation of the HTTP method to be
+ used.
+ :param params: Additional keyworded arguments to be added to the
+ request querystring.
+ '''
+ auth_session = self._construct_session(
+ access_token=request_token,
+ access_token_secret=request_token_secret,
+ header_auth=self.header_auth)
+
+ response = auth_session.request(http_method,
+ self.access_token_url,
+ params=params)
+
+ return _parse_response(response)
+
+ def get_authenticated_session(self, access_token, access_token_secret,
+ header_auth=False):
+ '''Returns an authenticated Requests session utilizing the hook.
+
+ :param access_token: The access token as returned by
+ :class:`get_access_token`
+ :param access_token_secret: The access token secret as returned by
+ :class:`get_access_token`
+ :param header_auth: Authenication via header, defaults to False.
+ '''
+ return self._construct_session(access_token=access_token,
+ access_token_secret=access_token_secret,
+ header_auth=header_auth)
+
+ def request(self, http_method, url, access_token, access_token_secret,
+ header_auth=False, params=None, data=None):
+ '''Makes a request using :class:`_construct_session`.
+
+ :param http_method: A string representation of the HTTP method to be
+ used.
+ :param url: The resource to be requested.
+ :param access_token: The access token as returned by
+ :class:`get_access_token`.
+ :param access_token_secret: The access token secret as returned by
+ :class:`get_access_token`.
+ :param header_auth: Authenication via header, defaults to False.
+ :param params: Additional arguments to be added to the request
+ querystring.
+ :param data: Additional data to be included in the request body.
+ '''
+ auth_session = \
+ self._construct_session(access_token=access_token,
+ access_token_secret=access_token_secret,
+ header_auth=header_auth)
+
+ response = auth_session.request(http_method,
+ url,
+ params=params,
+ data=data,
+ allow_redirects=True)
+
+ return _parse_response(response)
Please sign in to comment.
Something went wrong with that request. Please try again.