99"""
1010
1111__author__ = "Ryan McGrath <[email protected] >" 12- __version__ = "2.0 .0"
12+ __version__ = "2.1 .0"
1313
1414import urllib
1515import re
16- import time
1716
1817import requests
1918from requests .auth import OAuth1
20- import oauth2 as oauth
2119
2220try :
2321 from urlparse import parse_qsl
@@ -109,8 +107,8 @@ def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_
109107
110108 :param app_key: (optional) Your applications key
111109 :param app_secret: (optional) Your applications secret key
112- :param oauth_token: (optional) Used with oauth_secret to make authenticated calls
113- :param oauth_secret : (optional) Used with oauth_token to make authenticated calls
110+ :param oauth_token: (optional) Used with oauth_token_secret to make authenticated calls
111+ :param oauth_token_secret : (optional) Used with oauth_token to make authenticated calls
114112 :param headers: (optional) Custom headers to send along with the request
115113 :param callback_url: (optional) If set, will overwrite the callback url set in your application
116114 """
@@ -135,9 +133,9 @@ def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_
135133 if oauth_token is not None :
136134 self .oauth_token = u'%s' % oauth_token
137135
138- self .oauth_secret = None
136+ self .oauth_token_secret = None
139137 if oauth_token_secret is not None :
140- self .oauth_secret = u'%s' % oauth_token_secret
138+ self .oauth_token_secret = u'%s' % oauth_token_secret
141139
142140 self .callback_url = callback_url
143141
@@ -152,9 +150,9 @@ def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_
152150 self .auth = OAuth1 (self .app_key , self .app_secret ,
153151 signature_type = 'auth_header' )
154152
155- if self .oauth_token is not None and self .oauth_secret is not None :
153+ if self .oauth_token is not None and self .oauth_token_secret is not None :
156154 self .auth = OAuth1 (self .app_key , self .app_secret ,
157- self .oauth_token , self .oauth_secret ,
155+ self .oauth_token , self .oauth_token_secret ,
158156 signature_type = 'auth_header' )
159157
160158 # Filter down through the possibilities here - if they have a token, if they're first stage, etc.
@@ -182,27 +180,29 @@ def _constructFunc(self, api_call, **kwargs):
182180 )
183181
184182 method = fn ['method' ].lower ()
185- if not method in ('get' , 'post' , 'delete' ):
186- raise TwythonError ('Method must be of GET, POST or DELETE ' )
183+ if not method in ('get' , 'post' ):
184+ raise TwythonError ('Method must be of GET or POST ' )
187185
188186 content = self ._request (url , method = method , params = kwargs )
189187
190188 return content
191189
192- def _request (self , url , method = 'GET' , params = None , api_call = None ):
190+ def _request (self , url , method = 'GET' , params = None , files = None , api_call = None ):
193191 '''Internal response generator, no sense in repeating the same
194192 code twice, right? ;)
195193 '''
196194 myargs = {}
197195 method = method .lower ()
198196
197+ params = params or {}
198+
199199 if method == 'get' :
200200 url = '%s?%s' % (url , urllib .urlencode (params ))
201201 else :
202202 myargs = params
203203
204204 func = getattr (self .client , method )
205- response = func (url , data = myargs , auth = self .auth )
205+ response = func (url , data = myargs , files = files , headers = self . headers , auth = self .auth )
206206 content = response .content .decode ('utf-8' )
207207
208208 # create stash for last function intel
@@ -247,31 +247,23 @@ def _request(self, url, method='GET', params=None, api_call=None):
247247 we haven't gotten around to putting it in Twython yet. :)
248248 '''
249249
250- def request (self , endpoint , method = 'GET' , params = None , version = 1 ):
251- params = params or {}
252-
250+ def request (self , endpoint , method = 'GET' , params = None , files = None , version = 1 ):
253251 # In case they want to pass a full Twitter URL
254- # i.e. http ://search.twitter.com/
252+ # i.e. https ://search.twitter.com/
255253 if endpoint .startswith ('http://' ) or endpoint .startswith ('https://' ):
256254 url = endpoint
257255 else :
258256 url = '%s/%s.json' % (self .api_url % version , endpoint )
259257
260- content = self ._request (url , method = method , params = params , api_call = url )
258+ content = self ._request (url , method = method , params = params , files = files , api_call = url )
261259
262260 return content
263261
264262 def get (self , endpoint , params = None , version = 1 ):
265- params = params or {}
266263 return self .request (endpoint , params = params , version = version )
267264
268- def post (self , endpoint , params = None , version = 1 ):
269- params = params or {}
270- return self .request (endpoint , 'POST' , params = params , version = version )
271-
272- def delete (self , endpoint , params = None , version = 1 ):
273- params = params or {}
274- return self .request (endpoint , 'DELETE' , params = params , version = version )
265+ def post (self , endpoint , params = None , files = None , version = 1 ):
266+ return self .request (endpoint , 'POST' , params = params , files = files , version = version )
275267
276268 # End Dynamic Request Methods
277269
@@ -297,16 +289,12 @@ def get_lastfunction_header(self, header):
297289 def get_authentication_tokens (self ):
298290 """Returns an authorization URL for a user to hit.
299291 """
300- callback_url = self .callback_url
301-
302292 request_args = {}
303- if callback_url :
304- request_args ['oauth_callback' ] = callback_url
305-
306- method = 'get'
293+ if self .callback_url :
294+ request_args ['oauth_callback' ] = self .callback_url
307295
308- func = getattr ( self .client , method )
309- response = func ( self .request_token_url , data = request_args , auth = self .auth )
296+ req_url = self .request_token_url + '?' + urllib . urlencode ( request_args )
297+ response = self .client . get ( req_url , headers = self . headers , auth = self .auth )
310298
311299 if response .status_code != 200 :
312300 raise TwythonAuthError ("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (response .status_code , response .content ))
@@ -322,8 +310,8 @@ def get_authentication_tokens(self):
322310 }
323311
324312 # Use old-style callback argument if server didn't accept new-style
325- if callback_url and not oauth_callback_confirmed :
326- auth_url_params ['oauth_callback' ] = callback_url
313+ if self . callback_url and not oauth_callback_confirmed :
314+ auth_url_params ['oauth_callback' ] = self . callback_url
327315
328316 request_tokens ['auth_url' ] = self .authenticate_url + '?' + urllib .urlencode (auth_url_params )
329317
@@ -332,7 +320,7 @@ def get_authentication_tokens(self):
332320 def get_authorized_tokens (self ):
333321 """Returns authorized tokens after they go through the auth_url phase.
334322 """
335- response = self .client .get (self .access_token_url , auth = self .auth )
323+ response = self .client .get (self .access_token_url , headers = self . headers , auth = self .auth )
336324 authorized_tokens = dict (parse_qsl (response .content ))
337325 if not authorized_tokens :
338326 raise TwythonError ('Unable to decode authorized tokens.' )
@@ -371,34 +359,6 @@ def shortenURL(url_to_shorten, shortener='http://is.gd/api.php'):
371359 def constructApiURL (base_url , params ):
372360 return base_url + "?" + "&" .join (["%s=%s" % (Twython .unicode2utf8 (key ), urllib .quote_plus (Twython .unicode2utf8 (value ))) for (key , value ) in params .iteritems ()])
373361
374- def bulkUserLookup (self , ids = None , screen_names = None , version = 1 , ** kwargs ):
375- """ A method to do bulk user lookups against the Twitter API.
376-
377- Documentation: https://dev.twitter.com/docs/api/1/get/users/lookup
378-
379- :ids or screen_names: (required)
380- :param ids: (optional) A list of integers of Twitter User IDs
381- :param screen_names: (optional) A list of strings of Twitter Screen Names
382-
383- :param include_entities: (optional) When set to either true, t or 1,
384- each tweet will include a node called
385- "entities,". This node offers a variety of
386- metadata about the tweet in a discreet structure
387-
388- e.g x.bulkUserLookup(screen_names=['ryanmcgrath', 'mikehelmick'],
389- include_entities=1)
390- """
391- if ids is None and screen_names is None :
392- raise TwythonError ('Please supply either a list of ids or \
393- screen_names for this method.' )
394-
395- if ids is not None :
396- kwargs ['user_id' ] = ',' .join (map (str , ids ))
397- if screen_names is not None :
398- kwargs ['screen_name' ] = ',' .join (screen_names )
399-
400- return self .get ('users/lookup' , params = kwargs , version = version )
401-
402362 def search (self , ** kwargs ):
403363 """ Returns tweets that match a specified query.
404364
@@ -512,44 +472,7 @@ def updateStatusWithMedia(self, file_, version=1, **params):
512472 ** params )
513473
514474 def _media_update (self , url , file_ , params = None ):
515- params = params or {}
516- oauth_params = {
517- 'oauth_timestamp' : int (time .time ()),
518- }
519-
520- #create a fake request with your upload url and parameters
521- faux_req = oauth .Request (method = 'POST' , url = url , parameters = oauth_params )
522-
523- #sign the fake request.
524- signature_method = oauth .SignatureMethod_HMAC_SHA1 ()
525-
526- class dotdict (dict ):
527- """
528- This is a helper func. because python-oauth2 wants a
529- dict in dot notation.
530- """
531-
532- def __getattr__ (self , attr ):
533- return self .get (attr , None )
534- __setattr__ = dict .__setitem__
535- __delattr__ = dict .__delitem__
536-
537- consumer = {
538- 'key' : self .app_key ,
539- 'secret' : self .app_secret
540- }
541- token = {
542- 'key' : self .oauth_token ,
543- 'secret' : self .oauth_secret
544- }
545-
546- faux_req .sign_request (signature_method , dotdict (consumer ), dotdict (token ))
547-
548- #create a dict out of the fake request signed params
549- self .headers .update (faux_req .to_header ())
550-
551- req = requests .post (url , data = params , files = file_ , headers = self .headers )
552- return req .content
475+ return self .post (url , params = params , files = file_ )
553476
554477 def getProfileImageUrl (self , username , size = 'normal' , version = 1 ):
555478 """Gets the URL for the user's profile image.
@@ -624,7 +547,10 @@ def stream(data, callback):
624547
625548 for line in stream .iter_lines ():
626549 if line :
627- callback (simplejson .loads (line ))
550+ try :
551+ callback (simplejson .loads (line ))
552+ except ValueError :
553+ raise TwythonError ('Response was not valid JSON, unable to decode.' )
628554
629555 @staticmethod
630556 def unicode2utf8 (text ):
0 commit comments