Hello community, here is the log from the commit of package python-tweepy for openSUSE:Factory checked in at 2013-11-24 12:32:22 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-tweepy (Old) and /work/SRC/openSUSE:Factory/.python-tweepy.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tweepy" Changes: -------- --- /work/SRC/openSUSE:Factory/python-tweepy/python-tweepy.changes 2013-10-25 11:34:23.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-tweepy.new/python-tweepy.changes 2013-11-24 12:32:23.000000000 +0100 @@ -1,0 +2,6 @@ +Fri Nov 15 23:25:43 UTC 2013 - [email protected] + +- Update to version 2.1 + + No changelog available + +------------------------------------------------------------------- Old: ---- tweepy-2.0.tar.gz New: ---- tweepy-2.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-tweepy.spec ++++++ --- /var/tmp/diff_new_pack.PRtI4N/_old 2013-11-24 12:32:23.000000000 +0100 +++ /var/tmp/diff_new_pack.PRtI4N/_new 2013-11-24 12:32:23.000000000 +0100 @@ -17,7 +17,7 @@ Name: python-tweepy -Version: 2.0 +Version: 2.1 Release: 0 Url: http://github.com/joshthecoder/tweepy Summary: Twitter library for python ++++++ tweepy-2.0.tar.gz -> tweepy-2.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/PKG-INFO new/tweepy-2.1/PKG-INFO --- old/tweepy-2.0/PKG-INFO 2013-02-10 22:45:51.000000000 +0100 +++ new/tweepy-2.1/PKG-INFO 2013-07-14 20:59:03.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: tweepy -Version: 2.0 +Version: 2.1 Summary: Twitter library for python Home-page: http://github.com/tweepy/tweepy Author: Joshua Roesslein diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/__init__.py new/tweepy-2.1/tests/__init__.py --- old/tweepy-2.0/tests/__init__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/__init__.py 2013-05-19 10:17:49.000000000 +0200 @@ -0,0 +1 @@ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/config.py new/tweepy-2.1/tests/config.py --- old/tweepy-2.0/tests/config.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/config.py 2013-06-08 22:30:54.000000000 +0200 @@ -0,0 +1,15 @@ +import os + +from tweepy.auth import OAuthHandler + +username = os.environ.get('TWITTER_USERNAME', '') +oauth_consumer_key = os.environ.get('CONSUMER_KEY', '') +oauth_consumer_secret = os.environ.get('CONSUMER_SECRET', '') +oauth_token = os.environ.get('ACCESS_KEY', '') +oauth_token_secret = os.environ.get('ACCESS_SECRET', '') + +def create_auth(): + auth = OAuthHandler(oauth_consumer_key, oauth_consumer_secret) + auth.set_access_token(oauth_token, oauth_token_secret) + return auth + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/mock.py new/tweepy-2.1/tests/mock.py --- old/tweepy-2.0/tests/mock.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/mock.py 2013-05-19 10:17:49.000000000 +0200 @@ -0,0 +1,8 @@ +import random +import string + +def mock_tweet(): + """Generate some random tweet text.""" + count = random.randint(70, 140) + return ''.join([random.choice(string.letters) for i in xrange(count)]) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/test_api.py new/tweepy-2.1/tests/test_api.py --- old/tweepy-2.0/tests/test_api.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/test_api.py 2013-06-11 05:30:38.000000000 +0200 @@ -0,0 +1,359 @@ +import unittest +import random +from time import sleep +import os + +from nose import SkipTest + +from tweepy import (API, OAuthHandler, Friendship, Cursor, + MemoryCache, FileCache) + +from config import * + +test_tweet_id = '266367358078169089' + +"""Unit tests""" + +class TweepyErrorTests(unittest.TestCase): + + def testpickle(self): + """Verify exceptions can be pickled and unpickled.""" + import pickle + from tweepy.error import TweepError + + e = TweepError('no reason', {'status': 200}) + e2 = pickle.loads(pickle.dumps(e)) + + self.assertEqual(e.reason, e2.reason) + self.assertEqual(e.response, e2.response) + +class TweepyAPITests(unittest.TestCase): + + def setUp(self): + auth = OAuthHandler(oauth_consumer_key, oauth_consumer_secret) + auth.set_access_token(oauth_token, oauth_token_secret) + self.api = API(auth) + self.api.retry_count = 2 + self.api.retry_delay = 5 + + # TODO: Actually have some sort of better assertion + def testgetoembed(self): + data = self.api.get_oembed(test_tweet_id) + self.assertEqual(data['author_name'], "Twitter") + + + def testhometimeline(self): + self.api.home_timeline() + + def testusertimeline(self): + self.api.user_timeline() + self.api.user_timeline('twitter') + + def testmentionstimeline(self): + self.api.mentions_timeline() + + def testretweetsofme(self): + self.api.retweets_of_me() + + def testretweet(self): + # TODO(josh): Need a way to get random tweets to retweet. + raise SkipTest() + + def testretweets(self): + self.api.retweets(test_tweet_id) + + def testgetstatus(self): + self.api.get_status(id=test_tweet_id) + + def testupdateanddestroystatus(self): + # test update + text = 'testing %i' % random.randint(0, 1000) + update = self.api.update_status(status=text) + self.assertEqual(update.text, text) + + # test destroy + deleted = self.api.destroy_status(id=update.id) + self.assertEqual(deleted.id, update.id) + + def testgetuser(self): + u = self.api.get_user('twitter') + self.assertEqual(u.screen_name, 'twitter') + + u = self.api.get_user(783214) + self.assertEqual(u.screen_name, 'twitter') + + def testsearchusers(self): + self.api.search_users('twitter') + + def testsuggestedcategories(self): + self.api.suggested_categories() + + def testsuggestedusers(self): + categories = self.api.suggested_categories() + if len(categories) != 0: + self.api.suggested_users(categories[0].slug) + + def testsuggesteduserstweets(self): + categories = self.api.suggested_categories() + if len(categories) != 0: + self.api.suggested_users_tweets(categories[0].slug) + + def testme(self): + me = self.api.me() + self.assertEqual(me.screen_name, username) + + def testdirectmessages(self): + self.api.direct_messages() + + def testsentdirectmessages(self): + self.api.sent_direct_messages() + + def testsendanddestroydirectmessage(self): + # send + sent_dm = self.api.send_direct_message(username, text='test message') + self.assertEqual(sent_dm.text, 'test message') + self.assertEqual(sent_dm.sender.screen_name, username) + self.assertEqual(sent_dm.recipient.screen_name, username) + + # destroy + destroyed_dm = self.api.destroy_direct_message(sent_dm.id) + self.assertEqual(destroyed_dm.text, sent_dm.text) + self.assertEqual(destroyed_dm.id, sent_dm.id) + self.assertEqual(destroyed_dm.sender.screen_name, username) + self.assertEqual(destroyed_dm.recipient.screen_name, username) + + def testcreatedestroyfriendship(self): + enemy = self.api.destroy_friendship('twitter') + self.assertEqual(enemy.screen_name, 'twitter') + + # Wait 5 seconds to allow Twitter time + # to process the friendship destroy request. + sleep(5) + + friend = self.api.create_friendship('twitter') + self.assertEqual(friend.screen_name, 'twitter') + + def testshowfriendship(self): + source, target = self.api.show_friendship(target_screen_name='twtiter') + self.assert_(isinstance(source, Friendship)) + self.assert_(isinstance(target, Friendship)) + + def testfriendsids(self): + self.api.friends_ids(username) + + def testfollowersids(self): + self.api.followers_ids(username) + + def testfriends(self): + self.api.friends(username) + + def testfollowers(self): + self.api.followers(username) + + def testverifycredentials(self): + self.assertNotEqual(self.api.verify_credentials(), False) + + # make sure that `me.status.entities` is not an empty dict + me = self.api.verify_credentials(include_entities=True) + self.assertTrue(me.status.entities) + + # `status` shouldn't be included + me = self.api.verify_credentials(skip_status=True) + self.assertFalse(hasattr(me, 'status')) + + def testratelimitstatus(self): + self.api.rate_limit_status() + + """ TODO(josh): Remove once this deprecated API is gone. + def testsetdeliverydevice(self): + self.api.set_delivery_device('im') + self.api.set_delivery_device('none') + """ + + def testupdateprofilecolors(self): + original = self.api.me() + updated = self.api.update_profile_colors('000', '000', '000', '000', '000') + + # restore colors + self.api.update_profile_colors( + original.profile_background_color, + original.profile_text_color, + original.profile_link_color, + original.profile_sidebar_fill_color, + original.profile_sidebar_border_color + ) + + self.assertEqual(updated.profile_background_color, '000000') + self.assertEqual(updated.profile_text_color, '000000') + self.assertEqual(updated.profile_link_color, '000000') + self.assertEqual(updated.profile_sidebar_fill_color, '000000') + self.assertEqual(updated.profile_sidebar_border_color, '000000') + + """ + def testupateprofileimage(self): + self.api.update_profile_image('examples/profile.png') + + def testupdateprofilebg(self): + self.api.update_profile_background_image('examples/bg.png') + """ + + def testupdateprofile(self): + original = self.api.me() + profile = { + 'name': 'Tweepy test 123', + 'location': 'pytopia', + 'description': 'just testing things out' + } + updated = self.api.update_profile(**profile) + self.api.update_profile( + name = original.name, url = original.url, + location = original.location, description = original.description + ) + + for k,v in profile.items(): + if k == 'email': continue + self.assertEqual(getattr(updated, k), v) + + def testfavorites(self): + self.api.favorites() + + def testcreatedestroyfavorite(self): + self.api.create_favorite(4901062372) + self.api.destroy_favorite(4901062372) + + def testcreatedestroyblock(self): + self.api.create_block('twitter') + self.api.destroy_block('twitter') + self.api.create_friendship('twitter') # restore + + def testblocks(self): + self.api.blocks() + + def testblocksids(self): + self.api.blocks_ids() + + def testcreateupdatedestroylist(self): + params = { + 'owner_screen_name': username, + 'slug': 'tweeps' + } + l = self.api.create_list(name=params['slug'], **params) + l = self.api.update_list(list_id=l.id, description='updated!') + self.assertEqual(l.description, 'updated!') + self.api.destroy_list(list_id=l.id) + + def testlistsall(self): + self.api.lists_all() + + def testlistsmemberships(self): + self.api.lists_memberships() + + def testlistssubscriptions(self): + self.api.lists_subscriptions() + + def testlisttimeline(self): + self.api.list_timeline('applepie', 'stars') + + def testgetlist(self): + self.api.get_list(owner_screen_name='applepie', slug='stars') + + def testaddremovelistmember(self): + params = { + 'slug': 'test', + 'owner_screen_name': username, + 'screen_name': 'twitter' + } + + def assert_list(l): + self.assertEqual(l.name, params['slug']) + + assert_list(self.api.add_list_member(**params)) + assert_list(self.api.remove_list_member(**params)) + + def testlistmembers(self): + self.api.list_members('applepie', 'stars') + + def testshowlistmember(self): + self.assertTrue(self.api.show_list_member(owner_screen_name='applepie', slug='stars', screen_name='NathanFillion')) + + def testsubscribeunsubscribelist(self): + params = { + 'owner_screen_name': 'applepie', + 'slug': 'stars' + } + self.api.subscribe_list(**params) + self.api.unsubscribe_list(**params) + + def testlistsubscribers(self): + self.api.list_subscribers('applepie', 'stars') + + def testshowlistsubscriber(self): + self.assertTrue(self.api.show_list_subscriber('twitter', 'team', username)) + + def testsavedsearches(self): + s = self.api.create_saved_search('test') + self.api.saved_searches() + self.assertEqual(self.api.get_saved_search(s.id).query, 'test') + self.api.destroy_saved_search(s.id) + + def testsearch(self): + self.api.search('tweepy') + + def testgeoapis(self): + def place_name_in_list(place_name, place_list): + """Return True if a given place_name is in place_list.""" + return any([x.full_name.lower() == place_name.lower() for x in place_list]) + + twitter_hq = self.api.geo_similar_places(lat=37, long= -122, name='Twitter HQ') + # Assumes that twitter_hq is first Place returned... + self.assertEqual(twitter_hq[0].id, '3bdf30ed8b201f31') + # Test various API functions using Austin, TX, USA + self.assertEqual(self.api.geo_id(id='c3f37afa9efcf94b').full_name, 'Austin, TX') + self.assertTrue(place_name_in_list('Austin, TX', + self.api.reverse_geocode(lat=30.267370168467806, long= -97.74261474609375))) # Austin, TX, USA + +class TweepyCacheTests(unittest.TestCase): + + timeout = 2.0 + memcache_servers = ['127.0.0.1:11211'] # must be running for test to pass + + def _run_tests(self, do_cleanup=True): + # test store and get + self.cache.store('testkey', 'testvalue') + self.assertEqual(self.cache.get('testkey'), 'testvalue', + 'Stored value does not match retrieved value') + + # test timeout + sleep(self.timeout) + self.assertEqual(self.cache.get('testkey'), None, + 'Cache entry should have expired') + + # test cleanup + if do_cleanup: + self.cache.store('testkey', 'testvalue') + sleep(self.timeout) + self.cache.cleanup() + self.assertEqual(self.cache.count(), 0, 'Cache cleanup failed') + + # test count + for i in range(0, 20): + self.cache.store('testkey%i' % i, 'testvalue') + self.assertEqual(self.cache.count(), 20, 'Count is wrong') + + # test flush + self.cache.flush() + self.assertEqual(self.cache.count(), 0, 'Cache failed to flush') + + def testmemorycache(self): + self.cache = MemoryCache(timeout=self.timeout) + self._run_tests() + + def testfilecache(self): + os.mkdir('cache_test_dir') + self.cache = FileCache('cache_test_dir', self.timeout) + self._run_tests() + self.cache.flush() + os.rmdir('cache_test_dir') + +if __name__ == '__main__': + unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/test_auth.py new/tweepy-2.1/tests/test_auth.py --- old/tweepy-2.0/tests/test_auth.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/test_auth.py 2013-06-08 22:30:54.000000000 +0200 @@ -0,0 +1,23 @@ +import unittest + +from config import * +from tweepy import API, OAuthHandler + +class TweepyAuthTests(unittest.TestCase): + + def testoauth(self): + auth = OAuthHandler(oauth_consumer_key, oauth_consumer_secret) + + # test getting access token + auth_url = auth.get_authorization_url() + print 'Please authorize: ' + auth_url + verifier = raw_input('PIN: ').strip() + self.assert_(len(verifier) > 0) + access_token = auth.get_access_token(verifier) + self.assert_(access_token is not None) + + # build api object test using oauth + api = API(auth) + s = api.update_status('test %i' % random.randint(0, 1000)) + api.destroy_status(s.id) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/test_cursors.py new/tweepy-2.1/tests/test_cursors.py --- old/tweepy-2.0/tests/test_cursors.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/test_cursors.py 2013-06-16 21:31:54.000000000 +0200 @@ -0,0 +1,33 @@ +import unittest + +from tweepy import API, Cursor + +from config import create_auth + +class TweepyCursorTests(unittest.TestCase): + + def setUp(self): + self.api = API(create_auth()) + + def testidcursoritems(self): + items = list(Cursor(self.api.user_timeline).items(25)) + self.assertEqual(len(items), 25) + + def testidcursorpages(self): + pages = list(Cursor(self.api.user_timeline).pages(5)) + self.assertEqual(len(pages), 5) + + def testcursorcursoritems(self): + items = list(Cursor(self.api.friends_ids).items(10)) + self.assertEqual(len(items), 10) + + items = list(Cursor(self.api.followers_ids, 'twitter').items(10)) + self.assertEqual(len(items), 10) + + def testcursorcursorpages(self): + pages = list(Cursor(self.api.friends_ids).pages(1)) + self.assert_(len(pages) == 1) + + pages = list(Cursor(self.api.followers_ids, 'twitter').pages(1)) + self.assert_(len(pages) == 1) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/test_resultset.py new/tweepy-2.1/tests/test_resultset.py --- old/tweepy-2.0/tests/test_resultset.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/test_resultset.py 2013-06-11 05:30:38.000000000 +0200 @@ -0,0 +1,29 @@ +import unittest + +from tweepy.models import ResultSet + +class NoIdItem(object): pass + +class IdItem(object): + def __init__(self, id): + self.id = id + +ids_fixture = [1, 10, 8, 50, 2, 100, 5] + +class TweepyResultSetTests(unittest.TestCase): + def setUp(self): + self.results = ResultSet() + for i in ids_fixture: + self.results.append(IdItem(i)) + self.results.append(NoIdItem()) + + def testids(self): + ids = self.results.ids() + self.assertListEqual(ids, ids_fixture) + + def testmaxid(self): + self.assertEqual(self.results.max_id, 100) + + def testsinceid(self): + self.assertEqual(self.results.since_id, 1) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tests/test_streaming.py new/tweepy-2.1/tests/test_streaming.py --- old/tweepy-2.0/tests/test_streaming.py 1970-01-01 01:00:00.000000000 +0100 +++ new/tweepy-2.1/tests/test_streaming.py 2013-05-19 10:17:49.000000000 +0200 @@ -0,0 +1,64 @@ +from time import sleep +import unittest + +from tweepy.api import API +from tweepy.models import Status +from tweepy.streaming import Stream, StreamListener + +from config import create_auth +from mock import mock_tweet + +class MockStreamListener(StreamListener): + def __init__(self, test_case): + super(MockStreamListener, self).__init__() + self.test_case = test_case + self.status_count = 0 + self.status_stop_count = 0 + self.connect_cb = None + + def on_connect(self): + if self.connect_cb: + self.connect_cb() + + def on_timeout(self): + self.test_case.fail('timeout') + return False + + def on_status(self, status): + self.status_count += 1 + self.test_case.assertIsInstance(status, Status) + if self.status_stop_count == self.status_count: + return False + +class TweepyStreamTests(unittest.TestCase): + def setUp(self): + self.auth = create_auth() + self.listener = MockStreamListener(self) + self.stream = Stream(self.auth, self.listener, timeout=3.0) + + def tearDown(self): + self.stream.disconnect() + + def test_userstream(self): + # Generate random tweet which should show up in the stream. + def on_connect(): + API(self.auth).update_status(mock_tweet()) + + self.listener.connect_cb = on_connect + self.listener.status_stop_count = 1 + self.stream.userstream() + self.assertEqual(self.listener.status_count, 1) + + def test_sample(self): + self.listener.status_stop_count = 10 + self.stream.sample() + self.assertEquals(self.listener.status_count, + self.listener.status_stop_count) + + def test_filter_track(self): + self.listener.status_stop_count = 5 + phrases = ['twitter'] + self.stream.filter(track=phrases) + self.assertEquals(self.listener.status_count, + self.listener.status_stop_count) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/__init__.py new/tweepy-2.1/tweepy/__init__.py --- old/tweepy-2.0/tweepy/__init__.py 2013-02-10 22:35:43.000000000 +0100 +++ new/tweepy-2.1/tweepy/__init__.py 2013-06-16 21:02:22.000000000 +0200 @@ -5,11 +5,11 @@ """ Tweepy Twitter API library """ -__version__ = '2.0' +__version__ = '2.1' __author__ = 'Joshua Roesslein' __license__ = 'MIT' -from tweepy.models import Status, User, DirectMessage, Friendship, SavedSearch, SearchResult, ModelFactory, Category +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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/api.py new/tweepy-2.1/tweepy/api.py --- old/tweepy-2.0/tweepy/api.py 2013-02-10 22:10:33.000000000 +0100 +++ new/tweepy-2.1/tweepy/api.py 2013-06-16 21:01:25.000000000 +0200 @@ -17,8 +17,8 @@ def __init__(self, auth_handler=None, host='api.twitter.com', search_host='search.twitter.com', cache=None, secure=True, api_root='/1.1', search_root='', - retry_count=0, retry_delay=0, retry_errors=None, - parser=None): + retry_count=0, retry_delay=0, retry_errors=None, timeout=60, + parser=None, compression=False): self.auth = auth_handler self.host = host self.search_host = search_host @@ -26,16 +26,18 @@ self.search_root = search_root self.cache = cache self.secure = secure + self.compression = compression self.retry_count = retry_count self.retry_delay = retry_delay self.retry_errors = retry_errors + self.timeout = timeout self.parser = parser or ModelParser() """ statuses/home_timeline """ home_timeline = bind_api( path = '/statuses/home_timeline.json', payload_type = 'status', payload_list = True, - allowed_param = ['since_id', 'max_id', 'count', 'page'], + allowed_param = ['since_id', 'max_id', 'count'], require_auth = True ) @@ -44,7 +46,7 @@ path = '/statuses/user_timeline.json', payload_type = 'status', payload_list = True, allowed_param = ['id', 'user_id', 'screen_name', 'since_id', - 'max_id', 'count', 'page', 'include_rts'] + 'max_id', 'count', 'include_rts'] ) """ statuses/mentions """ @@ -83,7 +85,7 @@ retweets_of_me = bind_api( path = '/statuses/retweets_of_me.json', payload_type = 'status', payload_list = True, - allowed_param = ['since_id', 'max_id', 'count', 'page'], + allowed_param = ['since_id', 'max_id', 'count'], require_auth = True ) @@ -136,6 +138,13 @@ allowed_param = ['id', 'user_id', 'screen_name'] ) + ''' statuses/oembed ''' + get_oembed = bind_api( + path = '/statuses/oembed.json', + payload_type = 'json', + allowed_param = ['id', 'url', 'maxwidth', 'hide_media', 'omit_script', 'align', 'related', 'lang'] + ) + """ Perform bulk look up of users from user ID or screenname """ def lookup_users(self, user_ids=None, screen_names=None): return self._lookup_users(list_to_csv(user_ids), list_to_csv(screen_names)) @@ -186,7 +195,7 @@ direct_messages = bind_api( path = '/direct_messages.json', payload_type = 'direct_message', payload_list = True, - allowed_param = ['since_id', 'max_id', 'count', 'page'], + allowed_param = ['since_id', 'max_id', 'count'], require_auth = True ) @@ -242,13 +251,6 @@ require_auth = True ) - """ friendships/exists """ - exists_friendship = bind_api( - path = '/friendships/exists.json', - payload_type = 'json', - allowed_param = ['user_a', 'user_b'] - ) - """ friendships/show """ show_friendship = bind_api( path = '/friendships/show.json', @@ -257,10 +259,9 @@ 'target_id', 'target_screen_name'] ) - """ Perform bulk look up of friendships from user ID or screenname """ def lookup_friendships(self, user_ids=None, screen_names=None): - return self._lookup_friendships(list_to_csv(user_ids), list_to_csv(screen_names)) + return self._lookup_friendships(list_to_csv(user_ids), list_to_csv(screen_names)) _lookup_friendships = bind_api( path = '/friendships/lookup.json', @@ -277,6 +278,13 @@ allowed_param = ['id', 'user_id', 'screen_name', 'cursor'] ) + """ friends/list """ + friends = bind_api( + path = '/friends/list.json', + payload_type = 'user', payload_list = True, + allowed_param = ['id', 'user_id', 'screen_name', 'cursor'] + ) + """ friendships/incoming """ friendships_incoming = bind_api( path = '/friendships/incoming.json', @@ -298,6 +306,13 @@ allowed_param = ['id', 'user_id', 'screen_name', 'cursor'] ) + """ followers/list """ + followers = bind_api( + path = '/followers/list.json', + payload_type = 'user', payload_list = True, + allowed_param = ['id', 'user_id', 'screen_name', 'cursor'] + ) + """ account/verify_credentials """ def verify_credentials(self, **kargs): try: @@ -417,7 +432,7 @@ blocks = bind_api( path = '/blocks/list.json', payload_type = 'user', payload_list = True, - allowed_param = ['page'], + allowed_param = ['cursor'], require_auth = True ) @@ -430,10 +445,10 @@ """ report_spam """ report_spam = bind_api( - path = '/report_spam.json', + path = '/users/report_spam.json', method = 'POST', payload_type = 'user', - allowed_param = ['id', 'user_id', 'screen_name'], + allowed_param = ['user_id', 'screen_name'], require_auth = True ) @@ -613,12 +628,10 @@ """ search """ search = bind_api( - search_api = True, - path = '/search.json', - payload_type = 'search_result', payload_list = True, - allowed_param = ['q', 'lang', 'locale', 'rpp', 'page', 'since_id', 'geocode', 'show_user', 'max_id', 'since', 'until', 'result_type'] + path = '/search/tweets.json', + payload_type = 'search_results', + allowed_param = ['q', 'lang', 'locale', 'since_id', 'geocode', 'show_user', 'max_id', 'since', 'until', 'result_type'] ) - search.pagination_mode = 'page' """ trends/daily """ trends_daily = bind_api( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/auth.py new/tweepy-2.1/tweepy/auth.py --- old/tweepy-2.0/tweepy/auth.py 2013-02-10 21:49:34.000000000 +0100 +++ new/tweepy-2.1/tweepy/auth.py 2013-06-08 22:30:54.000000000 +0200 @@ -138,9 +138,9 @@ oauth_consumer=self._consumer, http_method='POST', http_url=url, parameters = { - 'x_auth_mode': 'client_auth', - 'x_auth_username': username, - 'x_auth_password': password + 'x_auth_mode': 'client_auth', + 'x_auth_username': username, + 'x_auth_password': password } ) request.sign_request(self._sigmethod, self._consumer, None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/binder.py new/tweepy-2.1/tweepy/binder.py --- old/tweepy-2.0/tweepy/binder.py 2013-02-10 21:49:34.000000000 +0100 +++ new/tweepy-2.1/tweepy/binder.py 2013-06-11 05:30:38.000000000 +0200 @@ -6,6 +6,8 @@ import urllib import time import re +from StringIO import StringIO +import gzip from tweepy.error import TweepError from tweepy.utils import convert_to_utf8_str @@ -128,11 +130,10 @@ retries_performed = 0 while retries_performed < self.retry_count + 1: # Open connection - # FIXME: add timeout if self.api.secure: - conn = httplib.HTTPSConnection(self.host) + conn = httplib.HTTPSConnection(self.host, timeout=self.api.timeout) else: - conn = httplib.HTTPConnection(self.host) + conn = httplib.HTTPConnection(self.host, timeout=self.api.timeout) # Apply authentication if self.api.auth: @@ -141,6 +142,10 @@ self.method, self.headers, self.parameters ) + # Request compression if configured + if self.api.compression: + self.headers['Accept-encoding'] = 'gzip' + # Execute request try: conn.request(self.method, url, headers=self.headers, body=self.post_data) @@ -168,7 +173,14 @@ raise TweepError(error_msg, resp) # Parse the response payload - result = self.api.parser.parse(self, resp.read()) + body = resp.read() + if resp.getheader('Content-Encoding', '') == 'gzip': + try: + zipper = gzip.GzipFile(fileobj=StringIO(body)) + body = zipper.read() + except Exception, e: + raise TweepError('Failed to decompress data: %s' % e) + result = self.api.parser.parse(self, body) conn.close() @@ -188,6 +200,9 @@ # 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 'page' in APIMethod.allowed_param: _call.pagination_mode = 'page' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/cursor.py new/tweepy-2.1/tweepy/cursor.py --- old/tweepy-2.0/tweepy/cursor.py 2013-02-10 21:49:34.000000000 +0100 +++ new/tweepy-2.1/tweepy/cursor.py 2013-06-16 21:39:31.000000000 +0200 @@ -11,8 +11,12 @@ if hasattr(method, 'pagination_mode'): if method.pagination_mode == 'cursor': self.iterator = CursorIterator(method, args, kargs) - else: + elif method.pagination_mode == 'id': + self.iterator = IdIterator(method, args, kargs) + elif method.pagination_mode == 'page': self.iterator = PageIterator(method, args, kargs) + else: + raise TweepError('Invalid pagination mode.') else: raise TweepError('This method does not perform pagination') @@ -74,6 +78,44 @@ self.count -= 1 return data +class IdIterator(BaseIterator): + + def __init__(self, method, args, kargs): + BaseIterator.__init__(self, method, args, kargs) + self.max_id = kargs.get('max_id') + self.since_id = kargs.get('since_id') + self.count = 0 + + def next(self): + """Fetch a set of items with IDs less than current set.""" + if self.limit and self.limit == self.count: + raise StopIteration + + # max_id is inclusive so decrement by one + # to avoid requesting duplicate items. + max_id = self.since_id - 1 if self.max_id else None + data = self.method(max_id = max_id, *self.args, **self.kargs) + if len(data) == 0: + raise StopIteration + self.max_id = data.max_id + self.since_id = data.since_id + self.count += 1 + return data + + def prev(self): + """Fetch a set of items with IDs greater than current set.""" + if self.limit and self.limit == self.count: + raise StopIteration + + since_id = self.max_id + data = self.method(since_id = since_id, *self.args, **self.kargs) + if len(data) == 0: + raise StopIteration + self.max_id = data.max_id + self.since_id = data.since_id + self.count += 1 + return data + class PageIterator(BaseIterator): def __init__(self, method, args, kargs): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/models.py new/tweepy-2.1/tweepy/models.py --- old/tweepy-2.0/tweepy/models.py 2013-02-10 22:10:33.000000000 +0100 +++ new/tweepy-2.1/tweepy/models.py 2013-06-16 21:01:25.000000000 +0200 @@ -9,7 +9,27 @@ class ResultSet(list): """A list like object that holds results from a Twitter API query.""" + def __init__(self, max_id=None, since_id=None): + super(ResultSet, self).__init__() + self._max_id = max_id + self._since_id = since_id + + @property + def max_id(self): + if self._max_id: + return self._max_id + ids = self.ids() + return max(ids) if ids else None + + @property + def since_id(self): + if self._since_id: + return self._since_id + ids = self.ids() + return min(ids) if ids else None + def ids(self): + return [item.id for item in self if hasattr(item, 'id')] class Model(object): @@ -209,34 +229,18 @@ return self._api.destroy_saved_search(self.id) -class SearchResult(Model): +class SearchResults(ResultSet): @classmethod def parse(cls, api, json): - result = cls() - for k, v in json.items(): - if k == 'created_at': - setattr(result, k, parse_search_datetime(v)) - elif k == 'source': - setattr(result, k, parse_html_value(unescape_html(v))) - else: - setattr(result, k, v) - return result + metadata = json['search_metadata'] + results = SearchResults(metadata.get('max_id'), metadata.get('since_id')) + results.refresh_url = metadata.get('refresh_url') + results.completed_in = metadata.get('completed_in') + results.query = metadata.get('query') - @classmethod - def parse_list(cls, api, json_list, result_set=None): - results = ResultSet() - results.max_id = json_list.get('max_id') - results.since_id = json_list.get('since_id') - results.refresh_url = json_list.get('refresh_url') - results.next_page = json_list.get('next_page') - results.results_per_page = json_list.get('results_per_page') - results.page = json_list.get('page') - results.completed_in = json_list.get('completed_in') - results.query = json_list.get('query') - - for obj in json_list['results']: - results.append(cls.parse(api, obj)) + for status in json['statuses']: + results.append(Status.parse(api, status)) return results @@ -315,7 +319,7 @@ result = cls(api) for k,v in json.items(): if k == 'connections': - setattr(result, 'is_following', 'following' in v) + setattr(result, 'is_following', 'following' in v) setattr(result, 'is_followed_by', 'followed_by' in v) else: setattr(result, k, v) @@ -414,7 +418,7 @@ direct_message = DirectMessage friendship = Friendship saved_search = SavedSearch - search_result = SearchResult + search_results = SearchResults category = Category list = List relation = Relation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy/streaming.py new/tweepy-2.1/tweepy/streaming.py --- old/tweepy-2.0/tweepy/streaming.py 2013-02-10 22:10:33.000000000 +0100 +++ new/tweepy-2.1/tweepy/streaming.py 2013-05-19 10:17:49.000000000 +0200 @@ -22,6 +22,15 @@ def __init__(self, api=None): self.api = api or API() + def on_connect(self): + """Called once connected to streaming server. + + This will be invoked once a successful response + is received from the server. Allows the listener + to perform some work prior to entering the read loop. + """ + pass + def on_data(self, data): """Called when raw data is received from connection. @@ -114,6 +123,7 @@ sleep(self.retry_time) else: error_counter = 0 + self.listener.on_connect() self._read_loop(resp) except timeout: if self.listener.on_timeout() == False: @@ -208,7 +218,7 @@ self._start(async) def filter(self, follow=None, track=None, async=False, locations=None, - count = None, stall_warnings=False): + count = None, stall_warnings=False, languages=None): self.parameters = {} self.headers['Content-type'] = "application/x-www-form-urlencoded" if self.running: @@ -225,6 +235,8 @@ self.parameters['count'] = count if stall_warnings: self.parameters['stall_warnings'] = stall_warnings + if languages: + self.parameters['language'] = ','.join(map(str, languages)) self.body = urlencode_noplus(self.parameters) self.parameters['delimited'] = 'length' self._start(async) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy.egg-info/PKG-INFO new/tweepy-2.1/tweepy.egg-info/PKG-INFO --- old/tweepy-2.0/tweepy.egg-info/PKG-INFO 2013-02-10 22:45:50.000000000 +0100 +++ new/tweepy-2.1/tweepy.egg-info/PKG-INFO 2013-07-14 20:59:03.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: tweepy -Version: 2.0 +Version: 2.1 Summary: Twitter library for python Home-page: http://github.com/tweepy/tweepy Author: Joshua Roesslein diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy.egg-info/SOURCES.txt new/tweepy-2.1/tweepy.egg-info/SOURCES.txt --- old/tweepy-2.0/tweepy.egg-info/SOURCES.txt 2013-02-10 22:45:50.000000000 +0100 +++ new/tweepy-2.1/tweepy.egg-info/SOURCES.txt 2013-07-14 20:59:03.000000000 +0200 @@ -1,4 +1,12 @@ setup.py +tests/__init__.py +tests/config.py +tests/mock.py +tests/test_api.py +tests/test_auth.py +tests/test_cursors.py +tests/test_resultset.py +tests/test_streaming.py tweepy/__init__.py tweepy/api.py tweepy/auth.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tweepy-2.0/tweepy.egg-info/top_level.txt new/tweepy-2.1/tweepy.egg-info/top_level.txt --- old/tweepy-2.0/tweepy.egg-info/top_level.txt 2013-02-10 22:45:50.000000000 +0100 +++ new/tweepy-2.1/tweepy.egg-info/top_level.txt 2013-07-14 20:59:03.000000000 +0200 @@ -1 +1,2 @@ +tests tweepy -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
