OAuth 2 support :)
[ci skip]
This commit is contained in:
parent
06922b7ca6
commit
8559a1f1ce
2 changed files with 67 additions and 20 deletions
|
|
@ -16,6 +16,7 @@ History
|
||||||
- Removed ``get_list_memberships``, method is Twitter API 1.0 deprecated
|
- Removed ``get_list_memberships``, method is Twitter API 1.0 deprecated
|
||||||
- Developers can now pass an array as a parameter to Twitter API methods and they will be automatically joined by a comma and converted to a string
|
- Developers can now pass an array as a parameter to Twitter API methods and they will be automatically joined by a comma and converted to a string
|
||||||
- ``endpoints.py`` now contains ``EndpointsMixin`` (rather than the previous ``api_table`` dict) for Twython, which enables Twython to use functions declared in the Mixin.
|
- ``endpoints.py`` now contains ``EndpointsMixin`` (rather than the previous ``api_table`` dict) for Twython, which enables Twython to use functions declared in the Mixin.
|
||||||
|
- Added OAuth 2 authentication (Application Only) for when you want to make read-only calls to Twitter without having to go through the whole user authentication ritual (see docs for usage)
|
||||||
|
|
||||||
2.10.1 (2013-05-29)
|
2.10.1 (2013-05-29)
|
||||||
++++++++++++++++++
|
++++++++++++++++++
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ dealing with the Twitter API
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from requests_oauthlib import OAuth1
|
from requests.auth import HTTPBasicAuth
|
||||||
|
from requests_oauthlib import OAuth1, OAuth2
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .compat import json, urlencode, parse_qsl, quote_plus, str, is_py2
|
from .compat import json, urlencode, parse_qsl, quote_plus, str, is_py2
|
||||||
|
|
@ -21,14 +22,19 @@ from .helpers import _transparent_params
|
||||||
|
|
||||||
class Twython(EndpointsMixin, object):
|
class Twython(EndpointsMixin, object):
|
||||||
def __init__(self, app_key=None, app_secret=None, oauth_token=None,
|
def __init__(self, app_key=None, app_secret=None, oauth_token=None,
|
||||||
oauth_token_secret=None, headers=None, proxies=None,
|
oauth_token_secret=None, access_token=None, token_type='bearer',
|
||||||
api_version='1.1', ssl_verify=True):
|
oauth_version=1, headers=None, proxies=None, api_version='1.1',
|
||||||
|
ssl_verify=True):
|
||||||
"""Instantiates an instance of Twython. Takes optional parameters for authentication and such (see below).
|
"""Instantiates an instance of Twython. Takes optional parameters for authentication and such (see below).
|
||||||
|
|
||||||
:param app_key: (optional) Your applications key
|
:param app_key: (optional) Your applications key
|
||||||
:param app_secret: (optional) Your applications secret key
|
:param app_secret: (optional) Your applications secret key
|
||||||
:param oauth_token: (optional) Used with oauth_token_secret to make authenticated calls
|
:param oauth_token: (optional) When using **OAuth 1**, combined with oauth_token_secret to make authenticated calls
|
||||||
:param oauth_token_secret: (optional) Used with oauth_token to make authenticated calls
|
:param oauth_token_secret: (optional) When using **OAuth 1** combined with oauth_token to make authenticated calls
|
||||||
|
:param access_token: (optional) When using **OAuth 2**, provide a valid access token if you have one
|
||||||
|
:param token_type: (optional) When using **OAuth 2**, provide your token type. Default: bearer
|
||||||
|
:param oauth_version: (optional) Choose which OAuth version to use. Default: 1
|
||||||
|
|
||||||
:param headers: (optional) Custom headers to send along with the request
|
:param headers: (optional) Custom headers to send along with the request
|
||||||
:param proxies: (optional) A dictionary of proxies, for example {"http":"proxy.example.org:8080", "https":"proxy.example.org:8081"}.
|
:param proxies: (optional) A dictionary of proxies, for example {"http":"proxy.example.org:8080", "https":"proxy.example.org:8081"}.
|
||||||
:param ssl_verify: (optional) Turns off ssl verification when False. Useful if you have development server issues.
|
:param ssl_verify: (optional) Turns off ssl verification when False. Useful if you have development server issues.
|
||||||
|
|
@ -38,14 +44,24 @@ class Twython(EndpointsMixin, object):
|
||||||
# API urls, OAuth urls and API version; needed for hitting that there API.
|
# API urls, OAuth urls and API version; needed for hitting that there API.
|
||||||
self.api_version = api_version
|
self.api_version = api_version
|
||||||
self.api_url = 'https://api.twitter.com/%s'
|
self.api_url = 'https://api.twitter.com/%s'
|
||||||
self.request_token_url = self.api_url % 'oauth/request_token'
|
|
||||||
self.access_token_url = self.api_url % 'oauth/access_token'
|
|
||||||
self.authenticate_url = self.api_url % 'oauth/authenticate'
|
|
||||||
|
|
||||||
self.app_key = app_key
|
self.app_key = app_key
|
||||||
self.app_secret = app_secret
|
self.app_secret = app_secret
|
||||||
self.oauth_token = oauth_token
|
self.oauth_token = oauth_token
|
||||||
self.oauth_token_secret = oauth_token_secret
|
self.oauth_token_secret = oauth_token_secret
|
||||||
|
self.access_token = access_token
|
||||||
|
|
||||||
|
# OAuth 1
|
||||||
|
self.request_token_url = self.api_url % 'oauth/request_token'
|
||||||
|
self.access_token_url = self.api_url % 'oauth/access_token'
|
||||||
|
self.authenticate_url = self.api_url % 'oauth/authenticate'
|
||||||
|
|
||||||
|
if self.access_token: # If they pass an access token, force OAuth 2
|
||||||
|
oauth_version = 2
|
||||||
|
|
||||||
|
# OAuth 2
|
||||||
|
if oauth_version == 2:
|
||||||
|
self.request_token_url = self.api_url % 'oauth2/token'
|
||||||
|
|
||||||
req_headers = {'User-Agent': 'Twython v' + __version__}
|
req_headers = {'User-Agent': 'Twython v' + __version__}
|
||||||
if headers:
|
if headers:
|
||||||
|
|
@ -55,14 +71,20 @@ class Twython(EndpointsMixin, object):
|
||||||
# If no keys/tokens are passed to __init__, auth=None allows for
|
# If no keys/tokens are passed to __init__, auth=None allows for
|
||||||
# unauthenticated requests, although I think all v1.1 requests need auth
|
# unauthenticated requests, although I think all v1.1 requests need auth
|
||||||
auth = None
|
auth = None
|
||||||
if self.app_key is not None and self.app_secret is not None and \
|
if oauth_version == 1:
|
||||||
self.oauth_token is None and self.oauth_token_secret is None:
|
# User Authentication is through OAuth 1
|
||||||
auth = OAuth1(self.app_key, self.app_secret)
|
if self.app_key is not None and self.app_secret is not None and \
|
||||||
|
self.oauth_token is None and self.oauth_token_secret is None:
|
||||||
|
auth = OAuth1(self.app_key, self.app_secret)
|
||||||
|
|
||||||
if self.app_key is not None and self.app_secret is not None and \
|
if self.app_key is not None and self.app_secret is not None and \
|
||||||
self.oauth_token is not None and self.oauth_token_secret is not None:
|
self.oauth_token is not None and self.oauth_token_secret is not None:
|
||||||
auth = OAuth1(self.app_key, self.app_secret,
|
auth = OAuth1(self.app_key, self.app_secret,
|
||||||
self.oauth_token, self.oauth_token_secret)
|
self.oauth_token, self.oauth_token_secret)
|
||||||
|
elif oauth_version == 2 and self.access_token:
|
||||||
|
# Application Authentication is through OAuth 2
|
||||||
|
token = {'token_type': token_type, 'access_token': self.access_token}
|
||||||
|
auth = OAuth2(self.app_key, token=token)
|
||||||
|
|
||||||
self.client = requests.Session()
|
self.client = requests.Session()
|
||||||
self.client.headers = req_headers
|
self.client.headers = req_headers
|
||||||
|
|
@ -205,6 +227,9 @@ class Twython(EndpointsMixin, object):
|
||||||
:param app_secret: (optional) If forced_login is set OR user is not currently logged in, Prefills the username input box of the OAuth login screen with the given value
|
:param app_secret: (optional) If forced_login is set OR user is not currently logged in, Prefills the username input box of the OAuth login screen with the given value
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
|
if self.oauth_version != 1:
|
||||||
|
raise TwythonError('This method can only be called when your OAuth version is 1.0.')
|
||||||
|
|
||||||
callback_url = callback_url or self.callback_url
|
callback_url = callback_url or self.callback_url
|
||||||
request_args = {}
|
request_args = {}
|
||||||
if callback_url:
|
if callback_url:
|
||||||
|
|
@ -247,6 +272,9 @@ class Twython(EndpointsMixin, object):
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if self.oauth_version != 1:
|
||||||
|
raise TwythonError('This method can only be called when your OAuth version is 1.0.')
|
||||||
|
|
||||||
response = self.client.get(self.access_token_url, params={'oauth_verifier': oauth_verifier})
|
response = self.client.get(self.access_token_url, params={'oauth_verifier': oauth_verifier})
|
||||||
authorized_tokens = dict(parse_qsl(response.content.decode('utf-8')))
|
authorized_tokens = dict(parse_qsl(response.content.decode('utf-8')))
|
||||||
if not authorized_tokens:
|
if not authorized_tokens:
|
||||||
|
|
@ -254,11 +282,29 @@ class Twython(EndpointsMixin, object):
|
||||||
|
|
||||||
return authorized_tokens
|
return authorized_tokens
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
def obtain_access_token(self):
|
||||||
# The following methods are all different in some manner or require special attention with regards to the Twitter API.
|
"""Returns an OAuth 2 access token to make OAuth 2 authenticated read-only calls.
|
||||||
# Because of this, we keep them separate from all the other endpoint definitions - ideally this should be change-able,
|
|
||||||
# but it's not high on the priority list at the moment.
|
:rtype: string
|
||||||
# ------------------------------------------------------------------------------------------------------------------------
|
"""
|
||||||
|
if self.oauth_version != 2:
|
||||||
|
raise TwythonError('This method can only be called when your OAuth version is 2.0.')
|
||||||
|
|
||||||
|
data = {'grant_type': 'client_credentials'}
|
||||||
|
basic_auth = HTTPBasicAuth(self.app_key, self.app_secret)
|
||||||
|
try:
|
||||||
|
response = self.client.post(self.request_token_url,
|
||||||
|
data=data, auth=basic_auth)
|
||||||
|
content = response.content.decode('utf-8')
|
||||||
|
try:
|
||||||
|
content = content.json()
|
||||||
|
except AttributeError:
|
||||||
|
content = json.loads(content)
|
||||||
|
access_token = content['access_token']
|
||||||
|
except (ValueError, requests.exceptions.RequestException):
|
||||||
|
raise TwythonAuthError('Unable to obtain OAuth 2 access token.')
|
||||||
|
else:
|
||||||
|
return access_token
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct_api_url(api_url, **params):
|
def construct_api_url(api_url, **params):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue