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=True, api_root='/1.1', search_root='',
20 retry_count=0, retry_delay=0, retry_errors=None, timeout=60,
21 parser=None, compression=False):
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.compression = compression
30 self.retry_count = retry_count
31 self.retry_delay = retry_delay
32 self.retry_errors = retry_errors
33 self.timeout = timeout
34 self.parser = parser or ModelParser()
36 """ statuses/home_timeline """
37 home_timeline = bind_api(
38 path = '/statuses/home_timeline.json',
39 payload_type = 'status', payload_list = True,
40 allowed_param = ['since_id', 'max_id', 'count'],
44 """ statuses/user_timeline """
45 user_timeline = bind_api(
46 path = '/statuses/user_timeline.json',
47 payload_type = 'status', payload_list = True,
48 allowed_param = ['id', 'user_id', 'screen_name', 'since_id',
49 'max_id', 'count', 'include_rts']
52 """ statuses/mentions """
53 mentions_timeline = bind_api(
54 path = '/statuses/mentions_timeline.json',
55 payload_type = 'status', payload_list = True,
56 allowed_param = ['since_id', 'max_id', 'count'],
60 """/related_results/show/:id.format"""
61 related_results = bind_api(
62 path = '/related_results/show/{id}.json',
63 payload_type = 'relation', payload_list = True,
64 allowed_param = ['id'],
68 """ statuses/retweets_of_me """
69 retweets_of_me = bind_api(
70 path = '/statuses/retweets_of_me.json',
71 payload_type = 'status', payload_list = True,
72 allowed_param = ['since_id', 'max_id', 'count'],
77 get_status = bind_api(
78 path = '/statuses/show.json',
79 payload_type = 'status',
80 allowed_param = ['id']
83 """ statuses/update """
84 update_status = bind_api(
85 path = '/statuses/update.json',
87 payload_type = 'status',
88 allowed_param = ['status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id'],
92 """ statuses/update_with_media """
93 def update_with_media(self, filename, *args, **kwargs):
94 headers, post_data = API._pack_image(filename, 3072, form_field='media[]')
95 kwargs.update({'headers': headers, 'post_data': post_data})
98 path='/statuses/update_with_media.json',
100 payload_type='status',
102 'status', 'possibly_sensitive', 'in_reply_to_status_id', 'lat', 'long',
103 'place_id', 'display_coordinates'
106 )(self, *args, **kwargs)
108 """ statuses/destroy """
109 destroy_status = bind_api(
110 path = '/statuses/destroy/{id}.json',
112 payload_type = 'status',
113 allowed_param = ['id'],
117 """ statuses/retweet """
119 path = '/statuses/retweet/{id}.json',
121 payload_type = 'status',
122 allowed_param = ['id'],
126 """ statuses/retweets """
128 path = '/statuses/retweets/{id}.json',
129 payload_type = 'status', payload_list = True,
130 allowed_param = ['id', 'count'],
134 retweeters = bind_api(
135 path = '/statuses/retweeters/ids.json',
136 payload_type = 'ids',
137 allowed_param = ['id', 'cursor', 'stringify_ids']
142 path = '/users/show.json',
143 payload_type = 'user',
144 allowed_param = ['id', 'user_id', 'screen_name']
147 ''' statuses/oembed '''
148 get_oembed = bind_api(
149 path = '/statuses/oembed.json',
150 payload_type = 'json',
151 allowed_param = ['id', 'url', 'maxwidth', 'hide_media', 'omit_script', 'align', 'related', 'lang']
154 """ Perform bulk look up of users from user ID or screenname """
155 def lookup_users(self, user_ids=None, screen_names=None):
156 return self._lookup_users(list_to_csv(user_ids), list_to_csv(screen_names))
158 _lookup_users = bind_api(
159 path = '/users/lookup.json',
160 payload_type = 'user', payload_list = True,
161 allowed_param = ['user_id', 'screen_name'],
164 """ Get the authenticated user """
166 return self.get_user(screen_name=self.auth.get_username())
169 search_users = bind_api(
170 path = '/users/search.json',
171 payload_type = 'user', payload_list = True,
173 allowed_param = ['q', 'count', 'page']
176 """ users/suggestions/:slug """
177 suggested_users = bind_api(
178 path = '/users/suggestions/{slug}.json',
179 payload_type = 'user', payload_list = True,
181 allowed_param = ['slug', 'lang']
184 """ users/suggestions """
185 suggested_categories = bind_api(
186 path = '/users/suggestions.json',
187 payload_type = 'category', payload_list = True,
188 allowed_param = ['lang'],
192 """ users/suggestions/:slug/members """
193 suggested_users_tweets = bind_api(
194 path = '/users/suggestions/{slug}/members.json',
195 payload_type = 'status', payload_list = True,
196 allowed_param = ['slug'],
200 """ direct_messages """
201 direct_messages = bind_api(
202 path = '/direct_messages.json',
203 payload_type = 'direct_message', payload_list = True,
204 allowed_param = ['since_id', 'max_id', 'count'],
208 """ direct_messages/show """
209 get_direct_message = bind_api(
210 path = '/direct_messages/show/{id}.json',
211 payload_type = 'direct_message',
212 allowed_param = ['id'],
216 """ direct_messages/sent """
217 sent_direct_messages = bind_api(
218 path = '/direct_messages/sent.json',
219 payload_type = 'direct_message', payload_list = True,
220 allowed_param = ['since_id', 'max_id', 'count', 'page'],
224 """ direct_messages/new """
225 send_direct_message = bind_api(
226 path = '/direct_messages/new.json',
228 payload_type = 'direct_message',
229 allowed_param = ['user', 'screen_name', 'user_id', 'text'],
233 """ direct_messages/destroy """
234 destroy_direct_message = bind_api(
235 path = '/direct_messages/destroy.json',
237 payload_type = 'direct_message',
238 allowed_param = ['id'],
242 """ friendships/create """
243 create_friendship = bind_api(
244 path = '/friendships/create.json',
246 payload_type = 'user',
247 allowed_param = ['id', 'user_id', 'screen_name', 'follow'],
251 """ friendships/destroy """
252 destroy_friendship = bind_api(
253 path = '/friendships/destroy.json',
255 payload_type = 'user',
256 allowed_param = ['id', 'user_id', 'screen_name'],
260 """ friendships/show """
261 show_friendship = bind_api(
262 path = '/friendships/show.json',
263 payload_type = 'friendship',
264 allowed_param = ['source_id', 'source_screen_name',
265 'target_id', 'target_screen_name']
268 """ Perform bulk look up of friendships from user ID or screenname """
269 def lookup_friendships(self, user_ids=None, screen_names=None):
270 return self._lookup_friendships(list_to_csv(user_ids), list_to_csv(screen_names))
272 _lookup_friendships = bind_api(
273 path = '/friendships/lookup.json',
274 payload_type = 'relationship', payload_list = True,
275 allowed_param = ['user_id', 'screen_name'],
281 friends_ids = bind_api(
282 path = '/friends/ids.json',
283 payload_type = 'ids',
284 allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
289 path = '/friends/list.json',
290 payload_type = 'user', payload_list = True,
291 allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
294 """ friendships/incoming """
295 friendships_incoming = bind_api(
296 path = '/friendships/incoming.json',
297 payload_type = 'ids',
298 allowed_param = ['cursor']
301 """ friendships/outgoing"""
302 friendships_outgoing = bind_api(
303 path = '/friendships/outgoing.json',
304 payload_type = 'ids',
305 allowed_param = ['cursor']
308 """ followers/ids """
309 followers_ids = bind_api(
310 path = '/followers/ids.json',
311 payload_type = 'ids',
312 allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
315 """ followers/list """
316 followers = bind_api(
317 path = '/followers/list.json',
318 payload_type = 'user', payload_list = True,
319 allowed_param = ['id', 'user_id', 'screen_name', 'cursor', 'count',
320 'skip_status', 'include_user_entities']
323 """ account/verify_credentials """
324 def verify_credentials(self, **kargs):
327 path = '/account/verify_credentials.json',
328 payload_type = 'user',
330 allowed_param = ['include_entities', 'skip_status'],
332 except TweepError as e:
333 if e.response and e.response.status == 401:
337 """ account/rate_limit_status """
338 rate_limit_status = bind_api(
339 path = '/application/rate_limit_status.json',
340 payload_type = 'json',
341 allowed_param = ['resources'],
345 """ account/update_delivery_device """
346 set_delivery_device = bind_api(
347 path = '/account/update_delivery_device.json',
349 allowed_param = ['device'],
350 payload_type = 'user',
354 """ account/update_profile_colors """
355 update_profile_colors = bind_api(
356 path = '/account/update_profile_colors.json',
358 payload_type = 'user',
359 allowed_param = ['profile_background_color', 'profile_text_color',
360 'profile_link_color', 'profile_sidebar_fill_color',
361 'profile_sidebar_border_color'],
365 """ account/update_profile_image """
366 def update_profile_image(self, filename):
367 headers, post_data = API._pack_image(filename, 700)
369 path = '/account/update_profile_image.json',
371 payload_type = 'user',
373 )(self, post_data=post_data, headers=headers)
375 """ account/update_profile_background_image """
376 def update_profile_background_image(self, filename, *args, **kargs):
377 headers, post_data = API._pack_image(filename, 800)
379 path = '/account/update_profile_background_image.json',
381 payload_type = 'user',
382 allowed_param = ['tile'],
384 )(self, post_data=post_data, headers=headers)
386 """ account/update_profile_banner """
387 def update_profile_banner(self, filename, *args, **kargs):
388 headers, post_data = API._pack_image(filename, 700, form_field="banner")
390 path = '/account/update_profile_banner.json',
392 allowed_param = ['width', 'height', 'offset_left', 'offset_right'],
394 )(self, post_data=post_data, headers=headers)
397 """ account/update_profile """
398 update_profile = bind_api(
399 path = '/account/update_profile.json',
401 payload_type = 'user',
402 allowed_param = ['name', 'url', 'location', 'description'],
407 favorites = bind_api(
408 path = '/favorites/list.json',
409 payload_type = 'status', payload_list = True,
410 allowed_param = ['screen_name', 'user_id', 'max_id', 'count', 'since_id', 'max_id']
413 """ favorites/create """
414 create_favorite = bind_api(
415 path = '/favorites/create.json',
417 payload_type = 'status',
418 allowed_param = ['id'],
422 """ favorites/destroy """
423 destroy_favorite = bind_api(
424 path = '/favorites/destroy.json',
426 payload_type = 'status',
427 allowed_param = ['id'],
431 """ blocks/create """
432 create_block = bind_api(
433 path = '/blocks/create.json',
435 payload_type = 'user',
436 allowed_param = ['id', 'user_id', 'screen_name'],
440 """ blocks/destroy """
441 destroy_block = bind_api(
442 path = '/blocks/destroy.json',
444 payload_type = 'user',
445 allowed_param = ['id', 'user_id', 'screen_name'],
449 """ blocks/blocking """
451 path = '/blocks/list.json',
452 payload_type = 'user', payload_list = True,
453 allowed_param = ['cursor'],
457 """ blocks/blocking/ids """
458 blocks_ids = bind_api(
459 path = '/blocks/ids.json',
460 payload_type = 'json',
465 report_spam = bind_api(
466 path = '/users/report_spam.json',
468 payload_type = 'user',
469 allowed_param = ['user_id', 'screen_name'],
473 """ saved_searches """
474 saved_searches = bind_api(
475 path = '/saved_searches/list.json',
476 payload_type = 'saved_search', payload_list = True,
480 """ saved_searches/show """
481 get_saved_search = bind_api(
482 path = '/saved_searches/show/{id}.json',
483 payload_type = 'saved_search',
484 allowed_param = ['id'],
488 """ saved_searches/create """
489 create_saved_search = bind_api(
490 path = '/saved_searches/create.json',
492 payload_type = 'saved_search',
493 allowed_param = ['query'],
497 """ saved_searches/destroy """
498 destroy_saved_search = bind_api(
499 path = '/saved_searches/destroy/{id}.json',
501 payload_type = 'saved_search',
502 allowed_param = ['id'],
506 create_list = bind_api(
507 path = '/lists/create.json',
509 payload_type = 'list',
510 allowed_param = ['name', 'mode', 'description'],
514 destroy_list = bind_api(
515 path = '/lists/destroy.json',
517 payload_type = 'list',
518 allowed_param = ['owner_screen_name', 'owner_id', 'list_id', 'slug'],
522 update_list = bind_api(
523 path = '/lists/update.json',
525 payload_type = 'list',
526 allowed_param = ['list_id', 'slug', 'name', 'mode', 'description', 'owner_screen_name', 'owner_id'],
530 lists_all = bind_api(
531 path = '/lists/list.json',
532 payload_type = 'list', payload_list = True,
533 allowed_param = ['screen_name', 'user_id'],
537 lists_memberships = bind_api(
538 path = '/lists/memberships.json',
539 payload_type = 'list', payload_list = True,
540 allowed_param = ['screen_name', 'user_id', 'filter_to_owned_lists', 'cursor'],
544 lists_subscriptions = bind_api(
545 path = '/lists/subscriptions.json',
546 payload_type = 'list', payload_list = True,
547 allowed_param = ['screen_name', 'user_id', 'cursor'],
551 list_timeline = bind_api(
552 path = '/lists/statuses.json',
553 payload_type = 'status', payload_list = True,
554 allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id', 'since_id', 'max_id', 'count', 'include_rts']
558 path = '/lists/show.json',
559 payload_type = 'list',
560 allowed_param = ['owner_screen_name', 'owner_id', 'slug', 'list_id']
563 add_list_member = bind_api(
564 path = '/lists/members/create.json',
566 payload_type = 'list',
567 allowed_param = ['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
571 remove_list_member = bind_api(
572 path = '/lists/members/destroy.json',
574 payload_type = 'list',
575 allowed_param = ['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
579 list_members = bind_api(
580 path = '/lists/members.json',
581 payload_type = 'user', payload_list = True,
582 allowed_param = ['owner_screen_name', 'slug', 'list_id', 'owner_id', 'cursor']
585 show_list_member = bind_api(
586 path = '/lists/members/show.json',
587 payload_type = 'user',
588 allowed_param = ['list_id', 'slug', 'user_id', 'screen_name', 'owner_screen_name', 'owner_id']
591 subscribe_list = bind_api(
592 path = '/lists/subscribers/create.json',
594 payload_type = 'list',
595 allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id'],
599 unsubscribe_list = bind_api(
600 path = '/lists/subscribers/destroy.json',
602 payload_type = 'list',
603 allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id'],
607 list_subscribers = bind_api(
608 path = '/lists/subscribers.json',
609 payload_type = 'user', payload_list = True,
610 allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id', 'cursor']
613 show_list_subscriber = bind_api(
614 path = '/lists/subscribers/show.json',
615 payload_type = 'user',
616 allowed_param = ['owner_screen_name', 'slug', 'screen_name', 'owner_id', 'list_id', 'user_id']
619 """ trends/available """
620 trends_available = bind_api(
621 path = '/trends/available.json',
622 payload_type = 'json'
625 trends_place = bind_api(
626 path = '/trends/place.json',
627 payload_type = 'json',
628 allowed_param = ['id', 'exclude']
631 trends_closest = bind_api(
632 path = '/trends/closest.json',
633 payload_type = 'json',
634 allowed_param = ['lat', 'long']
639 path = '/search/tweets.json',
640 payload_type = 'search_results',
641 allowed_param = ['q', 'lang', 'locale', 'since_id', 'geocode', 'max_id', 'since', 'until', 'result_type', 'count', 'include_entities', 'from', 'to', 'source']
645 trends_daily = bind_api(
646 path = '/trends/daily.json',
647 payload_type = 'json',
648 allowed_param = ['date', 'exclude']
651 """ trends/weekly """
652 trends_weekly = bind_api(
653 path = '/trends/weekly.json',
654 payload_type = 'json',
655 allowed_param = ['date', 'exclude']
658 """ geo/reverse_geocode """
659 reverse_geocode = bind_api(
660 path = '/geo/reverse_geocode.json',
661 payload_type = 'place', payload_list = True,
662 allowed_param = ['lat', 'long', 'accuracy', 'granularity', 'max_results']
667 path = '/geo/id/{id}.json',
668 payload_type = 'place',
669 allowed_param = ['id']
673 geo_search = bind_api(
674 path = '/geo/search.json',
675 payload_type = 'place', payload_list = True,
676 allowed_param = ['lat', 'long', 'query', 'ip', 'granularity', 'accuracy', 'max_results', 'contained_within']
679 """ geo/similar_places """
680 geo_similar_places = bind_api(
681 path = '/geo/similar_places.json',
682 payload_type = 'place', payload_list = True,
683 allowed_param = ['lat', 'long', 'name', 'contained_within']
686 """ help/languages.json """
687 supported_languages = bind_api(
688 path = '/help/languages.json',
689 payload_type = 'json',
693 """ help/configuration """
694 configuration = bind_api(
695 path = '/help/configuration.json',
696 payload_type = 'json',
700 """ Internal use only """
702 def _pack_image(filename, max_size, form_field="image"):
703 """Pack image from file into multipart-formdata post body"""
704 # image must be less than 700kb in size
706 if os.path.getsize(filename) > (max_size * 1024):
707 raise TweepError('File is too big, must be less than 700kb.')
709 raise TweepError('Unable to access file')
711 # image must be gif, jpeg, or png
712 file_type = mimetypes.guess_type(filename)
713 if file_type is None:
714 raise TweepError('Could not determine file type')
715 file_type = file_type[0]
716 if file_type not in ['image/gif', 'image/jpeg', 'image/png']:
717 raise TweepError('Invalid file type for image: %s' % file_type)
719 # build the mulitpart-formdata body
720 fp = open(filename, 'rb')
723 body.append('--' + BOUNDARY)
724 body.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (form_field, filename))
725 body.append('Content-Type: %s' % file_type)
727 body.append(fp.read())
728 body.append('--' + BOUNDARY + '--')
731 body = '\r\n'.join(body)
735 'Content-Type': 'multipart/form-data; boundary=Tw3ePy',
736 'Content-Length': str(len(body))