Changed everything to ASCII. I'm worried we'll lose the forest for the \u1f332
[twitter-api-cdsw-solutions] / tweepy / api.py
1 # Tweepy
2 # Copyright 2009-2010 Joshua Roesslein
3 # See LICENSE for details.
4
5 import os
6 import mimetypes
7
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
12
13
14 class API(object):
15     """Twitter API"""
16
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
23         self.host = host
24         self.search_host = search_host
25         self.api_root = api_root
26         self.search_root = search_root
27         self.cache = cache
28         self.secure = secure
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()
35
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'],
41         require_auth = True
42     )
43
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']
50     )
51
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'],
57         require_auth = True
58     )
59
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'],
65         require_auth = False
66     )
67
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'],
73         require_auth = True
74     )
75
76     """ statuses/show """
77     get_status = bind_api(
78         path = '/statuses/show.json',
79         payload_type = 'status',
80         allowed_param = ['id']
81     )
82
83     """ statuses/update """
84     update_status = bind_api(
85         path = '/statuses/update.json',
86         method = 'POST',
87         payload_type = 'status',
88         allowed_param = ['status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id'],
89         require_auth = True
90     )
91
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})
96
97         return bind_api(
98             path='/statuses/update_with_media.json',
99             method = 'POST',
100             payload_type='status',
101             allowed_param = [
102                 'status', 'possibly_sensitive', 'in_reply_to_status_id', 'lat', 'long',
103                 'place_id', 'display_coordinates'
104             ],
105             require_auth=True
106         )(self, *args, **kwargs)
107
108     """ statuses/destroy """
109     destroy_status = bind_api(
110         path = '/statuses/destroy/{id}.json',
111         method = 'POST',
112         payload_type = 'status',
113         allowed_param = ['id'],
114         require_auth = True
115     )
116
117     """ statuses/retweet """
118     retweet = bind_api(
119         path = '/statuses/retweet/{id}.json',
120         method = 'POST',
121         payload_type = 'status',
122         allowed_param = ['id'],
123         require_auth = True
124     )
125
126     """ statuses/retweets """
127     retweets = bind_api(
128         path = '/statuses/retweets/{id}.json',
129         payload_type = 'status', payload_list = True,
130         allowed_param = ['id', 'count'],
131         require_auth = True
132     )
133
134     retweeters = bind_api(
135         path = '/statuses/retweeters/ids.json',
136         payload_type = 'ids',
137         allowed_param = ['id', 'cursor', 'stringify_ids']
138     )
139
140     """ users/show """
141     get_user = bind_api(
142         path = '/users/show.json',
143         payload_type = 'user',
144         allowed_param = ['id', 'user_id', 'screen_name']
145     )
146
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']
152     )
153
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))
157
158     _lookup_users = bind_api(
159         path = '/users/lookup.json',
160         payload_type = 'user', payload_list = True,
161         allowed_param = ['user_id', 'screen_name'],
162     )
163
164     """ Get the authenticated user """
165     def me(self):
166         return self.get_user(screen_name=self.auth.get_username())
167
168     """ users/search """
169     search_users = bind_api(
170         path = '/users/search.json',
171         payload_type = 'user', payload_list = True,
172         require_auth = True,
173         allowed_param = ['q', 'count', 'page']
174     )
175
176     """ users/suggestions/:slug """
177     suggested_users = bind_api(
178         path = '/users/suggestions/{slug}.json',
179         payload_type = 'user', payload_list = True,
180         require_auth = True,
181         allowed_param = ['slug', 'lang']
182     )
183
184     """ users/suggestions """
185     suggested_categories = bind_api(
186         path = '/users/suggestions.json',
187         payload_type = 'category', payload_list = True,
188         allowed_param = ['lang'],
189         require_auth = True
190     )
191
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'],
197         require_auth = True
198     )
199
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'],
205         require_auth = True
206     )
207
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'],
213         require_auth = True
214     )
215
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'],
221         require_auth = True
222     )
223
224     """ direct_messages/new """
225     send_direct_message = bind_api(
226         path = '/direct_messages/new.json',
227         method = 'POST',
228         payload_type = 'direct_message',
229         allowed_param = ['user', 'screen_name', 'user_id', 'text'],
230         require_auth = True
231     )
232
233     """ direct_messages/destroy """
234     destroy_direct_message = bind_api(
235         path = '/direct_messages/destroy.json',
236         method = 'DELETE',
237         payload_type = 'direct_message',
238         allowed_param = ['id'],
239         require_auth = True
240     )
241
242     """ friendships/create """
243     create_friendship = bind_api(
244         path = '/friendships/create.json',
245         method = 'POST',
246         payload_type = 'user',
247         allowed_param = ['id', 'user_id', 'screen_name', 'follow'],
248         require_auth = True
249     )
250
251     """ friendships/destroy """
252     destroy_friendship = bind_api(
253         path = '/friendships/destroy.json',
254         method = 'DELETE',
255         payload_type = 'user',
256         allowed_param = ['id', 'user_id', 'screen_name'],
257         require_auth = True
258     )
259
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']
266     )
267
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))
271
272     _lookup_friendships = bind_api(
273         path = '/friendships/lookup.json',
274         payload_type = 'relationship', payload_list = True,
275         allowed_param = ['user_id', 'screen_name'],
276         require_auth = True
277     )
278
279
280     """ friends/ids """
281     friends_ids = bind_api(
282         path = '/friends/ids.json',
283         payload_type = 'ids',
284         allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
285     )
286
287     """ friends/list """
288     friends = bind_api(
289         path = '/friends/list.json',
290         payload_type = 'user', payload_list = True,
291         allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
292     )
293
294     """ friendships/incoming """
295     friendships_incoming = bind_api(
296         path = '/friendships/incoming.json',
297         payload_type = 'ids',
298         allowed_param = ['cursor']
299     )
300
301     """ friendships/outgoing"""
302     friendships_outgoing = bind_api(
303         path = '/friendships/outgoing.json',
304         payload_type = 'ids',
305         allowed_param = ['cursor']
306     )
307
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']
313     )
314
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']
321     )
322
323     """ account/verify_credentials """
324     def verify_credentials(self, **kargs):
325         try:
326             return bind_api(
327                 path = '/account/verify_credentials.json',
328                 payload_type = 'user',
329                 require_auth = True,
330                 allowed_param = ['include_entities', 'skip_status'],
331             )(self, **kargs)
332         except TweepError as e:
333             if e.response and e.response.status == 401:
334                 return False
335             raise
336
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'],
342         use_cache = False
343     )
344
345     """ account/update_delivery_device """
346     set_delivery_device = bind_api(
347         path = '/account/update_delivery_device.json',
348         method = 'POST',
349         allowed_param = ['device'],
350         payload_type = 'user',
351         require_auth = True
352     )
353
354     """ account/update_profile_colors """
355     update_profile_colors = bind_api(
356         path = '/account/update_profile_colors.json',
357         method = 'POST',
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'],
362         require_auth = True
363     )
364
365     """ account/update_profile_image """
366     def update_profile_image(self, filename):
367         headers, post_data = API._pack_image(filename, 700)
368         return bind_api(
369             path = '/account/update_profile_image.json',
370             method = 'POST',
371             payload_type = 'user',
372             require_auth = True
373         )(self, post_data=post_data, headers=headers)
374
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)
378         bind_api(
379             path = '/account/update_profile_background_image.json',
380             method = 'POST',
381             payload_type = 'user',
382             allowed_param = ['tile'],
383             require_auth = True
384         )(self, post_data=post_data, headers=headers)
385
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")
389         bind_api(
390             path = '/account/update_profile_banner.json',
391             method = 'POST',
392             allowed_param = ['width', 'height', 'offset_left', 'offset_right'],
393             require_auth = True
394         )(self, post_data=post_data, headers=headers)
395
396
397     """ account/update_profile """
398     update_profile = bind_api(
399         path = '/account/update_profile.json',
400         method = 'POST',
401         payload_type = 'user',
402         allowed_param = ['name', 'url', 'location', 'description'],
403         require_auth = True
404     )
405
406     """ favorites """
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']
411     )
412
413     """ favorites/create """
414     create_favorite = bind_api(
415         path = '/favorites/create.json',
416         method = 'POST',
417         payload_type = 'status',
418         allowed_param = ['id'],
419         require_auth = True
420     )
421
422     """ favorites/destroy """
423     destroy_favorite = bind_api(
424         path = '/favorites/destroy.json',
425         method = 'POST',
426         payload_type = 'status',
427         allowed_param = ['id'],
428         require_auth = True
429     )
430
431     """ blocks/create """
432     create_block = bind_api(
433         path = '/blocks/create.json',
434         method = 'POST',
435         payload_type = 'user',
436         allowed_param = ['id', 'user_id', 'screen_name'],
437         require_auth = True
438     )
439
440     """ blocks/destroy """
441     destroy_block = bind_api(
442         path = '/blocks/destroy.json',
443         method = 'DELETE',
444         payload_type = 'user',
445         allowed_param = ['id', 'user_id', 'screen_name'],
446         require_auth = True
447     )
448
449     """ blocks/blocking """
450     blocks = bind_api(
451         path = '/blocks/list.json',
452         payload_type = 'user', payload_list = True,
453         allowed_param = ['cursor'],
454         require_auth = True
455     )
456
457     """ blocks/blocking/ids """
458     blocks_ids = bind_api(
459         path = '/blocks/ids.json',
460         payload_type = 'json',
461         require_auth = True
462     )
463
464     """ report_spam """
465     report_spam = bind_api(
466         path = '/users/report_spam.json',
467         method = 'POST',
468         payload_type = 'user',
469         allowed_param = ['user_id', 'screen_name'],
470         require_auth = True
471     )
472
473     """ saved_searches """
474     saved_searches = bind_api(
475         path = '/saved_searches/list.json',
476         payload_type = 'saved_search', payload_list = True,
477         require_auth = True
478     )
479
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'],
485         require_auth = True
486     )
487
488     """ saved_searches/create """
489     create_saved_search = bind_api(
490         path = '/saved_searches/create.json',
491         method = 'POST',
492         payload_type = 'saved_search',
493         allowed_param = ['query'],
494         require_auth = True
495     )
496
497     """ saved_searches/destroy """
498     destroy_saved_search = bind_api(
499         path = '/saved_searches/destroy/{id}.json',
500         method = 'POST',
501         payload_type = 'saved_search',
502         allowed_param = ['id'],
503         require_auth = True
504     )
505
506     create_list = bind_api(
507         path = '/lists/create.json',
508         method = 'POST',
509         payload_type = 'list',
510         allowed_param = ['name', 'mode', 'description'],
511         require_auth = True
512     )
513
514     destroy_list = bind_api(
515         path = '/lists/destroy.json',
516         method = 'POST',
517         payload_type = 'list',
518         allowed_param = ['owner_screen_name', 'owner_id', 'list_id', 'slug'],
519         require_auth = True
520     )
521
522     update_list = bind_api(
523         path = '/lists/update.json',
524         method = 'POST',
525         payload_type = 'list',
526         allowed_param = ['list_id', 'slug', 'name', 'mode', 'description', 'owner_screen_name', 'owner_id'],
527         require_auth = True
528     )
529
530     lists_all = bind_api(
531         path = '/lists/list.json',
532         payload_type = 'list', payload_list = True,
533         allowed_param = ['screen_name', 'user_id'],
534         require_auth = True
535     )
536
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'],
541         require_auth = True
542     )
543
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'],
548         require_auth = True
549     )
550
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']
555     )
556
557     get_list = bind_api(
558         path = '/lists/show.json',
559         payload_type = 'list',
560         allowed_param = ['owner_screen_name', 'owner_id', 'slug', 'list_id']
561     )
562
563     add_list_member = bind_api(
564         path = '/lists/members/create.json',
565         method = 'POST',
566         payload_type = 'list',
567         allowed_param = ['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
568         require_auth = True
569     )
570
571     remove_list_member = bind_api(
572         path = '/lists/members/destroy.json',
573         method = 'POST',
574         payload_type = 'list',
575         allowed_param = ['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
576         require_auth = True
577     )
578
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']
583     )
584
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']
589     )
590
591     subscribe_list = bind_api(
592         path = '/lists/subscribers/create.json',
593         method = 'POST',
594         payload_type = 'list',
595         allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id'],
596         require_auth = True
597     )
598
599     unsubscribe_list = bind_api(
600         path = '/lists/subscribers/destroy.json',
601         method = 'POST',
602         payload_type = 'list',
603         allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id'],
604         require_auth = True
605     )
606
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']
611     )
612
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']
617     )
618
619     """ trends/available """
620     trends_available = bind_api(
621         path = '/trends/available.json',
622         payload_type = 'json'
623     )
624
625     trends_place = bind_api(
626         path = '/trends/place.json',
627         payload_type = 'json',
628         allowed_param = ['id', 'exclude']
629     )
630
631     trends_closest = bind_api(
632         path = '/trends/closest.json',
633         payload_type = 'json',
634         allowed_param = ['lat', 'long']
635     )
636
637     """ search """
638     search = bind_api(
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']
642     )
643
644     """ trends/daily """
645     trends_daily = bind_api(
646         path = '/trends/daily.json',
647         payload_type = 'json',
648         allowed_param = ['date', 'exclude']
649     )
650
651     """ trends/weekly """
652     trends_weekly = bind_api(
653         path = '/trends/weekly.json',
654         payload_type = 'json',
655         allowed_param = ['date', 'exclude']
656     )
657
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']
663     )
664
665     """ geo/id """
666     geo_id = bind_api(
667         path = '/geo/id/{id}.json',
668         payload_type = 'place',
669         allowed_param = ['id']
670     )
671
672     """ geo/search """
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']
677     )
678
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']
684     )
685
686     """ help/languages.json """
687     supported_languages = bind_api(
688         path = '/help/languages.json',
689         payload_type = 'json',
690         require_auth = True
691     )
692
693     """ help/configuration """
694     configuration = bind_api(
695         path = '/help/configuration.json',
696         payload_type = 'json',
697         require_auth = True
698     )
699
700     """ Internal use only """
701     @staticmethod
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
705         try:
706             if os.path.getsize(filename) > (max_size * 1024):
707                 raise TweepError('File is too big, must be less than 700kb.')
708         except os.error:
709             raise TweepError('Unable to access file')
710
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)
718
719         # build the mulitpart-formdata body
720         fp = open(filename, 'rb')
721         BOUNDARY = 'Tw3ePy'
722         body = []
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)
726         body.append('')
727         body.append(fp.read())
728         body.append('--' + BOUNDARY + '--')
729         body.append('')
730         fp.close()
731         body = '\r\n'.join(body)
732
733         # build headers
734         headers = {
735             'Content-Type': 'multipart/form-data; boundary=Tw3ePy',
736             'Content-Length': str(len(body))
737         }
738
739         return headers, body
740

Benjamin Mako Hill || Want to submit a patch?