Commit 1bdff779 authored by Aaron1011's avatar Aaron1011
Browse files

Merge pull request #486 from muraty/PEP8fix

Pep8fix
parents 79e00a53 91d5b7ae
......@@ -9,19 +9,13 @@ __version__ = '2.3'
__author__ = 'Joshua Roesslein'
__license__ = 'MIT'
from tweepy.models import Status, User, DirectMessage, Friendship, SavedSearch, SearchResults, ModelFactory, Category
from tweepy.error import TweepError
from tweepy.api import API
from tweepy.cache import Cache, MemoryCache, FileCache
from tweepy.auth import OAuthHandler, AppAuthHandler
from tweepy.streaming import Stream, StreamListener
from tweepy.cursor import Cursor
# Global, unauthenticated instance of API
api = API()
def debug(enable=True, level=1):
import httplib
httplib.HTTPConnection.debuglevel = level
......@@ -4,7 +4,6 @@
import os
import mimetypes
import urllib
from tweepy.binder import bind_api
from tweepy.error import TweepError
......@@ -65,9 +64,9 @@ class API(object):
parser_type = Parser
if not isinstance(self.parser, parser_type):
raise TypeError(
'"parser" argument has to be an instance of "{}". It is currently a {}.'.format(
parser_type.__name__, type(self.parser)
)
'"parser" argument has to be an instance of "{}".'
' It is currently a {}.'.format(parser_type.__name__,
type(self.parser))
)
@property
......@@ -83,7 +82,8 @@ class API(object):
require_auth=True
)
def statuses_lookup(self, id_, include_entities=None, trim_user=None, map_=None):
def statuses_lookup(self, id_, include_entities=None,
trim_user=None, map_=None):
return self._statuses_lookup(list_to_csv(id_), include_entities,
trim_user, map_)
......@@ -164,7 +164,6 @@ class API(object):
allowed_param=['id']
)
@property
def update_status(self):
""" :reference: https://dev.twitter.com/rest/reference/post/statuses/update
......@@ -592,8 +591,10 @@ class API(object):
@property
def update_profile_colors(self):
""" :reference: https://dev.twitter.com/rest/reference/post/account/update_profile_colors
:allowed_param:'profile_background_color', 'profile_text_color', 'profile_link_color', 'profile_sidebar_fill_color', 'profile_sidebar_border_color'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/account/update_profile_colors
:allowed_param:'profile_background_color', 'profile_text_color',
'profile_link_color', 'profile_sidebar_fill_color',
'profile_sidebar_border_color'],
"""
return bind_api(
api=self,
......@@ -902,14 +903,17 @@ class API(object):
@property
def list_timeline(self):
""" :reference: https://dev.twitter.com/rest/reference/get/lists/statuses
:allowed_param:'owner_screen_name', 'slug', 'owner_id', 'list_id', 'since_id', 'max_id', 'count', 'include_rts'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/lists/statuses
:allowed_param:'owner_screen_name', 'slug', 'owner_id', 'list_id',
'since_id', 'max_id', 'count', 'include_rts
"""
return bind_api(
api=self,
path='/lists/statuses.json',
payload_type='status', payload_list=True,
allowed_param=['owner_screen_name', 'slug', 'owner_id', 'list_id', 'since_id', 'max_id', 'count', 'include_rts']
allowed_param=['owner_screen_name', 'slug', 'owner_id',
'list_id', 'since_id', 'max_id', 'count',
'include_rts']
)
@property
......@@ -926,29 +930,33 @@ class API(object):
@property
def add_list_member(self):
""" :reference: https://dev.twitter.com/rest/reference/post/lists/members/create
:allowed_param:'screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/create
:allowed_param:'screen_name', 'user_id', 'owner_screen_name',
'owner_id', 'slug', 'list_id'
"""
return bind_api(
api=self,
path='/lists/members/create.json',
method='POST',
payload_type='list',
allowed_param=['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
allowed_param=['screen_name', 'user_id', 'owner_screen_name',
'owner_id', 'slug', 'list_id'],
require_auth=True
)
@property
def remove_list_member(self):
""" :reference: https://dev.twitter.com/rest/reference/post/lists/members/destroy
:allowed_param:'screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/destroy
:allowed_param:'screen_name', 'user_id', 'owner_screen_name',
'owner_id', 'slug', 'list_id'
"""
return bind_api(
api=self,
path='/lists/members/destroy.json',
method='POST',
payload_type='list',
allowed_param=['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
allowed_param=['screen_name', 'user_id', 'owner_screen_name',
'owner_id', 'slug', 'list_id'],
require_auth=True
)
......@@ -962,19 +970,21 @@ class API(object):
@property
def _add_list_members(self):
""" :reference: https://dev.twitter.com/rest/reference/post/lists/members/create_all
:allowed_param:'screen_name', 'user_id', 'slug', 'lit_id', 'owner_id', 'owner_screen_name'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/create_all
:allowed_param:'screen_name', 'user_id', 'slug', 'lit_id',
'owner_id', 'owner_screen_name'
"""
return bind_api(
api=self,
path='/lists/members/create_all.json',
method='POST',
payload_type='list',
allowed_param=['screen_name', 'user_id', 'slug', 'lit_id', 'owner_id', 'owner_screen_name'],
allowed_param=['screen_name', 'user_id', 'slug', 'lit_id',
'owner_id', 'owner_screen_name'],
require_auth=True
)
def remove_list_members(self, screen_name=None, user_id=None, slug=None,
list_id=None, owner_id=None, owner_screen_name=None):
""" Perform bulk remove of list members from user ID or screenname """
......@@ -985,92 +995,107 @@ class API(object):
@property
def _remove_list_members(self):
""" :reference: https://dev.twitter.com/rest/reference/post/lists/members/destroy_all
:allowed_param:'screen_name', 'user_id', 'slug', 'lit_id', 'owner_id', 'owner_screen_name'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/destroy_all
:allowed_param:'screen_name', 'user_id', 'slug', 'lit_id',
'owner_id', 'owner_screen_name'
"""
return bind_api(
api=self,
path='/lists/members/destroy_all.json',
method='POST',
payload_type='list',
allowed_param=['screen_name', 'user_id', 'slug', 'lit_id', 'owner_id', 'owner_screen_name'],
allowed_param=['screen_name', 'user_id', 'slug', 'lit_id',
'owner_id', 'owner_screen_name'],
require_auth=True
)
@property
def list_members(self):
""" :reference: https://dev.twitter.com/rest/reference/get/lists/members
:allowed_param:'owner_screen_name', 'slug', 'list_id', 'owner_id', 'cursor'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/lists/members
:allowed_param:'owner_screen_name', 'slug', 'list_id',
'owner_id', 'cursor
"""
return bind_api(
api=self,
path='/lists/members.json',
payload_type='user', payload_list=True,
allowed_param=['owner_screen_name', 'slug', 'list_id', 'owner_id', 'cursor']
allowed_param=['owner_screen_name', 'slug', 'list_id',
'owner_id', 'cursor']
)
@property
def show_list_member(self):
""" :reference: https://dev.twitter.com/rest/reference/get/lists/members/show
:allowed_param:'list_id', 'slug', 'user_id', 'screen_name', 'owner_screen_name', 'owner_id'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/lists/members/show
:allowed_param:'list_id', 'slug', 'user_id', 'screen_name',
'owner_screen_name', 'owner_id
"""
return bind_api(
api=self,
path='/lists/members/show.json',
payload_type='user',
allowed_param=['list_id', 'slug', 'user_id', 'screen_name', 'owner_screen_name', 'owner_id']
allowed_param=['list_id', 'slug', 'user_id', 'screen_name',
'owner_screen_name', 'owner_id']
)
@property
def subscribe_list(self):
""" :reference: https://dev.twitter.com/rest/reference/post/lists/subscribers/create
:allowed_param:'owner_screen_name', 'slug', 'owner_id', 'list_id'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/lists/subscribers/create
:allowed_param:'owner_screen_name', 'slug', 'owner_id',
'list_id'
"""
return bind_api(
api=self,
path='/lists/subscribers/create.json',
method='POST',
payload_type='list',
allowed_param=['owner_screen_name', 'slug', 'owner_id', 'list_id'],
allowed_param=['owner_screen_name', 'slug', 'owner_id',
'list_id'],
require_auth=True
)
@property
def unsubscribe_list(self):
""" :reference: https://dev.twitter.com/rest/reference/post/lists/subscribers/destroy
:allowed_param:'owner_screen_name', 'slug', 'owner_id', 'list_id'
""" :reference: https://dev.twitter.com/docs/api/1.1/post/lists/subscribers/destroy
:allowed_param:'owner_screen_name', 'slug', 'owner_id',
'list_id'
"""
return bind_api(
api=self,
path='/lists/subscribers/destroy.json',
method='POST',
payload_type='list',
allowed_param=['owner_screen_name', 'slug', 'owner_id', 'list_id'],
allowed_param=['owner_screen_name', 'slug', 'owner_id',
'list_id'],
require_auth=True
)
@property
def list_subscribers(self):
""" :reference: https://dev.twitter.com/rest/reference/get/lists/subscribers
:allowed_param:'owner_screen_name', 'slug', 'owner_id', 'list_id', 'cursor'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/lists/subscribers
:allowed_param:'owner_screen_name', 'slug', 'owner_id',
'list_id', 'cursor
"""
return bind_api(
api=self,
path='/lists/subscribers.json',
payload_type='user', payload_list=True,
allowed_param=['owner_screen_name', 'slug', 'owner_id', 'list_id', 'cursor']
allowed_param=['owner_screen_name', 'slug', 'owner_id',
'list_id', 'cursor']
)
@property
def show_list_subscriber(self):
""" :reference: https://dev.twitter.com/rest/reference/get/lists/subscribers/show
:allowed_param:'owner_screen_name', 'slug', 'screen_name', 'owner_id', 'list_id', 'user_id'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/lists/subscribers/show
:allowed_param:'owner_screen_name', 'slug', 'screen_name',
'owner_id', 'list_id', 'user_id
"""
return bind_api(
api=self,
path='/lists/subscribers/show.json',
payload_type='user',
allowed_param=['owner_screen_name', 'slug', 'screen_name', 'owner_id', 'list_id', 'user_id']
allowed_param=['owner_screen_name', 'slug', 'screen_name',
'owner_id', 'list_id', 'user_id']
)
@property
......@@ -1108,15 +1133,19 @@ class API(object):
@property
def search(self):
""" :reference: https://dev.twitter.com/rest/reference/get/search/tweets
:allowed_param:'q', 'lang', 'locale', 'since_id', 'geocode', 'max_id', 'since', 'until', 'result_type', 'count', 'include_entities', 'from', 'to', 'source'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/search
:allowed_param:'q', 'lang', 'locale', 'since_id', 'geocode',
'max_id', 'since', 'until', 'result_type', 'count',
'include_entities', 'from', 'to', 'source']
"""
return bind_api(
api=self,
path='/search/tweets.json',
payload_type='search_results',
allowed_param=['q', 'lang', 'locale', 'since_id', 'geocode', 'max_id', 'since', 'until', 'result_type',
'count', 'include_entities', 'from', 'to', 'source']
allowed_param=['q', 'lang', 'locale', 'since_id', 'geocode',
'max_id', 'since', 'until', 'result_type',
'count', 'include_entities', 'from',
'to', 'source']
)
@property
......@@ -1152,7 +1181,8 @@ class API(object):
api=self,
path='/geo/reverse_geocode.json',
payload_type='place', payload_list=True,
allowed_param=['lat', 'long', 'accuracy', 'granularity', 'max_results']
allowed_param=['lat', 'long', 'accuracy', 'granularity',
'max_results']
)
@property
......@@ -1169,14 +1199,17 @@ class API(object):
@property
def geo_search(self):
""" :reference: https://dev.twitter.com/rest/reference/get/geo/search
:allowed_param:'lat', 'long', 'query', 'ip', 'granularity', 'accuracy', 'max_results', 'contained_within'
""" :reference: https://dev.twitter.com/docs/api/1.1/get/geo/search
:allowed_param:'lat', 'long', 'query', 'ip', 'granularity',
'accuracy', 'max_results', 'contained_within
"""
return bind_api(
api=self,
path='/geo/search.json',
payload_type='place', payload_list=True,
allowed_param=['lat', 'long', 'query', 'ip', 'granularity', 'accuracy', 'max_results', 'contained_within']
allowed_param=['lat', 'long', 'query', 'ip', 'granularity',
'accuracy', 'max_results', 'contained_within']
)
@property
......@@ -1245,14 +1278,14 @@ class API(object):
filename = filename.encode("utf-8")
filename = filename.encode("utf-8")
BOUNDARY = 'Tw3ePy'
body = []
body.append('--' + BOUNDARY)
boundary = 'Tw3ePy'
body = list()
body.append('--' + boundary)
body.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (form_field, filename))
body.append('Content-Type: %s' % file_type)
body.append('')
body.append(fp.read())
body.append('--' + BOUNDARY + '--')
body.append('--' + boundary + '--')
body.append('')
fp.close()
body = '\r\n'.join(body)
......
from urllib2 import Request, urlopen
import urllib
import base64
import json
import logging
from tweepy.error import TweepError
......@@ -11,6 +7,11 @@ from requests_oauthlib import OAuth1Session, OAuth1
from requests.auth import AuthBase
from urlparse import parse_qs
WARNING_MESSAGE = """Warning! Due to a Twitter API bug, signin_with_twitter
and access_type don't always play nice together. Details
https://dev.twitter.com/discussions/21281"""
class AuthHandler(object):
def apply_auth(self, url, method, headers, parameters):
......@@ -40,15 +41,20 @@ class OAuthHandler(AuthHandler):
self.access_token_secret = None
self.callback = callback
self.username = None
self.oauth = OAuth1Session(consumer_key, client_secret=consumer_secret, callback_uri=self.callback)
self.oauth = OAuth1Session(consumer_key,
client_secret=consumer_secret,
callback_uri=self.callback)
def _get_oauth_url(self, endpoint):
return 'https://' + self.OAUTH_HOST + self.OAUTH_ROOT + endpoint
def apply_auth(self):
return OAuth1(self.consumer_key, client_secret=self.consumer_secret, resource_owner_key=self.access_token, resource_owner_secret=self.access_token_secret)
return OAuth1(self.consumer_key,
client_secret=self.consumer_secret,
resource_owner_key=self.access_token,
resource_owner_secret=self.access_token_secret)
def _get_request_token(self, access_type = None):
def _get_request_token(self, access_type=None):
try:
url = self._get_oauth_url('request_token')
if access_type:
......@@ -61,16 +67,15 @@ class OAuthHandler(AuthHandler):
self.access_token = key
self.access_token_secret = secret
def get_authorization_url(self, signin_with_twitter = False, access_type = None):
def get_authorization_url(self,
signin_with_twitter=False,
access_type=None):
"""Get the authorization URL to redirect the user"""
try:
if signin_with_twitter:
url = self._get_oauth_url('authenticate')
if access_type:
logging.warning(
"Warning! Due to a Twitter API bug, signin_with_twitter "
"and access_type don't always play nice together. Details: "
"https://dev.twitter.com/discussions/21281")
logging.warning(WARNING_MESSAGE)
else:
url = self._get_oauth_url('authorize')
self.request_token = self._get_request_token(access_type=access_type)
......@@ -78,18 +83,22 @@ class OAuthHandler(AuthHandler):
except Exception as e:
raise TweepError(e)
def get_access_token(self, verifier = None):
def get_access_token(self, verifier=None):
"""
After user has authorized the request token, get access token
with user supplied verifier.
"""
try:
url = self._get_oauth_url('access_token')
self.oauth = OAuth1Session(self.consumer_key, client_secret=self.consumer_secret, resource_owner_key=self.request_token['oauth_token'], resource_owner_secret=self.request_token['oauth_token_secret'], verifier=verifier, callback_uri=self.callback)
self.oauth = OAuth1Session(self.consumer_key,
client_secret=self.consumer_secret,
resource_owner_key=self.request_token['oauth_token'],
resource_owner_secret=self.request_token['oauth_token_secret'],
verifier=verifier, callback_uri=self.callback)
resp = self.oauth.fetch_access_token(url)
self.access_token = resp['oauth_token']
self.access_token_secret = resp['oauth_token_secret']
return (self.access_token, self.access_token_secret)
return self.access_token, self.access_token_secret
except Exception as e:
raise TweepError(e)
......@@ -102,14 +111,17 @@ class OAuthHandler(AuthHandler):
"""
try:
url = self._get_oauth_url('access_token')
oauth = OAuth1(self.consumer_key, client_secret=self.consumer_secret)
r = requests.post(url=url, auth=oauth, headers={'x_auth_mode':
'client_auth', 'x_auth_username': username, 'x_auth_password':
password})
oauth = OAuth1(self.consumer_key,
client_secret=self.consumer_secret)
r = requests.post(url=url,
auth=oauth,
headers={'x_auth_mode': 'client_auth',
'x_auth_username': username,
'x_auth_password': password})
print r.content
credentials = parse_qs(r.content)
return (credentials.get('oauth_token')[0], credentials.get('oauth_token_secret')[0])
return credentials.get('oauth_token')[0], credentials.get('oauth_token_secret')[0]
except Exception as e:
raise TweepError(e)
......@@ -120,17 +132,19 @@ class OAuthHandler(AuthHandler):
if user:
self.username = user.screen_name
else:
raise TweepError('Unable to get username, invalid oauth token!')
raise TweepError('Unable to get username,'
' invalid oauth token!')
return self.username
class OAuth2Bearer(AuthBase):
def __init__(self, bearer_token):
self.bearer_token = bearer_token
def __call__(self, request):
request.headers['Authorization'] = 'Bearer ' + self.bearer_token
return request
class AppAuthHandler(AuthHandler):
"""Application-only authentication handler"""
......@@ -143,20 +157,19 @@ class AppAuthHandler(AuthHandler):
self.consumer_secret = consumer_secret
self._bearer_token = ''
resp = requests.post(self._get_oauth_url('token'), auth=(self.consumer_key, self.consumer_secret),
data={'grant_type': 'client_credentials'})
resp = requests.post(self._get_oauth_url('token'),
auth=(self.consumer_key,
self.consumer_secret),
data={'grant_type': 'client_credentials'})
data = resp.json()
if data.get('token_type') != 'bearer':
raise TweepError('Expected token_type to equal "bearer", but got %s \
instead' % data.get('token_type'))
raise TweepError('Expected token_type to equal "bearer", '
'but got %s instead' % data.get('token_type'))
self._bearer_token = data['access_token']
def _get_oauth_url(self, endpoint):
return 'https://' + self.OAUTH_HOST + self.OAUTH_ROOT + endpoint
def apply_auth(self):
return OAuth2Bearer(self._bearer_token)
......@@ -39,11 +39,16 @@ def bind_api(**config):
raise TweepError('Authentication required!')
self.post_data = kwargs.pop('post_data', None)
self.retry_count = kwargs.pop('retry_count', api.retry_count)
self.retry_delay = kwargs.pop('retry_delay', api.retry_delay)
self.retry_errors = kwargs.pop('retry_errors', api.retry_errors)
self.wait_on_rate_limit = kwargs.pop('wait_on_rate_limit', api.wait_on_rate_limit)
self.wait_on_rate_limit_notify = kwargs.pop('wait_on_rate_limit_notify', api.wait_on_rate_limit_notify)
self.retry_count = kwargs.pop('retry_count',
api.retry_count)
self.retry_delay = kwargs.pop('retry_delay',
api.retry_delay)
self.retry_errors = kwargs.pop('retry_errors',
api.retry_errors)
self.wait_on_rate_limit = kwargs.pop('wait_on_rate_limit',
api.wait_on_rate_limit)
self.wait_on_rate_limit_notify = kwargs.pop('wait_on_rate_limit_notify',
api.wait_on_rate_limit_notify)
self.parser = kwargs.pop('parser', api.parser)
self.session.headers = kwargs.pop('headers', {})
self.build_parameters(args, kwargs)
......@@ -135,13 +140,15 @@ def bind_api(**config):
retries_performed = 0
while retries_performed < self.retry_count + 1:
# handle running out of api calls
if self.wait_on_rate_limit and self._reset_time is not None and \
self._remaining_calls is not None and self._remaining_calls < 1:
sleep_time = self._reset_time - int(time.time())
if sleep_time > 0:
if self.wait_on_rate_limit_notify:
print "Rate limit reached. Sleeping for: " + str(sleep_time)
time.sleep(sleep_time + 5) # sleep for few extra sec
if self.wait_on_rate_limit:
if self._reset_time is not None:
if self._remaining_calls is not None:
if self._remaining_calls < 1:
sleep_time = self._reset_time - int(time.time())
if sleep_time > 0:
if self.wait_on_rate_limit_notify:
print "Rate limit reached. Sleeping for: " + str(sleep_time)
time.sleep(sleep_time + 5) # sleep for few extra sec
# Apply authentication
if self.api.auth:
......@@ -153,9 +160,12 @@ def bind_api(**config):
# Execute request
try:
resp = self.session.request(self.method, full_url,
data=self.post_data, timeout=self.api.timeout,
auth=auth, proxies=self.api.proxy)
resp = self.session.request(self.method,
full_url,
data=self.post_data,
timeout=self.api.timeout,
auth=auth,
proxies=self.api.proxy)
except Exception, e:
raise TweepError('Failed to send request: %s' % e)
rem_calls = resp.headers.get('x-rate-limit-remaining')
......@@ -167,7 +177,8 @@ def bind_api(**config):
if reset_time is not None:
self._reset_time = int(reset_time)
if self.wait_on_rate_limit and self._remaining_calls == 0 and (
resp.status == 429 or resp.status == 420): # if ran out of calls before waiting switching retry last call
# if ran out of calls before waiting switching retry last call
resp.status == 429 or resp.status == 420):
continue
retry_delay = self.retry_delay
# Exit request loop if non-retry error code
......@@ -211,9 +222,9 @@ def bind_api(**config):
# Set pagination mode
if 'cursor' in APIMethod.allowed_param:
_call.pagination_mode = 'cursor'
elif 'max_id' in APIMethod.allowed_param and \
'since_id' in APIMethod.allowed_param:
_call.pagination_mode = 'id'
elif 'max_id' in APIMethod.allowed_param:
if 'since_id' in APIMethod.allowed_param:
_call.pagination_mode = 'id'
elif 'page' in APIMethod.allowed_param:
_call.pagination_mode = 'page'
......
......@@ -236,10 +236,11 @@ class FileCache(Cache):
# check if value is expired
if timeout is None:
timeout = self.timeout
if timeout > 0 and (time.time() - created_time) >= timeout:
# expired! delete from cache
value = None
self._delete_file(path)
if timeout > 0:
if (time.time() - created_time) >= timeout:
# expired! delete from cache
value = None
self._delete_file(path)
# unlock and return result
self._unlock_file(f_lock)
......@@ -267,6 +268,7 @@ class FileCache(Cache):
continue
self._delete_file(os.path.join(self.cache_dir, entry))
class MemCacheCache(Cache):
"""Cache interface"""
......@@ -288,7 +290,8 @@ class MemCacheCache(Cache):