api.py 25.8 KB
Newer Older
1
# Tweepy
2
3
# Copyright 2009-2010 Joshua Roesslein
# See LICENSE for details.
4

5
6
7
import os
import mimetypes

Josh Roesslein's avatar
Josh Roesslein committed
8
9
from tweepy.binder import bind_api
from tweepy.error import TweepError
10
from tweepy.parsers import ModelParser, Parser
11
from tweepy.utils import list_to_csv
12

Josh Roesslein's avatar
Josh Roesslein committed
13

14
class API(object):
Josh Roesslein's avatar
Josh Roesslein committed
15
16
    """Twitter API"""

17
18
    def __init__(self, auth_handler=None,
            host='api.twitter.com', search_host='search.twitter.com',
Joshua Roesslein's avatar
Joshua Roesslein committed
19
             cache=None, api_root='/1.1', search_root='',
20
            retry_count=0, retry_delay=0, retry_errors=None, timeout=60,
21
            parser=None, compression=False, wait_on_rate_limit=False,
Aaron Hill's avatar
Aaron Hill committed
22
            wait_on_rate_limit_notify=False, proxy=None):
Josh Roesslein's avatar
Josh Roesslein committed
23
        self.auth = auth_handler
Josh Roesslein's avatar
Josh Roesslein committed
24
        self.host = host
25
        self.search_host = search_host
Josh Roesslein's avatar
Josh Roesslein committed
26
        self.api_root = api_root
27
        self.search_root = search_root
Josh Roesslein's avatar
Josh Roesslein committed
28
        self.cache = cache
Mike's avatar
Mike committed
29
        self.compression = compression
30
31
        self.retry_count = retry_count
        self.retry_delay = retry_delay
32
        self.retry_errors = retry_errors
33
        self.timeout = timeout
34
        self.wait_on_rate_limit = wait_on_rate_limit
35
        self.wait_on_rate_limit_notify = wait_on_rate_limit_notify
36
        self.parser = parser or ModelParser()
Aaron Hill's avatar
Aaron Hill committed
37
38
39
        self.proxy = {}
        if proxy:
            self.proxy['https'] = proxy
Josh Roesslein's avatar
Josh Roesslein committed
40

41
42
43
44
45
46
47
48
49
50
        # Attempt to explain more clearly the parser argument requirements
        # https://github.com/tweepy/tweepy/issues/421
        #
        parser_type = Parser
        if not isinstance(self.parser, parser_type):
            raise TypeError(
                '"parser" argument has to be an instance of "{}". It is currently a {}.'.format(
                    parser_type.__name__, type(self.parser)
                )
            )
Josh Roesslein's avatar
Josh Roesslein committed
51

Ferenc Szalai's avatar
Ferenc Szalai committed
52
    """ statuses/home_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
53
54
    home_timeline = bind_api(
        path = '/statuses/home_timeline.json',
55
        payload_type = 'status', payload_list = True,
56
        allowed_param = ['since_id', 'max_id', 'count'],
Josh Roesslein's avatar
Josh Roesslein committed
57
58
59
        require_auth = True
    )

60
61
62
63
64
65
66
67
68
69
70
    def statuses_lookup(self, id, include_entities=None, trim_user=None, map=None):
        return self._statuses_lookup(list_to_csv(id), include_entities,
                trim_user, map)

    _statuses_lookup = bind_api(
        path = '/statuses/lookup.json',
        payload_type = 'status', payload_list = True,
        allowed_param = ['id', 'include_entities', 'trim_user', 'map'],
        require_auth = True
    )

71
    """ statuses/user_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
72
73
    user_timeline = bind_api(
        path = '/statuses/user_timeline.json',
74
        payload_type = 'status', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
75
        allowed_param = ['id', 'user_id', 'screen_name', 'since_id',
76
                          'max_id', 'count', 'include_rts']
Josh Roesslein's avatar
Josh Roesslein committed
77
78
    )

79
    """ statuses/mentions """
80
81
    mentions_timeline = bind_api(
        path = '/statuses/mentions_timeline.json',
82
        payload_type = 'status', payload_list = True,
83
        allowed_param = ['since_id', 'max_id', 'count'],
Josh Roesslein's avatar
Josh Roesslein committed
84
85
86
        require_auth = True
    )

Aaron Swartz's avatar
Aaron Swartz committed
87
88
89
90
91
92
    """/related_results/show/:id.format"""
    related_results = bind_api(
        path = '/related_results/show/{id}.json',
        payload_type = 'relation', payload_list = True,
        allowed_param = ['id'],
        require_auth = False
93
    )
94

95
    """ statuses/retweets_of_me """
Josh Roesslein's avatar
Josh Roesslein committed
96
97
    retweets_of_me = bind_api(
        path = '/statuses/retweets_of_me.json',
98
        payload_type = 'status', payload_list = True,
99
        allowed_param = ['since_id', 'max_id', 'count'],
Josh Roesslein's avatar
Josh Roesslein committed
100
101
102
        require_auth = True
    )

103
    """ statuses/show """
Josh Roesslein's avatar
Josh Roesslein committed
104
105
    get_status = bind_api(
        path = '/statuses/show.json',
106
        payload_type = 'status',
Josh Roesslein's avatar
Josh Roesslein committed
107
108
109
        allowed_param = ['id']
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
110
    """ statuses/update """
Josh Roesslein's avatar
Josh Roesslein committed
111
112
113
    update_status = bind_api(
        path = '/statuses/update.json',
        method = 'POST',
114
        payload_type = 'status',
Arudmin's avatar
Arudmin committed
115
        allowed_param = ['status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id', 'display_coordinates'],
Josh Roesslein's avatar
Josh Roesslein committed
116
117
118
        require_auth = True
    )

119
120
    """ statuses/update_with_media """
    def update_with_media(self, filename, *args, **kwargs):
121
122
        f = kwargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 3072, form_field='media[]', f=f)
123
124
125
126
127
128
129
130
131
132
133
134
135
        kwargs.update({'headers': headers, 'post_data': post_data})

        return bind_api(
            path='/statuses/update_with_media.json',
            method = 'POST',
            payload_type='status',
            allowed_param = [
                'status', 'possibly_sensitive', 'in_reply_to_status_id', 'lat', 'long',
                'place_id', 'display_coordinates'
            ],
            require_auth=True
        )(self, *args, **kwargs)

136
    """ statuses/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
137
    destroy_status = bind_api(
Joshua Roesslein's avatar
Joshua Roesslein committed
138
139
        path = '/statuses/destroy/{id}.json',
        method = 'POST',
140
        payload_type = 'status',
Josh Roesslein's avatar
Josh Roesslein committed
141
142
143
144
        allowed_param = ['id'],
        require_auth = True
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
145
    """ statuses/retweet """
146
147
148
    retweet = bind_api(
        path = '/statuses/retweet/{id}.json',
        method = 'POST',
149
        payload_type = 'status',
150
151
152
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
153

Ferenc Szalai's avatar
Ferenc Szalai committed
154
    """ statuses/retweets """
155
156
    retweets = bind_api(
        path = '/statuses/retweets/{id}.json',
157
        payload_type = 'status', payload_list = True,
158
159
160
        allowed_param = ['id', 'count'],
        require_auth = True
    )
161

Joshua Roesslein's avatar
Joshua Roesslein committed
162
163
164
165
166
167
    retweeters = bind_api(
        path = '/statuses/retweeters/ids.json',
        payload_type = 'ids',
        allowed_param = ['id', 'cursor', 'stringify_ids']
    )

168
    """ users/show """
Josh Roesslein's avatar
Josh Roesslein committed
169
170
    get_user = bind_api(
        path = '/users/show.json',
171
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
172
173
174
        allowed_param = ['id', 'user_id', 'screen_name']
    )

Miriam Sexton's avatar
Miriam Sexton committed
175
176
    ''' statuses/oembed '''
    get_oembed = bind_api(
Miriam Sexton's avatar
Miriam Sexton committed
177
        path = '/statuses/oembed.json',
Miriam Sexton's avatar
Miriam Sexton committed
178
179
180
181
        payload_type = 'json',
        allowed_param = ['id', 'url', 'maxwidth', 'hide_media', 'omit_script', 'align', 'related', 'lang']
    )

182
183
184
185
186
187
188
189
190
191
    """ 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))

    _lookup_users = bind_api(
        path = '/users/lookup.json',
        payload_type = 'user', payload_list = True,
        allowed_param = ['user_id', 'screen_name'],
    )

192
    """ Get the authenticated user """
Josh Roesslein's avatar
Josh Roesslein committed
193
    def me(self):
Josh Roesslein's avatar
Josh Roesslein committed
194
        return self.get_user(screen_name=self.auth.get_username())
Josh Roesslein's avatar
Josh Roesslein committed
195

196
197
198
    """ users/search """
    search_users = bind_api(
        path = '/users/search.json',
199
        payload_type = 'user', payload_list = True,
200
        require_auth = True,
201
        allowed_param = ['q', 'count', 'page']
202
203
    )

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    """ users/suggestions/:slug """
    suggested_users = bind_api(
        path = '/users/suggestions/{slug}.json',
        payload_type = 'user', payload_list = True,
        require_auth = True,
        allowed_param = ['slug', 'lang']
    )

    """ users/suggestions """
    suggested_categories = bind_api(
        path = '/users/suggestions.json',
        payload_type = 'category', payload_list = True,
        allowed_param = ['lang'],
        require_auth = True
    )

    """ users/suggestions/:slug/members """
    suggested_users_tweets = bind_api(
        path = '/users/suggestions/{slug}/members.json',
        payload_type = 'status', payload_list = True,
        allowed_param = ['slug'],
        require_auth = True
    )

228
    """ direct_messages """
Josh Roesslein's avatar
Josh Roesslein committed
229
230
    direct_messages = bind_api(
        path = '/direct_messages.json',
231
        payload_type = 'direct_message', payload_list = True,
232
        allowed_param = ['since_id', 'max_id', 'count'],
Josh Roesslein's avatar
Josh Roesslein committed
233
234
235
        require_auth = True
    )

236
237
238
239
240
241
242
243
    """ direct_messages/show """
    get_direct_message = bind_api(
        path = '/direct_messages/show/{id}.json',
        payload_type = 'direct_message',
        allowed_param = ['id'],
        require_auth = True
    )

244
    """ direct_messages/sent """
Josh Roesslein's avatar
Josh Roesslein committed
245
246
    sent_direct_messages = bind_api(
        path = '/direct_messages/sent.json',
247
        payload_type = 'direct_message', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
248
249
250
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )
251

252
    """ direct_messages/new """
Josh Roesslein's avatar
Josh Roesslein committed
253
254
    send_direct_message = bind_api(
        path = '/direct_messages/new.json',
255
        method = 'POST',
256
        payload_type = 'direct_message',
257
        allowed_param = ['user', 'screen_name', 'user_id', 'text'],
258
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
259
    )
260

261
    """ direct_messages/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
262
263
264
    destroy_direct_message = bind_api(
        path = '/direct_messages/destroy.json',
        method = 'DELETE',
265
        payload_type = 'direct_message',
Josh Roesslein's avatar
Josh Roesslein committed
266
267
268
269
        allowed_param = ['id'],
        require_auth = True
    )

270
    """ friendships/create """
Josh Roesslein's avatar
Josh Roesslein committed
271
272
    create_friendship = bind_api(
        path = '/friendships/create.json',
273
        method = 'POST',
274
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
275
        allowed_param = ['id', 'user_id', 'screen_name', 'follow'],
276
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
277
278
    )

279
    """ friendships/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
280
281
282
    destroy_friendship = bind_api(
        path = '/friendships/destroy.json',
        method = 'DELETE',
283
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
284
285
286
287
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

288
    """ friendships/show """
Josh Roesslein's avatar
Josh Roesslein committed
289
290
    show_friendship = bind_api(
        path = '/friendships/show.json',
291
        payload_type = 'friendship',
Josh Roesslein's avatar
Josh Roesslein committed
292
293
294
295
        allowed_param = ['source_id', 'source_screen_name',
                          'target_id', 'target_screen_name']
    )

296
297
    """ Perform bulk look up of friendships from user ID or screenname """
    def lookup_friendships(self, user_ids=None, screen_names=None):
Santosh Kumar's avatar
Santosh Kumar committed
298
        return self._lookup_friendships(list_to_csv(user_ids), list_to_csv(screen_names))
299
300
301
302
303
304
305
306
307

    _lookup_friendships = bind_api(
        path = '/friendships/lookup.json',
        payload_type = 'relationship', payload_list = True,
        allowed_param = ['user_id', 'screen_name'],
        require_auth = True
    )


308
    """ friends/ids """
Josh Roesslein's avatar
Josh Roesslein committed
309
310
    friends_ids = bind_api(
        path = '/friends/ids.json',
311
        payload_type = 'ids',
312
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
313
314
    )

315
316
317
318
    """ friends/list """
    friends = bind_api(
        path = '/friends/list.json',
        payload_type = 'user', payload_list = True,
319
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
320
321
    )

322
323
324
325
326
327
328
329
330
331
332
333
334
335
    """ friendships/incoming """
    friendships_incoming = bind_api(
        path = '/friendships/incoming.json',
        payload_type = 'ids',
        allowed_param = ['cursor']
    )

    """ friendships/outgoing"""
    friendships_outgoing = bind_api(
        path = '/friendships/outgoing.json',
        payload_type = 'ids',
        allowed_param = ['cursor']
    )

336
    """ followers/ids """
Josh Roesslein's avatar
Josh Roesslein committed
337
338
    followers_ids = bind_api(
        path = '/followers/ids.json',
339
        payload_type = 'ids',
340
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor', 'count']
Josh Roesslein's avatar
Josh Roesslein committed
341
342
    )

343
344
345
346
    """ followers/list """
    followers = bind_api(
        path = '/followers/list.json',
        payload_type = 'user', payload_list = True,
347
348
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor', 'count',
            'skip_status', 'include_user_entities']
349
350
    )

351
    """ account/verify_credentials """
352
    def verify_credentials(self, **kargs):
Josh Roesslein's avatar
Josh Roesslein committed
353
354
355
        try:
            return bind_api(
                path = '/account/verify_credentials.json',
356
                payload_type = 'user',
357
358
359
                require_auth = True,
                allowed_param = ['include_entities', 'skip_status'],
            )(self, **kargs)
360
        except TweepError as e:
361
362
363
            if e.response and e.response.status == 401:
                return False
            raise
Josh Roesslein's avatar
Josh Roesslein committed
364

365
    """ account/rate_limit_status """
Josh Roesslein's avatar
Josh Roesslein committed
366
    rate_limit_status = bind_api(
367
        path = '/application/rate_limit_status.json',
368
        payload_type = 'json',
369
        allowed_param = ['resources'],
370
        use_cache = False
Josh Roesslein's avatar
Josh Roesslein committed
371
372
    )

373
    """ account/update_delivery_device """
Josh Roesslein's avatar
Josh Roesslein committed
374
375
376
377
    set_delivery_device = bind_api(
        path = '/account/update_delivery_device.json',
        method = 'POST',
        allowed_param = ['device'],
378
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
379
380
381
        require_auth = True
    )

382
    """ account/update_profile_colors """
Josh Roesslein's avatar
Josh Roesslein committed
383
384
385
    update_profile_colors = bind_api(
        path = '/account/update_profile_colors.json',
        method = 'POST',
386
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
387
388
389
390
391
392
        allowed_param = ['profile_background_color', 'profile_text_color',
                          'profile_link_color', 'profile_sidebar_fill_color',
                          'profile_sidebar_border_color'],
        require_auth = True
    )

393
    """ account/update_profile_image """
394
395
    def update_profile_image(self, filename, file=None):
        headers, post_data = API._pack_image(filename, 700, f=file)
Josh Roesslein's avatar
Josh Roesslein committed
396
        return bind_api(
Josh Roesslein's avatar
Josh Roesslein committed
397
398
            path = '/account/update_profile_image.json',
            method = 'POST',
399
            payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
400
401
402
            require_auth = True
        )(self, post_data=post_data, headers=headers)

403
    """ account/update_profile_background_image """
Josh Roesslein's avatar
Josh Roesslein committed
404
    def update_profile_background_image(self, filename, *args, **kargs):
405
406
        f = kargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 800, f=f)
Josh Roesslein's avatar
Josh Roesslein committed
407
408
409
        bind_api(
            path = '/account/update_profile_background_image.json',
            method = 'POST',
410
            payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
411
412
413
414
            allowed_param = ['tile'],
            require_auth = True
        )(self, post_data=post_data, headers=headers)

415
416
    """ account/update_profile_banner """
    def update_profile_banner(self, filename, *args, **kargs):
417
418
        f = kargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 700, form_field="banner", f=f)
419
420
421
422
423
424
425
426
        bind_api(
            path = '/account/update_profile_banner.json',
            method = 'POST',
            allowed_param = ['width', 'height', 'offset_left', 'offset_right'],
            require_auth = True
        )(self, post_data=post_data, headers=headers)


427
    """ account/update_profile """
Josh Roesslein's avatar
Josh Roesslein committed
428
429
430
    update_profile = bind_api(
        path = '/account/update_profile.json',
        method = 'POST',
431
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
432
        allowed_param = ['name', 'url', 'location', 'description'],
433
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
434
435
    )

436
    """ favorites """
Josh Roesslein's avatar
Josh Roesslein committed
437
    favorites = bind_api(
438
        path = '/favorites/list.json',
439
        payload_type = 'status', payload_list = True,
440
        allowed_param = ['screen_name', 'user_id', 'max_id', 'count', 'since_id', 'max_id']
Josh Roesslein's avatar
Josh Roesslein committed
441
442
    )

443
    """ favorites/create """
444
    create_favorite = bind_api(
445
        path = '/favorites/create.json',
446
        method = 'POST',
447
        payload_type = 'status',
448
449
450
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
451

452
    """ favorites/destroy """
453
    destroy_favorite = bind_api(
454
455
        path = '/favorites/destroy.json',
        method = 'POST',
456
        payload_type = 'status',
457
458
459
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
460

461
    """ blocks/create """
Josh Roesslein's avatar
Josh Roesslein committed
462
463
464
    create_block = bind_api(
        path = '/blocks/create.json',
        method = 'POST',
465
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
466
        allowed_param = ['id', 'user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
467
468
469
        require_auth = True
    )

470
    """ blocks/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
471
472
473
    destroy_block = bind_api(
        path = '/blocks/destroy.json',
        method = 'DELETE',
474
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
475
        allowed_param = ['id', 'user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
476
477
478
        require_auth = True
    )

479
    """ blocks/blocking """
Josh Roesslein's avatar
Josh Roesslein committed
480
    blocks = bind_api(
Joshua Roesslein's avatar
Joshua Roesslein committed
481
        path = '/blocks/list.json',
482
        payload_type = 'user', payload_list = True,
483
        allowed_param = ['cursor'],
Josh Roesslein's avatar
Josh Roesslein committed
484
485
486
        require_auth = True
    )

487
    """ blocks/blocking/ids """
Josh Roesslein's avatar
Josh Roesslein committed
488
    blocks_ids = bind_api(
Joshua Roesslein's avatar
Joshua Roesslein committed
489
        path = '/blocks/ids.json',
490
        payload_type = 'json',
Josh Roesslein's avatar
Josh Roesslein committed
491
492
493
        require_auth = True
    )

494
    """ report_spam """
Josh Roesslein's avatar
Josh Roesslein committed
495
    report_spam = bind_api(
496
        path = '/users/report_spam.json',
Josh Roesslein's avatar
Josh Roesslein committed
497
        method = 'POST',
498
        payload_type = 'user',
499
        allowed_param = ['user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
500
501
502
        require_auth = True
    )

503
    """ saved_searches """
Josh Roesslein's avatar
Josh Roesslein committed
504
    saved_searches = bind_api(
505
        path = '/saved_searches/list.json',
506
        payload_type = 'saved_search', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
507
508
509
        require_auth = True
    )

510
    """ saved_searches/show """
511
512
    get_saved_search = bind_api(
        path = '/saved_searches/show/{id}.json',
513
        payload_type = 'saved_search',
514
515
516
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
517

518
    """ saved_searches/create """
Josh Roesslein's avatar
Josh Roesslein committed
519
520
521
    create_saved_search = bind_api(
        path = '/saved_searches/create.json',
        method = 'POST',
522
        payload_type = 'saved_search',
Josh Roesslein's avatar
Josh Roesslein committed
523
524
525
526
        allowed_param = ['query'],
        require_auth = True
    )

527
    """ saved_searches/destroy """
528
529
    destroy_saved_search = bind_api(
        path = '/saved_searches/destroy/{id}.json',
530
        method = 'POST',
531
        payload_type = 'saved_search',
532
533
534
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
535

536
537
538
539
540
541
542
    create_list = bind_api(
        path = '/lists/create.json',
        method = 'POST',
        payload_type = 'list',
        allowed_param = ['name', 'mode', 'description'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
543

544
545
546
547
548
549
550
    destroy_list = bind_api(
        path = '/lists/destroy.json',
        method = 'POST',
        payload_type = 'list',
        allowed_param = ['owner_screen_name', 'owner_id', 'list_id', 'slug'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
551

552
553
554
555
556
557
558
    update_list = bind_api(
        path = '/lists/update.json',
        method = 'POST',
        payload_type = 'list',
        allowed_param = ['list_id', 'slug', 'name', 'mode', 'description', 'owner_screen_name', 'owner_id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
559

560
561
    lists_all = bind_api(
        path = '/lists/list.json',
562
        payload_type = 'list', payload_list = True,
563
        allowed_param = ['screen_name', 'user_id'],
564
565
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
566

567
    lists_memberships = bind_api(
568
        path = '/lists/memberships.json',
569
        payload_type = 'list', payload_list = True,
570
        allowed_param = ['screen_name', 'user_id', 'filter_to_owned_lists', 'cursor'],
571
572
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
573

574
    lists_subscriptions = bind_api(
575
        path = '/lists/subscriptions.json',
576
        payload_type = 'list', payload_list = True,
577
        allowed_param = ['screen_name', 'user_id', 'cursor'],
578
579
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
580

581
    list_timeline = bind_api(
582
        path = '/lists/statuses.json',
583
        payload_type = 'status', payload_list = True,
584
        allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id', 'since_id', 'max_id', 'count', 'include_rts']
585
    )
Josh Roesslein's avatar
Josh Roesslein committed
586

587
    get_list = bind_api(
588
        path = '/lists/show.json',
589
        payload_type = 'list',
590
        allowed_param = ['owner_screen_name', 'owner_id', 'slug', 'list_id']
591
    )
Josh Roesslein's avatar
Josh Roesslein committed
592

593
594
595
596
597
598
599
    add_list_member = bind_api(
        path = '/lists/members/create.json',
        method = 'POST',
        payload_type = 'list',
        allowed_param = ['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
600

601
602
603
604
605
606
607
    remove_list_member = bind_api(
        path = '/lists/members/destroy.json',
        method = 'POST',
        payload_type = 'list',
        allowed_param = ['screen_name', 'user_id', 'owner_screen_name', 'owner_id', 'slug', 'list_id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
608

609
    """ Perform bulk add of list members from user ID or screenname """
kk6's avatar
kk6 committed
610
    def add_list_members(self, screen_name=None, user_id=None, slug=None,
611
                         list_id=None, owner_id=None, owner_screen_name=None):
kk6's avatar
kk6 committed
612
613
        return self._add_list_members(list_to_csv(screen_name),
                                      list_to_csv(user_id),
614
615
616
617
                                      slug, list_id, owner_id,
                                      owner_screen_name)

    _add_list_members = bind_api(
618
619
620
        path = '/lists/members/create_all.json',
        method = 'POST',
        payload_type = 'list',
621
        allowed_param = ['screen_name', 'user_id', 'slug', 'lit_id', 'owner_id', 'owner_screen_name'],
622
623
624
        require_auth = True
    )

625
    """ Perform bulk remove of list members from user ID or screenname """
kk6's avatar
kk6 committed
626
    def remove_list_members(self, screen_name=None, user_id=None, slug=None,
627
                         list_id=None, owner_id=None, owner_screen_name=None):
kk6's avatar
kk6 committed
628
629
        return self._remove_list_members(list_to_csv(screen_name),
                                      list_to_csv(user_id),
630
631
632
633
                                      slug, list_id, owner_id,
                                      owner_screen_name)

    _remove_list_members = bind_api(
634
635
636
        path = '/lists/members/destroy_all.json',
        method = 'POST',
        payload_type = 'list',
637
        allowed_param = ['screen_name', 'user_id', 'slug', 'lit_id', 'owner_id', 'owner_screen_name'],
638
639
640
        require_auth = True
    )

641
    list_members = bind_api(
642
        path = '/lists/members.json',
643
        payload_type = 'user', payload_list = True,
644
        allowed_param = ['owner_screen_name', 'slug', 'list_id', 'owner_id', 'cursor']
645
    )
Josh Roesslein's avatar
Josh Roesslein committed
646

647
648
649
650
651
    show_list_member = bind_api(
        path = '/lists/members/show.json',
        payload_type = 'user',
        allowed_param = ['list_id', 'slug', 'user_id', 'screen_name', 'owner_screen_name', 'owner_id']
    )
Josh Roesslein's avatar
Josh Roesslein committed
652

653
    subscribe_list = bind_api(
654
        path = '/lists/subscribers/create.json',
655
        method = 'POST',
656
        payload_type = 'list',
657
        allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id'],
658
659
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
660

661
    unsubscribe_list = bind_api(
662
663
        path = '/lists/subscribers/destroy.json',
        method = 'POST',
664
        payload_type = 'list',
665
        allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id'],
666
667
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
668

669
    list_subscribers = bind_api(
670
        path = '/lists/subscribers.json',
671
        payload_type = 'user', payload_list = True,
672
        allowed_param = ['owner_screen_name', 'slug', 'owner_id', 'list_id', 'cursor']
673
    )
Josh Roesslein's avatar
Josh Roesslein committed
674

675
676
677
678
679
    show_list_subscriber = bind_api(
        path = '/lists/subscribers/show.json',
        payload_type = 'user',
        allowed_param = ['owner_screen_name', 'slug', 'screen_name', 'owner_id', 'list_id', 'user_id']
    )
Josh Roesslein's avatar
Josh Roesslein committed
680

681
    """ trends/available """
682
683
    trends_available = bind_api(
        path = '/trends/available.json',
684
685
686
687
688
        payload_type = 'json'
    )

    trends_place = bind_api(
        path = '/trends/place.json',
689
        payload_type = 'json',
690
        allowed_param = ['id', 'exclude']
691
692
    )

693
694
    trends_closest = bind_api(
        path = '/trends/closest.json',
695
        payload_type = 'json',
696
        allowed_param = ['lat', 'long']
697
    )
698

699
    """ search """
700
    search = bind_api(
701
702
        path = '/search/tweets.json',
        payload_type = 'search_results',
703
        allowed_param = ['q', 'lang', 'locale', 'since_id', 'geocode', 'max_id', 'since', 'until', 'result_type', 'count', 'include_entities', 'from', 'to', 'source']
704
    )
Josh Roesslein's avatar
Josh Roesslein committed
705

706
    """ trends/daily """
707
708
    trends_daily = bind_api(
        path = '/trends/daily.json',
709
        payload_type = 'json',
710
711
        allowed_param = ['date', 'exclude']
    )
712

713
    """ trends/weekly """
714
715
    trends_weekly = bind_api(
        path = '/trends/weekly.json',
716
        payload_type = 'json',
717
718
        allowed_param = ['date', 'exclude']
    )
719

720
721
722
    """ geo/reverse_geocode """
    reverse_geocode = bind_api(
        path = '/geo/reverse_geocode.json',
723
        payload_type = 'place', payload_list = True,
724
725
726
727
728
729
        allowed_param = ['lat', 'long', 'accuracy', 'granularity', 'max_results']
    )

    """ geo/id """
    geo_id = bind_api(
        path = '/geo/id/{id}.json',
730
        payload_type = 'place',
731
732
733
        allowed_param = ['id']
    )

734
735
736
    """ geo/search """
    geo_search = bind_api(
        path = '/geo/search.json',
737
        payload_type = 'place', payload_list = True,
738
739
740
        allowed_param = ['lat', 'long', 'query', 'ip', 'granularity', 'accuracy', 'max_results', 'contained_within']
    )

741
742
743
744
745
746
747
    """ geo/similar_places """
    geo_similar_places = bind_api(
        path = '/geo/similar_places.json',
        payload_type = 'place', payload_list = True,
        allowed_param = ['lat', 'long', 'name', 'contained_within']
    )

748
749
750
751
752
    """ help/languages.json """
    supported_languages = bind_api(
        path = '/help/languages.json',
        payload_type = 'json',
        require_auth = True
753
    )
Joshua Roesslein's avatar
Joshua Roesslein committed
754

755
    """ help/configuration """
756
757
758
    configuration = bind_api(
        path = '/help/configuration.json',
        payload_type = 'json',
759
        require_auth = True
760
761
    )

762
    """ Internal use only """
Josh Roesslein's avatar
Josh Roesslein committed
763
    @staticmethod
764
    def _pack_image(filename, max_size, form_field="image", f=None):
Josh Roesslein's avatar
Josh Roesslein committed
765
766
        """Pack image from file into multipart-formdata post body"""
        # image must be less than 700kb in size
767
768
769
770
771
772
773
774
775
776
777
778
        if f == None:
            try:
                if os.path.getsize(filename) > (max_size * 1024):
                    raise TweepError('File is too big, must be less than 700kb.')
            except os.error:
                raise TweepError('Unable to access file')

            # build the mulitpart-formdata body
            fp = open(filename, 'rb')
        else:
            f.seek(0, 2) # Seek to end of file
            if f.tell() > (max_size * 1024):
Josh Roesslein's avatar
Josh Roesslein committed
779
                raise TweepError('File is too big, must be less than 700kb.')
780
781
            f.seek(0) # Reset to beginning of file
            fp = f
Josh Roesslein's avatar
Josh Roesslein committed
782
783
784
785
786
787
788
789
790

        # image must be gif, jpeg, or png
        file_type = mimetypes.guess_type(filename)
        if file_type is None:
            raise TweepError('Could not determine file type')
        file_type = file_type[0]
        if file_type not in ['image/gif', 'image/jpeg', 'image/png']:
            raise TweepError('Invalid file type for image: %s' % file_type)

791
792


Josh Roesslein's avatar
Josh Roesslein committed
793
794
795
        BOUNDARY = 'Tw3ePy'
        body = []
        body.append('--' + BOUNDARY)
796
        body.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (form_field, filename))
Josh Roesslein's avatar
Josh Roesslein committed
797
798
799
800
801
802
803
804
805
806
807
        body.append('Content-Type: %s' % file_type)
        body.append('')
        body.append(fp.read())
        body.append('--' + BOUNDARY + '--')
        body.append('')
        fp.close()
        body = '\r\n'.join(body)

        # build headers
        headers = {
            'Content-Type': 'multipart/form-data; boundary=Tw3ePy',
808
            'Content-Length': str(len(body))
Josh Roesslein's avatar
Josh Roesslein committed
809
810
811
        }

        return headers, body