2
# Copyright 2009-2010 Joshua Roesslein
3
# See LICENSE for details.
8
from tweepy.binder import bind_api
9
from tweepy.error import TweepError
10
from tweepy.parsers import ModelParser
11
from tweepy.utils import list_to_csv
17
def __init__(self, auth_handler=None,
18
host='api.twitter.com', search_host='search.twitter.com',
19
cache=None, secure=False, api_root='/1', search_root='',
20
retry_count=0, retry_delay=0, retry_errors=None,
22
self.auth = auth_handler
24
self.search_host = search_host
25
self.api_root = api_root
26
self.search_root = search_root
29
self.retry_count = retry_count
30
self.retry_delay = retry_delay
31
self.retry_errors = retry_errors
32
self.parser = parser or ModelParser()
34
""" statuses/public_timeline """
35
public_timeline = bind_api(
36
path = '/statuses/public_timeline.json',
37
payload_type = 'status', payload_list = True,
41
""" statuses/home_timeline """
42
home_timeline = bind_api(
43
path = '/statuses/home_timeline.json',
44
payload_type = 'status', payload_list = True,
45
allowed_param = ['since_id', 'max_id', 'count', 'page'],
49
""" statuses/friends_timeline """
50
friends_timeline = bind_api(
51
path = '/statuses/friends_timeline.json',
52
payload_type = 'status', payload_list = True,
53
allowed_param = ['since_id', 'max_id', 'count', 'page'],
57
""" statuses/user_timeline """
58
user_timeline = bind_api(
59
path = '/statuses/user_timeline.json',
60
payload_type = 'status', payload_list = True,
61
allowed_param = ['id', 'user_id', 'screen_name', 'since_id',
62
'max_id', 'count', 'page']
65
""" statuses/mentions """
67
path = '/statuses/mentions.json',
68
payload_type = 'status', payload_list = True,
69
allowed_param = ['since_id', 'max_id', 'count', 'page'],
73
"""/statuses/:id/retweeted_by.format"""
74
retweeted_by = bind_api(
75
path = '/statuses/{id}/retweeted_by.json',
76
payload_type = 'status', payload_list = True,
77
allowed_param = ['id', 'count', 'page'],
81
"""/statuses/:id/retweeted_by/ids.format"""
82
retweeted_by_ids = bind_api(
83
path = '/statuses/{id}/retweeted_by/ids.json',
85
allowed_param = ['id', 'count', 'page'],
89
""" statuses/retweeted_by_me """
90
retweeted_by_me = bind_api(
91
path = '/statuses/retweeted_by_me.json',
92
payload_type = 'status', payload_list = True,
93
allowed_param = ['since_id', 'max_id', 'count', 'page'],
97
""" statuses/retweeted_to_me """
98
retweeted_to_me = bind_api(
99
path = '/statuses/retweeted_to_me.json',
100
payload_type = 'status', payload_list = True,
101
allowed_param = ['since_id', 'max_id', 'count', 'page'],
105
""" statuses/retweets_of_me """
106
retweets_of_me = bind_api(
107
path = '/statuses/retweets_of_me.json',
108
payload_type = 'status', payload_list = True,
109
allowed_param = ['since_id', 'max_id', 'count', 'page'],
113
""" statuses/show """
114
get_status = bind_api(
115
path = '/statuses/show.json',
116
payload_type = 'status',
117
allowed_param = ['id']
120
""" statuses/update """
121
update_status = bind_api(
122
path = '/statuses/update.json',
124
payload_type = 'status',
125
allowed_param = ['status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id'],
129
""" statuses/destroy """
130
destroy_status = bind_api(
131
path = '/statuses/destroy.json',
133
payload_type = 'status',
134
allowed_param = ['id'],
138
""" statuses/retweet """
140
path = '/statuses/retweet/{id}.json',
142
payload_type = 'status',
143
allowed_param = ['id'],
147
""" statuses/retweets """
149
path = '/statuses/retweets/{id}.json',
150
payload_type = 'status', payload_list = True,
151
allowed_param = ['id', 'count'],
157
path = '/users/show.json',
158
payload_type = 'user',
159
allowed_param = ['id', 'user_id', 'screen_name']
162
""" Perform bulk look up of users from user ID or screenname """
163
def lookup_users(self, user_ids=None, screen_names=None):
164
return self._lookup_users(list_to_csv(user_ids), list_to_csv(screen_names))
166
_lookup_users = bind_api(
167
path = '/users/lookup.json',
168
payload_type = 'user', payload_list = True,
169
allowed_param = ['user_id', 'screen_name'],
173
""" Get the authenticated user """
175
return self.get_user(screen_name=self.auth.get_username())
178
search_users = bind_api(
179
path = '/users/search.json',
180
payload_type = 'user', payload_list = True,
182
allowed_param = ['q', 'per_page', 'page']
185
""" statuses/friends """
187
path = '/statuses/friends.json',
188
payload_type = 'user', payload_list = True,
189
allowed_param = ['id', 'user_id', 'screen_name', 'page', 'cursor']
192
""" statuses/followers """
193
followers = bind_api(
194
path = '/statuses/followers.json',
195
payload_type = 'user', payload_list = True,
196
allowed_param = ['id', 'user_id', 'screen_name', 'page', 'cursor']
199
""" direct_messages """
200
direct_messages = bind_api(
201
path = '/direct_messages.json',
202
payload_type = 'direct_message', payload_list = True,
203
allowed_param = ['since_id', 'max_id', 'count', 'page'],
207
""" direct_messages/sent """
208
sent_direct_messages = bind_api(
209
path = '/direct_messages/sent.json',
210
payload_type = 'direct_message', payload_list = True,
211
allowed_param = ['since_id', 'max_id', 'count', 'page'],
215
""" direct_messages/new """
216
send_direct_message = bind_api(
217
path = '/direct_messages/new.json',
219
payload_type = 'direct_message',
220
allowed_param = ['user', 'screen_name', 'user_id', 'text'],
224
""" direct_messages/destroy """
225
destroy_direct_message = bind_api(
226
path = '/direct_messages/destroy.json',
228
payload_type = 'direct_message',
229
allowed_param = ['id'],
233
""" friendships/create """
234
create_friendship = bind_api(
235
path = '/friendships/create.json',
237
payload_type = 'user',
238
allowed_param = ['id', 'user_id', 'screen_name', 'follow'],
242
""" friendships/destroy """
243
destroy_friendship = bind_api(
244
path = '/friendships/destroy.json',
246
payload_type = 'user',
247
allowed_param = ['id', 'user_id', 'screen_name'],
251
""" friendships/exists """
252
exists_friendship = bind_api(
253
path = '/friendships/exists.json',
254
payload_type = 'json',
255
allowed_param = ['user_a', 'user_b']
258
""" friendships/show """
259
show_friendship = bind_api(
260
path = '/friendships/show.json',
261
payload_type = 'friendship',
262
allowed_param = ['source_id', 'source_screen_name',
263
'target_id', 'target_screen_name']
267
friends_ids = bind_api(
268
path = '/friends/ids.json',
269
payload_type = 'ids',
270
allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
273
""" friendships/incoming """
274
friendships_incoming = bind_api(
275
path = '/friendships/incoming.json',
276
payload_type = 'ids',
277
allowed_param = ['cursor']
280
""" friendships/outgoing"""
281
friendships_outgoing = bind_api(
282
path = '/friendships/outgoing.json',
283
payload_type = 'ids',
284
allowed_param = ['cursor']
287
""" followers/ids """
288
followers_ids = bind_api(
289
path = '/followers/ids.json',
290
payload_type = 'ids',
291
allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
294
""" account/verify_credentials """
295
def verify_credentials(self):
298
path = '/account/verify_credentials.json',
299
payload_type = 'user',
305
""" account/rate_limit_status """
306
rate_limit_status = bind_api(
307
path = '/account/rate_limit_status.json',
308
payload_type = 'json'
311
""" account/update_delivery_device """
312
set_delivery_device = bind_api(
313
path = '/account/update_delivery_device.json',
315
allowed_param = ['device'],
316
payload_type = 'user',
320
""" account/update_profile_colors """
321
update_profile_colors = bind_api(
322
path = '/account/update_profile_colors.json',
324
payload_type = 'user',
325
allowed_param = ['profile_background_color', 'profile_text_color',
326
'profile_link_color', 'profile_sidebar_fill_color',
327
'profile_sidebar_border_color'],
331
""" account/update_profile_image """
332
def update_profile_image(self, filename):
333
headers, post_data = API._pack_image(filename, 700)
335
path = '/account/update_profile_image.json',
337
payload_type = 'user',
339
)(self, post_data=post_data, headers=headers)
341
""" account/update_profile_background_image """
342
def update_profile_background_image(self, filename, *args, **kargs):
343
headers, post_data = API._pack_image(filename, 800)
345
path = '/account/update_profile_background_image.json',
347
payload_type = 'user',
348
allowed_param = ['tile'],
350
)(self, post_data=post_data, headers=headers)
352
""" account/update_profile """
353
update_profile = bind_api(
354
path = '/account/update_profile.json',
356
payload_type = 'user',
357
allowed_param = ['name', 'url', 'location', 'description'],
362
favorites = bind_api(
363
path = '/favorites.json',
364
payload_type = 'status', payload_list = True,
365
allowed_param = ['id', 'page']
368
""" favorites/create """
369
create_favorite = bind_api(
370
path = '/favorites/create/{id}.json',
372
payload_type = 'status',
373
allowed_param = ['id'],
377
""" favorites/destroy """
378
destroy_favorite = bind_api(
379
path = '/favorites/destroy/{id}.json',
381
payload_type = 'status',
382
allowed_param = ['id'],
386
""" notifications/follow """
387
enable_notifications = bind_api(
388
path = '/notifications/follow.json',
390
payload_type = 'user',
391
allowed_param = ['id', 'user_id', 'screen_name'],
395
""" notifications/leave """
396
disable_notifications = bind_api(
397
path = '/notifications/leave.json',
399
payload_type = 'user',
400
allowed_param = ['id', 'user_id', 'screen_name'],
404
""" blocks/create """
405
create_block = bind_api(
406
path = '/blocks/create.json',
408
payload_type = 'user',
409
allowed_param = ['id', 'user_id', 'screen_name'],
413
""" blocks/destroy """
414
destroy_block = bind_api(
415
path = '/blocks/destroy.json',
417
payload_type = 'user',
418
allowed_param = ['id', 'user_id', 'screen_name'],
422
""" blocks/exists """
423
def exists_block(self, *args, **kargs):
426
path = '/blocks/exists.json',
427
allowed_param = ['id', 'user_id', 'screen_name'],
429
)(self, *args, **kargs)
434
""" blocks/blocking """
436
path = '/blocks/blocking.json',
437
payload_type = 'user', payload_list = True,
438
allowed_param = ['page'],
442
""" blocks/blocking/ids """
443
blocks_ids = bind_api(
444
path = '/blocks/blocking/ids.json',
445
payload_type = 'json',
450
report_spam = bind_api(
451
path = '/report_spam.json',
453
payload_type = 'user',
454
allowed_param = ['id', 'user_id', 'screen_name'],
458
""" saved_searches """
459
saved_searches = bind_api(
460
path = '/saved_searches.json',
461
payload_type = 'saved_search', payload_list = True,
465
""" saved_searches/show """
466
get_saved_search = bind_api(
467
path = '/saved_searches/show/{id}.json',
468
payload_type = 'saved_search',
469
allowed_param = ['id'],
473
""" saved_searches/create """
474
create_saved_search = bind_api(
475
path = '/saved_searches/create.json',
477
payload_type = 'saved_search',
478
allowed_param = ['query'],
482
""" saved_searches/destroy """
483
destroy_saved_search = bind_api(
484
path = '/saved_searches/destroy/{id}.json',
486
payload_type = 'saved_search',
487
allowed_param = ['id'],
495
path = '/help/test.json',
501
def create_list(self, *args, **kargs):
503
path = '/%s/lists.json' % self.auth.get_username(),
505
payload_type = 'list',
506
allowed_param = ['name', 'mode', 'description'],
508
)(self, *args, **kargs)
510
def destroy_list(self, slug):
512
path = '/%s/lists/%s.json' % (self.auth.get_username(), slug),
514
payload_type = 'list',
518
def update_list(self, slug, *args, **kargs):
520
path = '/%s/lists/%s.json' % (self.auth.get_username(), slug),
522
payload_type = 'list',
523
allowed_param = ['name', 'mode', 'description'],
525
)(self, *args, **kargs)
528
path = '/{user}/lists.json',
529
payload_type = 'list', payload_list = True,
530
allowed_param = ['user', 'cursor'],
534
lists_memberships = bind_api(
535
path = '/{user}/lists/memberships.json',
536
payload_type = 'list', payload_list = True,
537
allowed_param = ['user', 'cursor'],
541
lists_subscriptions = bind_api(
542
path = '/{user}/lists/subscriptions.json',
543
payload_type = 'list', payload_list = True,
544
allowed_param = ['user', 'cursor'],
548
list_timeline = bind_api(
549
path = '/{owner}/lists/{slug}/statuses.json',
550
payload_type = 'status', payload_list = True,
551
allowed_param = ['owner', 'slug', 'since_id', 'max_id', 'per_page', 'page']
555
path = '/{owner}/lists/{slug}.json',
556
payload_type = 'list',
557
allowed_param = ['owner', 'slug']
560
def add_list_member(self, slug, *args, **kargs):
562
path = '/%s/%s/members.json' % (self.auth.get_username(), slug),
564
payload_type = 'list',
565
allowed_param = ['id'],
567
)(self, *args, **kargs)
569
def remove_list_member(self, slug, *args, **kargs):
571
path = '/%s/%s/members.json' % (self.auth.get_username(), slug),
573
payload_type = 'list',
574
allowed_param = ['id'],
576
)(self, *args, **kargs)
578
list_members = bind_api(
579
path = '/{owner}/{slug}/members.json',
580
payload_type = 'user', payload_list = True,
581
allowed_param = ['owner', 'slug', 'cursor']
584
def is_list_member(self, owner, slug, user_id):
587
path = '/%s/%s/members/%s.json' % (owner, slug, user_id),
588
payload_type = 'user'
593
subscribe_list = bind_api(
594
path = '/{owner}/{slug}/subscribers.json',
596
payload_type = 'list',
597
allowed_param = ['owner', 'slug'],
601
unsubscribe_list = bind_api(
602
path = '/{owner}/{slug}/subscribers.json',
604
payload_type = 'list',
605
allowed_param = ['owner', 'slug'],
609
list_subscribers = bind_api(
610
path = '/{owner}/{slug}/subscribers.json',
611
payload_type = 'user', payload_list = True,
612
allowed_param = ['owner', 'slug', 'cursor']
615
def is_subscribed_list(self, owner, slug, user_id):
618
path = '/%s/%s/subscribers/%s.json' % (owner, slug, user_id),
619
payload_type = 'user'
624
""" trends/available """
625
trends_available = bind_api(
626
path = '/trends/available.json',
627
payload_type = 'json',
628
allowed_param = ['lat', 'long']
631
""" trends/location """
632
trends_location = bind_api(
633
path = '/trends/{woeid}.json',
634
payload_type = 'json',
635
allowed_param = ['woeid']
641
path = '/search.json',
642
payload_type = 'search_result', payload_list = True,
643
allowed_param = ['q', 'lang', 'locale', 'rpp', 'page', 'since_id', 'geocode', 'show_user', 'max_id', 'since', 'until', 'result_type']
645
search.pagination_mode = 'page'
649
path = '/trends.json',
650
payload_type = 'json'
653
""" trends/current """
654
trends_current = bind_api(
655
path = '/trends/current.json',
656
payload_type = 'json',
657
allowed_param = ['exclude']
661
trends_daily = bind_api(
662
path = '/trends/daily.json',
663
payload_type = 'json',
664
allowed_param = ['date', 'exclude']
667
""" trends/weekly """
668
trends_weekly = bind_api(
669
path = '/trends/weekly.json',
670
payload_type = 'json',
671
allowed_param = ['date', 'exclude']
674
""" geo/reverse_geocode """
675
reverse_geocode = bind_api(
676
path = '/geo/reverse_geocode.json',
677
payload_type = 'json',
678
allowed_param = ['lat', 'long', 'accuracy', 'granularity', 'max_results']
681
""" geo/nearby_places """
682
nearby_places = bind_api(
683
path = '/geo/nearby_places.json',
684
payload_type = 'json',
685
allowed_param = ['lat', 'long', 'ip', 'accuracy', 'granularity', 'max_results']
690
path = '/geo/id/{id}.json',
691
payload_type = 'json',
692
allowed_param = ['id']
695
""" Internal use only """
697
def _pack_image(filename, max_size):
698
"""Pack image from file into multipart-formdata post body"""
699
# image must be less than 700kb in size
701
if os.path.getsize(filename) > (max_size * 1024):
702
raise TweepError('File is too big, must be less than 700kb.')
704
raise TweepError('Unable to access file')
706
# image must be gif, jpeg, or png
707
file_type = mimetypes.guess_type(filename)
708
if file_type is None:
709
raise TweepError('Could not determine file type')
710
file_type = file_type[0]
711
if file_type not in ['image/gif', 'image/jpeg', 'image/png']:
712
raise TweepError('Invalid file type for image: %s' % file_type)
714
# build the mulitpart-formdata body
715
fp = open(filename, 'rb')
718
body.append('--' + BOUNDARY)
719
body.append('Content-Disposition: form-data; name="image"; filename="%s"' % filename)
720
body.append('Content-Type: %s' % file_type)
722
body.append(fp.read())
723
body.append('--' + BOUNDARY + '--')
726
body = '\r\n'.join(body)
730
'Content-Type': 'multipart/form-data; boundary=Tw3ePy',
731
'Content-Length': len(body)