From 2155ae0c2344a70d06c8082ff6aef8fd4082d439 Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Mon, 25 Jun 2012 11:50:44 -0400 Subject: [PATCH 1/5] Fix error in README.md, strip some not-needed comments and fixed a ternary --- README.md | 2 +- twython/twython.py | 43 +++++++++++++------------------------------ 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d19f34f..8bfe7b5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Features - Twitter lists - Timelines - User avatar URL - - and anything found in `the docs `_ + - and anything found in [the docs](https://dev.twitter.com/docs/api) * Image Uploading! - **Update user status with an image** - Change user avatar diff --git a/twython/twython.py b/twython/twython.py index e5d268c..0d6bb01 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -27,12 +27,7 @@ except ImportError: # table is a file with a dictionary of every API endpoint that Twython supports. from twitter_endpoints import base_url, api_table, twitter_http_status_codes - -# There are some special setups (like, oh, a Django application) where -# simplejson exists behind the scenes anyway. Past Python 2.6, this should -# never really cause any problems to begin with. try: - # If they have the library, chances are they're gonna want to use that. import simplejson except ImportError: try: @@ -40,7 +35,6 @@ except ImportError: import json as simplejson except ImportError: try: - # This case gets rarer by the day, but if we need to, we can pull it from Django provided it's there. from django.utils import simplejson except: # Seriously wtf is wrong with you if you get this Exception. @@ -110,21 +104,11 @@ class Twython(object): self.authenticate_url = self.api_url % 'oauth/authenticate' # Enforce unicode on keys and secrets - self.app_key = None - if app_key is not None or twitter_token is not None: - self.app_key = u'%s' % (app_key or twitter_token) + self.app_key = app_key and unicode(app_key) or twitter_token and unicode(twitter_token) + self.app_secret = app_key and unicode(app_secret) or twitter_secret and unicode(twitter_secret) - self.app_secret = None - if app_secret is not None or twitter_secret is not None: - self.app_secret = u'%s' % (app_secret or twitter_secret) - - self.oauth_token = None - if oauth_token is not None: - self.oauth_token = u'%s' % oauth_token - - self.oauth_token_secret = None - if oauth_token_secret is not None: - self.oauth_token_secret = u'%s' % oauth_token_secret + self.oauth_token = oauth_token and u'%s' % oauth_token + self.oauth_token_secret = oauth_token_secret and u'%s' % oauth_token_secret self.callback_url = callback_url @@ -146,8 +130,7 @@ class Twython(object): signature_type='auth_header') if self.client is None: - # If they don't do authentication, but still want to request - # unprotected resources, we need an opener. + # Allow unauthenticated requests to be made. self.client = requests.session(proxies=proxies) # register available funcs to allow listing name when debugging. @@ -181,11 +164,16 @@ class Twython(object): '''Internal response generator, no sense in repeating the same code twice, right? ;) ''' - myargs = {} method = method.lower() + if not method in ('get', 'post'): + raise TwythonError('Method must be of GET or POST') params = params or {} + # In the next release of requests after 0.13.1, we can get rid of this + # myargs variable and line 184, urlencoding the params and just + # pass params=params in the func() + myargs = {} if method == 'get': url = '%s?%s' % (url, urllib.urlencode(params)) else: @@ -207,10 +195,6 @@ class Twython(object): 'content': content, } - # Python 2.6 `json` will throw a ValueError if it - # can't load the string as valid JSON, - # `simplejson` will throw simplejson.decoder.JSONDecodeError - # But excepting just ValueError will work with both. o.O try: content = simplejson.loads(content) except ValueError: @@ -436,7 +420,7 @@ class Twython(object): return self._media_update(url, {'image': (file_, open(file_, 'rb'))}, params={'tile': tile}) - + def bulkUserLookup(self, **kwargs): """Stub for a method that has been deprecated, kept for now to raise errors properly if people are relying on this (which they are...). @@ -446,7 +430,7 @@ class Twython(object): DeprecationWarning, stacklevel=2 ) - + def updateProfileImage(self, file_, version=1): """Updates the authenticating user's profile image (avatar). @@ -458,7 +442,6 @@ class Twython(object): return self._media_update(url, {'image': (file_, open(file_, 'rb'))}) - # statuses/update_with_media def updateStatusWithMedia(self, file_, version=1, **params): """Updates the users status with media From dfdbbec5a8a4c288bf3f7e118280c7a85ca829bc Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Mon, 25 Jun 2012 11:54:33 -0400 Subject: [PATCH 2/5] Add H6's to README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8bfe7b5..dd8be37 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Installation Usage ----- -Authorization URL +###### Authorization URL ```python from twython import Twython @@ -50,7 +50,7 @@ print 'Connect to Twitter via: %s' % auth_props['auth_url'] Be sure you have a URL set up to handle the callback after the user has allowed your app to access their data, the callback can be used for storing their final OAuth Token and OAuth Token Secret in a database for use at a later date. -Handling the callback +###### Handling the callback ```python from twython import Twython @@ -71,7 +71,7 @@ print auth_tokens *Function definitions (i.e. getHomeTimeline()) can be found by reading over twython/twitter_endpoints.py* -Getting a user home timeline +###### Getting a user home timeline ```python from twython import Twython @@ -90,7 +90,7 @@ t = Twython(app_key=app_key, print t.getHomeTimeline() ``` -Get a user avatar url *(no authentication needed)* +###### Get a user avatar url *(no authentication needed)* ```python from twython import Twython @@ -100,7 +100,7 @@ print t.getProfileImageUrl('ryanmcgrath', size='bigger') print t.getProfileImageUrl('mikehelmick') ``` -Search Twitter *(no authentication needed)* +###### Search Twitter *(no authentication needed)* ```python from twython import Twython @@ -109,7 +109,7 @@ t = Twython() print t.search(q='python') ``` -Streaming API +###### Streaming API *Usage is as follows; it's designed to be open-ended enough that you can adapt it to higher-level (read: Twitter must give you access) streams.* From a9b7b836c985a963ddbdf89522d5222cd74f0db1 Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Thu, 28 Jun 2012 11:08:59 -0400 Subject: [PATCH 3/5] Fixes #103 Fix #93 is incorrect. We can avoid this by just removing the check and quote_plus --- twython/twython.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/twython/twython.py b/twython/twython.py index 0d6bb01..4d5822c 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -366,8 +366,6 @@ class Twython(object): e.g x.search(q='jjndf', page='2') """ - if 'q' in kwargs: - kwargs['q'] = urllib.quote_plus(Twython.unicode2utf8(kwargs['q'], ':')) return self.get('https://search.twitter.com/search.json', params=kwargs) From f4b2ebc40a9c1e8b91ce84c25378091e51bb5828 Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Thu, 28 Jun 2012 11:13:49 -0400 Subject: [PATCH 4/5] This func no longer needs to urlencode the query, _request does it --- twython/twython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/twython/twython.py b/twython/twython.py index 4d5822c..3405c2f 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -380,7 +380,7 @@ class Twython(object): for result in search: print result """ - kwargs['q'] = urllib.quote_plus(Twython.unicode2utf8(search_query)) + kwargs['q'] = search_query content = self.get('https://search.twitter.com/search.json', params=kwargs) if not content['results']: From d86437681679462a6d84e069a20fdad3bb1b76f3 Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Fri, 29 Jun 2012 12:19:37 -0400 Subject: [PATCH 5/5] Code cleanup, Update requests version * No sense in setting self.auth twice * Make self.client a requests.session to reuse headers and auth * requests 0.13.2 dependency isn't needed, but doesn't hurt --- setup.py | 2 +- twython/twython.py | 44 ++++++++++++++++++-------------------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/setup.py b/setup.py index d4f529b..8f4f883 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( include_package_data=True, # Package dependencies. - install_requires=['simplejson', 'requests>=0.13.0'], + install_requires=['simplejson', 'requests>=0.13.2'], # Metadata for PyPI. author='Ryan McGrath', diff --git a/twython/twython.py b/twython/twython.py index 3405c2f..b74938e 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -113,25 +113,25 @@ class Twython(object): self.callback_url = callback_url # If there's headers, set them, otherwise be an embarassing parent for their own good. - self.headers = headers - if self.headers is None: - self.headers = {'User-agent': 'Twython Python Twitter Library v' + __version__} + self.headers = headers or {'User-Agent': 'Twython v' + __version__} - self.client = None + # Allow for unauthenticated requests + self.client = requests.session(proxies=proxies) self.auth = None - if self.app_key is not None and self.app_secret is not None: + 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: self.auth = OAuth1(self.app_key, self.app_secret, signature_type='auth_header') - if self.oauth_token is not None and self.oauth_token_secret is not None: + 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.auth = OAuth1(self.app_key, self.app_secret, self.oauth_token, self.oauth_token_secret, signature_type='auth_header') - if self.client is None: - # Allow unauthenticated requests to be made. - self.client = requests.session(proxies=proxies) + if self.auth is not None: + self.client = requests.session(headers=self.headers, auth=self.auth, proxies=proxies) # register available funcs to allow listing name when debugging. def setFunc(key): @@ -152,11 +152,7 @@ class Twython(object): base_url + fn['url'] ) - method = fn['method'].lower() - if not method in ('get', 'post'): - raise TwythonError('Method must be of GET or POST') - - content = self._request(url, method=method, params=kwargs) + content = self._request(url, method=fn['method'], params=kwargs) return content @@ -170,17 +166,13 @@ class Twython(object): params = params or {} - # In the next release of requests after 0.13.1, we can get rid of this - # myargs variable and line 184, urlencoding the params and just - # pass params=params in the func() - myargs = {} - if method == 'get': - url = '%s?%s' % (url, urllib.urlencode(params)) - else: - myargs = params - func = getattr(self.client, method) - response = func(url, data=myargs, files=files, headers=self.headers, auth=self.auth) + if method == 'get': + # Still wasn't fixed in `requests` 0.13.2? :( + url = url + '?' + urllib.urlencode(params) + response = func(url) + else: + response = func(url, data=params, files=files) content = response.content.decode('utf-8') # create stash for last function intel @@ -271,7 +263,7 @@ class Twython(object): request_args['oauth_callback'] = self.callback_url req_url = self.request_token_url + '?' + urllib.urlencode(request_args) - response = self.client.get(req_url, headers=self.headers, auth=self.auth) + response = self.client.get(req_url) if response.status_code != 200: raise TwythonAuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (response.status_code, response.content)) @@ -297,7 +289,7 @@ class Twython(object): def get_authorized_tokens(self): """Returns authorized tokens after they go through the auth_url phase. """ - response = self.client.get(self.access_token_url, headers=self.headers, auth=self.auth) + response = self.client.get(self.access_token_url) authorized_tokens = dict(parse_qsl(response.content)) if not authorized_tokens: raise TwythonError('Unable to decode authorized tokens.')