From 894e94a4cd666bb32e3b0144a4935b0624e8e020 Mon Sep 17 00:00:00 2001 From: Mike Helmick Date: Thu, 23 May 2013 23:32:32 -0400 Subject: [PATCH] 2.10.1 - More test coverage! - Fix ``search_gen`` - Fixed ``get_lastfunction_header`` to actually do what its docstring says, returns ``None`` if header is not found - Updated some internal API code, ``__init__`` didn't need to have ``self.auth`` and ``self.headers`` because they were never used anywhere else but the ``__init__`` --- HISTORY.rst | 7 ++++ setup.py | 4 ++- test_twython.py | 78 ++++++++++++++++++++++++++++++++++++++++++--- twython/__init__.py | 2 +- twython/twython.py | 35 ++++++++++---------- 5 files changed, 102 insertions(+), 24 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index df10007..4e3706d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,13 @@ History ------- +2.10.1 (2013-05-xx) +++++++++++++++++++ +- More test coverage! +- Fix ``search_gen`` +- Fixed ``get_lastfunction_header`` to actually do what its docstring says, returns ``None`` if header is not found +- Updated some internal API code, ``__init__`` didn't need to have ``self.auth`` and ``self.headers`` because they were never used anywhere else but the ``__init__`` + 2.10.0 (2013-05-21) ++++++++++++++++++ - Added ``get_retweeters_ids`` method diff --git a/setup.py b/setup.py index d24a3de..045d9e0 100755 --- a/setup.py +++ b/setup.py @@ -1,10 +1,12 @@ +#!/usr/bin/env python + import os import sys from setuptools import setup __author__ = 'Ryan McGrath ' -__version__ = '2.10.0' +__version__ = '2.10.1' packages = [ 'twython', diff --git a/test_twython.py b/test_twython.py index 759dcb4..e5e7fa1 100644 --- a/test_twython.py +++ b/test_twython.py @@ -24,6 +24,7 @@ test_list_id = os.environ.get('TEST_LIST_ID', '574') # 574 is @twitter/team class TwythonAuthTestCase(unittest.TestCase): def setUp(self): self.api = Twython(app_key, app_secret) + self.bad_api = Twython('BAD_APP_KEY', 'BAD_APP_SECRET') def test_get_authentication_tokens(self): '''Test getting authentication tokens works''' @@ -31,11 +32,76 @@ class TwythonAuthTestCase(unittest.TestCase): force_login=True, screen_name=screen_name) + def test_get_authentication_tokens_bad_tokens(self): + '''Test getting authentication tokens with bad tokens + raises TwythonAuthError''' + self.assertRaises(TwythonAuthError, self.api.get_authentication_tokens, + callback_url='http://google.com/') + + def test_get_authorized_tokens_bad_tokens(self): + '''Test getting final tokens fails with wrong tokens''' + self.assertRaises(TwythonError, self.api.get_authorized_tokens, + 'BAD_OAUTH_VERIFIER') + class TwythonAPITestCase(unittest.TestCase): def setUp(self): self.api = Twython(app_key, app_secret, - oauth_token, oauth_token_secret) + oauth_token, oauth_token_secret, + headers={'User-Agent': '__twython__ Test'}) + + def test_construct_api_url(self): + '''Test constructing a Twitter API url works as we expect''' + url = 'https://api.twitter.com/1.1/search/tweets.json' + constructed_url = self.api.construct_api_url(url, {'q': '#twitter'}) + self.assertEqual(constructed_url, 'https://api.twitter.com/1.1/search/tweets.json?q=%23twitter') + + def test_shorten_url(self): + '''Test shortening a url works''' + self.api.shorten_url('http://google.com') + + def test_shorten_url_no_shortner(self): + '''Test shortening a url with no shortener provided raises TwythonError''' + self.assertRaises(TwythonError, self.api.shorten_url, + 'http://google.com', '') + + def test_get(self): + '''Test Twython generic GET request works''' + self.api.get('account/verify_credentials') + + def test_post(self): + '''Test Twython generic POST request works, with a full url and + with just an endpoint''' + update_url = 'https://api.twitter.com/1.1/statuses/update.json' + status = self.api.post(update_url, params={'status': 'I love Twython!'}) + self.api.post('statuses/destroy/%s' % status['id_str']) + + def test_get_lastfunction_header(self): + '''Test getting last specific header of the last API call works''' + self.api.get('statuses/home_timeline') + self.api.get_lastfunction_header('x-rate-limit-remaining') + + def test_get_lastfunction_header_not_present(self): + '''Test getting specific header that does not exist from the last call returns None''' + self.api.get('statuses/home_timeline') + header = self.api.get_lastfunction_header('does-not-exist') + self.assertEqual(header, None) + + def test_get_lastfunction_header_no_last_api_call(self): + '''Test attempting to get a header when no API call was made raises a TwythonError''' + self.assertRaises(TwythonError, self.api.get_lastfunction_header, + 'no-api-call-was-made') + + def test_search_gen(self): + '''Test looping through the generator results works, at least once that is''' + search = self.api.search_gen('python') + for result in search: + if result: + break + + def test_encode(self): + '''Test encoding UTF-8 works''' + self.api.encode('Twython is awesome!') # Timelines def test_get_mentions_timeline(self): @@ -84,9 +150,11 @@ class TwythonAPITestCase(unittest.TestCase): def test_retweet_twice(self): '''Test that trying to retweet a tweet twice raises a TwythonError''' - retweet = self.api.retweet(id='99530515043983360') - self.assertRaises(TwythonError, self.api.retweet, - id='99530515043983360') + tweets = self.api.search(q='twitter').get('statuses') + if tweets: + retweet = self.api.retweet(id=tweets[0]['id_str']) + self.assertRaises(TwythonError, self.api.retweet, + id=tweets[0]['id_str']) # Then clean up self.api.destroy_status(id=retweet['id_str']) @@ -132,7 +200,7 @@ class TwythonAPITestCase(unittest.TestCase): def test_get_user_ids_of_blocked_retweets(self): '''Test that collection of user_ids that the authenticated user does not want to receive retweets from succeeds''' - self.api.get_user_ids_of_blocked_retweets(stringify_ids='true') + self.api.get_user_ids_of_blocked_retweets(stringify_ids=True) def test_get_friends_ids(self): '''Test returning ids of users the authenticated user and then a random diff --git a/twython/__init__.py b/twython/__init__.py index 6390bcb..ce1c200 100644 --- a/twython/__init__.py +++ b/twython/__init__.py @@ -18,7 +18,7 @@ Questions, comments? ryan@venodesigns.net """ __author__ = 'Ryan McGrath ' -__version__ = '2.10.0' +__version__ = '2.10.1' from .twython import Twython from .streaming import TwythonStreamer diff --git a/twython/twython.py b/twython/twython.py index 286afd8..1ac04f8 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -59,27 +59,27 @@ class Twython(object): stacklevel=2 ) - self.headers = {'User-Agent': 'Twython v' + __version__} + req_headers = {'User-Agent': 'Twython v' + __version__} if headers: - self.headers.update(headers) + req_headers.update(headers) # Generate OAuth authentication object for the request - # If no keys/tokens are passed to __init__, self.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 - self.auth = None + auth = 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) + 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 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) + auth = OAuth1(self.app_key, self.app_secret, + self.oauth_token, self.oauth_token_secret) self.client = requests.Session() - self.client.headers = self.headers + self.client.headers = req_headers self.client.proxies = proxies - self.client.auth = self.auth + self.client.auth = auth self.client.verify = ssl_verify # register available funcs to allow listing name when debugging. @@ -208,7 +208,7 @@ class Twython(object): def request(self, endpoint, method='GET', params=None, version='1.1'): # In case they want to pass a full Twitter URL - # i.e. https://search.twitter.com/ + # i.e. https://api.twitter.com/1.1/search/tweets.json if endpoint.startswith('http://') or endpoint.startswith('https://'): url = endpoint else: @@ -241,9 +241,11 @@ class Twython(object): """ if self._last_call is None: raise TwythonError('This function must be called after an API call. It delivers header information.') + if header in self._last_call['headers']: return self._last_call['headers'][header] - return self._last_call + else: + return None def get_authentication_tokens(self, callback_url=None, force_login=False, screen_name=''): """Returns a dict including an authorization URL (auth_url) to direct a user to @@ -325,7 +327,7 @@ class Twython(object): stacklevel=2 ) - if shortener == '': + if not shortener: raise TwythonError('Please provide a URL shortening service.') request = requests.get(shortener, params={ @@ -336,7 +338,7 @@ class Twython(object): if request.status_code in [301, 201, 200]: return request.text else: - raise TwythonError('shortenURL() failed with a %s error code.' % request.status_code) + raise TwythonError('shorten_url failed with a %s error code.' % request.status_code) @staticmethod def constructApiURL(base_url, params): @@ -373,17 +375,16 @@ class Twython(object): See Twython.search() for acceptable parameters - e.g search = x.searchGen('python') + e.g search = x.search_gen('python') for result in search: print result """ - kwargs['q'] = search_query content = self.search(q=search_query, **kwargs) - if not content['results']: + if not content.get('statuses'): raise StopIteration - for tweet in content['results']: + for tweet in content['statuses']: yield tweet try: