Skip to content

Commit edfde16

Browse files
committed
Merge ID based cursors branch.
2 parents 02a43b7 + 0106b11 commit edfde16

File tree

5 files changed

+83
-8
lines changed

5 files changed

+83
-8
lines changed

tests/test_resultset.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import unittest
2+
3+
from tweepy.models import ResultSet
4+
5+
class NoIdItem(object): pass
6+
7+
class IdItem(object):
8+
def __init__(self, id):
9+
self.id = id
10+
11+
ids_fixture = [1, 10, 8, 50, 2, 100, 5]
12+
13+
class TweepyResultSetTests(unittest.TestCase):
14+
def setUp(self):
15+
self.results = ResultSet()
16+
for i in ids_fixture:
17+
self.results.append(IdItem(i))
18+
self.results.append(NoIdItem())
19+
20+
def testids(self):
21+
ids = self.results.ids()
22+
self.assertListEqual(ids, ids_fixture)
23+
24+
def testmaxid(self):
25+
self.assertEqual(self.results.max_id, 100)
26+
27+
def testsinceid(self):
28+
self.assertEqual(self.results.since_id, 1)
29+

tweepy/api.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __init__(self, auth_handler=None,
3737
home_timeline = bind_api(
3838
path = '/statuses/home_timeline.json',
3939
payload_type = 'status', payload_list = True,
40-
allowed_param = ['since_id', 'max_id', 'count', 'page'],
40+
allowed_param = ['since_id', 'max_id', 'count'],
4141
require_auth = True
4242
)
4343

@@ -46,7 +46,7 @@ def __init__(self, auth_handler=None,
4646
path = '/statuses/user_timeline.json',
4747
payload_type = 'status', payload_list = True,
4848
allowed_param = ['id', 'user_id', 'screen_name', 'since_id',
49-
'max_id', 'count', 'page', 'include_rts']
49+
'max_id', 'count', 'include_rts']
5050
)
5151

5252
""" statuses/mentions """
@@ -85,7 +85,7 @@ def __init__(self, auth_handler=None,
8585
retweets_of_me = bind_api(
8686
path = '/statuses/retweets_of_me.json',
8787
payload_type = 'status', payload_list = True,
88-
allowed_param = ['since_id', 'max_id', 'count', 'page'],
88+
allowed_param = ['since_id', 'max_id', 'count'],
8989
require_auth = True
9090
)
9191

@@ -195,7 +195,7 @@ def me(self):
195195
direct_messages = bind_api(
196196
path = '/direct_messages.json',
197197
payload_type = 'direct_message', payload_list = True,
198-
allowed_param = ['since_id', 'max_id', 'count', 'page'],
198+
allowed_param = ['since_id', 'max_id', 'count'],
199199
require_auth = True
200200
)
201201

@@ -282,7 +282,7 @@ def lookup_friendships(self, user_ids=None, screen_names=None):
282282
friends = bind_api(
283283
path = '/friends/list.json',
284284
payload_type = 'user', payload_list = True,
285-
allowed_param = ['id', 'user_id', 'screen_name', 'page', 'cursor']
285+
allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
286286
)
287287

288288
""" friendships/incoming """
@@ -310,7 +310,7 @@ def lookup_friendships(self, user_ids=None, screen_names=None):
310310
followers = bind_api(
311311
path = '/followers/list.json',
312312
payload_type = 'user', payload_list = True,
313-
allowed_param = ['id', 'user_id', 'screen_name', 'page', 'cursor']
313+
allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
314314
)
315315

316316
""" account/verify_credentials """
@@ -432,7 +432,7 @@ def update_profile_background_image(self, filename, *args, **kargs):
432432
blocks = bind_api(
433433
path = '/blocks/list.json',
434434
payload_type = 'user', payload_list = True,
435-
allowed_param = ['page'],
435+
allowed_param = ['cursor'],
436436
require_auth = True
437437
)
438438

tweepy/binder.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ def _call(api, *args, **kargs):
200200
# Set pagination mode
201201
if 'cursor' in APIMethod.allowed_param:
202202
_call.pagination_mode = 'cursor'
203+
elif 'max_id' in APIMethod.allowed_param and \
204+
'since_id' in APIMethod.allowed_param:
205+
_call.pagination_mode = 'id'
203206
elif 'page' in APIMethod.allowed_param:
204207
_call.pagination_mode = 'page'
205208

tweepy/cursor.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ def __init__(self, method, *args, **kargs):
1111
if hasattr(method, 'pagination_mode'):
1212
if method.pagination_mode == 'cursor':
1313
self.iterator = CursorIterator(method, args, kargs)
14-
else:
14+
elif method.pagination_mode == 'id':
15+
self.iterator = IdIterator(method, args, kargs)
16+
elif method.pagination_mode == 'page':
1517
self.iterator = PageIterator(method, args, kargs)
18+
else:
19+
raise TweepError('Invalid pagination mode.')
1620
else:
1721
raise TweepError('This method does not perform pagination')
1822

@@ -74,6 +78,31 @@ def prev(self):
7478
self.count -= 1
7579
return data
7680

81+
class IdIterator(BaseIterator):
82+
83+
def __init__(self, method, args, kargs):
84+
BaseIterator.__init__(self, method, args, kargs)
85+
self.max_id = kargs.get('max_id')
86+
self.since_id = kargs.get('since_id')
87+
88+
def next(self):
89+
"""Fetch a set of items with IDs less than current set."""
90+
# max_id is inclusive so decrement by one
91+
# to avoid requesting duplicate items.
92+
max_id = self.since_id - 1 if self.max_id else None
93+
data = self.method(max_id = max_id, *self.args, **self.kargs)
94+
self.max_id = data.max_id
95+
self.since_id = data.since_id
96+
return data
97+
98+
def prev(self):
99+
"""Fetch a set of items with IDs greater than current set."""
100+
since_id = self.max_id
101+
data = self.method(since_id = since_id, *self.args, **self.kargs)
102+
self.max_id = data.max_id
103+
self.since_id = data.since_id
104+
return data
105+
77106
class PageIterator(BaseIterator):
78107

79108
def __init__(self, method, args, kargs):

tweepy/models.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,21 @@
99

1010
class ResultSet(list):
1111
"""A list like object that holds results from a Twitter API query."""
12+
def __init__(self, max_id=None, since_id=None):
13+
super(ResultSet, self).__init__()
14+
self._max_id = max_id
15+
self._since_id = since_id
1216

17+
@property
18+
def max_id(self):
19+
return self._max_id or max(self.ids())
20+
21+
@property
22+
def since_id(self):
23+
return self._since_id or min(self.ids())
24+
25+
def ids(self):
26+
return [item.id for item in self if hasattr(item, 'id')]
1327

1428
class Model(object):
1529

0 commit comments

Comments
 (0)