api.py 21.1 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
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',
19
             cache=None, secure=True, api_root='/1.1', search_root='',
20
            retry_count=0, retry_delay=0, retry_errors=None,
21
            parser=None):
Josh Roesslein's avatar
Josh Roesslein committed
22
        self.auth = auth_handler
Josh Roesslein's avatar
Josh Roesslein committed
23
        self.host = host
24
        self.search_host = search_host
Josh Roesslein's avatar
Josh Roesslein committed
25
        self.api_root = api_root
26
        self.search_root = search_root
Josh Roesslein's avatar
Josh Roesslein committed
27
28
        self.cache = cache
        self.secure = secure
29
30
        self.retry_count = retry_count
        self.retry_delay = retry_delay
31
        self.retry_errors = retry_errors
32
        self.parser = parser or ModelParser()
Josh Roesslein's avatar
Josh Roesslein committed
33

Ferenc Szalai's avatar
Ferenc Szalai committed
34
    """ statuses/home_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
35
36
    home_timeline = bind_api(
        path = '/statuses/home_timeline.json',
37
        payload_type = 'status', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
38
39
40
41
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

42
    """ statuses/user_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
43
44
    user_timeline = bind_api(
        path = '/statuses/user_timeline.json',
45
        payload_type = 'status', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
46
        allowed_param = ['id', 'user_id', 'screen_name', 'since_id',
47
                          'max_id', 'count', 'page', 'include_rts']
Josh Roesslein's avatar
Josh Roesslein committed
48
49
    )

50
    """ statuses/mentions """
51
52
    mentions_timeline = bind_api(
        path = '/statuses/mentions_timeline.json',
53
        payload_type = 'status', payload_list = True,
54
        allowed_param = ['since_id', 'max_id', 'count'],
Josh Roesslein's avatar
Josh Roesslein committed
55
56
57
        require_auth = True
    )

58
59
60
61
62
63
64
    """/statuses/:id/retweeted_by.format"""
    retweeted_by = bind_api(
        path = '/statuses/{id}/retweeted_by.json',
        payload_type = 'status', payload_list = True,
        allowed_param = ['id', 'count', 'page'],
        require_auth = True
    )
65

Aaron Swartz's avatar
Aaron Swartz committed
66
67
68
69
70
71
    """/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
72
    )
73
74
75
76
77
78
79
80
81

    """/statuses/:id/retweeted_by/ids.format"""
    retweeted_by_ids = bind_api(
        path = '/statuses/{id}/retweeted_by/ids.json',
        payload_type = 'ids',
        allowed_param = ['id', 'count', 'page'],
        require_auth = True
    )

82
    """ statuses/retweets_of_me """
Josh Roesslein's avatar
Josh Roesslein committed
83
84
    retweets_of_me = bind_api(
        path = '/statuses/retweets_of_me.json',
85
        payload_type = 'status', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
86
87
88
89
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

90
    """ statuses/show """
Josh Roesslein's avatar
Josh Roesslein committed
91
92
    get_status = bind_api(
        path = '/statuses/show.json',
93
        payload_type = 'status',
Josh Roesslein's avatar
Josh Roesslein committed
94
95
96
        allowed_param = ['id']
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
97
    """ statuses/update """
Josh Roesslein's avatar
Josh Roesslein committed
98
99
100
    update_status = bind_api(
        path = '/statuses/update.json',
        method = 'POST',
101
        payload_type = 'status',
102
        allowed_param = ['status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id'],
Josh Roesslein's avatar
Josh Roesslein committed
103
104
105
        require_auth = True
    )

106
    """ statuses/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
107
108
109
    destroy_status = bind_api(
        path = '/statuses/destroy.json',
        method = 'DELETE',
110
        payload_type = 'status',
Josh Roesslein's avatar
Josh Roesslein committed
111
112
113
114
        allowed_param = ['id'],
        require_auth = True
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
115
    """ statuses/retweet """
116
117
118
    retweet = bind_api(
        path = '/statuses/retweet/{id}.json',
        method = 'POST',
119
        payload_type = 'status',
120
121
122
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
123

Ferenc Szalai's avatar
Ferenc Szalai committed
124
    """ statuses/retweets """
125
126
    retweets = bind_api(
        path = '/statuses/retweets/{id}.json',
127
        payload_type = 'status', payload_list = True,
128
129
130
        allowed_param = ['id', 'count'],
        require_auth = True
    )
131

132
    """ users/show """
Josh Roesslein's avatar
Josh Roesslein committed
133
134
    get_user = bind_api(
        path = '/users/show.json',
135
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
136
137
138
        allowed_param = ['id', 'user_id', 'screen_name']
    )

139
140
141
142
143
144
145
146
147
148
    """ 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'],
    )

149
    """ Get the authenticated user """
Josh Roesslein's avatar
Josh Roesslein committed
150
    def me(self):
Josh Roesslein's avatar
Josh Roesslein committed
151
        return self.get_user(screen_name=self.auth.get_username())
Josh Roesslein's avatar
Josh Roesslein committed
152

153
154
155
    """ users/search """
    search_users = bind_api(
        path = '/users/search.json',
156
        payload_type = 'user', payload_list = True,
157
158
159
160
        require_auth = True,
        allowed_param = ['q', 'per_page', 'page']
    )

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    """ 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
    )

185
    """ direct_messages """
Josh Roesslein's avatar
Josh Roesslein committed
186
187
    direct_messages = bind_api(
        path = '/direct_messages.json',
188
        payload_type = 'direct_message', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
189
190
191
192
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

193
194
195
196
197
198
199
200
    """ direct_messages/show """
    get_direct_message = bind_api(
        path = '/direct_messages/show/{id}.json',
        payload_type = 'direct_message',
        allowed_param = ['id'],
        require_auth = True
    )

201
    """ direct_messages/sent """
Josh Roesslein's avatar
Josh Roesslein committed
202
203
    sent_direct_messages = bind_api(
        path = '/direct_messages/sent.json',
204
        payload_type = 'direct_message', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
205
206
207
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )
208

209
    """ direct_messages/new """
Josh Roesslein's avatar
Josh Roesslein committed
210
211
    send_direct_message = bind_api(
        path = '/direct_messages/new.json',
212
        method = 'POST',
213
        payload_type = 'direct_message',
214
        allowed_param = ['user', 'screen_name', 'user_id', 'text'],
215
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
216
    )
217

218
    """ direct_messages/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
219
220
221
    destroy_direct_message = bind_api(
        path = '/direct_messages/destroy.json',
        method = 'DELETE',
222
        payload_type = 'direct_message',
Josh Roesslein's avatar
Josh Roesslein committed
223
224
225
226
        allowed_param = ['id'],
        require_auth = True
    )

227
    """ friendships/create """
Josh Roesslein's avatar
Josh Roesslein committed
228
229
    create_friendship = bind_api(
        path = '/friendships/create.json',
230
        method = 'POST',
231
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
232
        allowed_param = ['id', 'user_id', 'screen_name', 'follow'],
233
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
234
235
    )

236
    """ friendships/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
237
238
239
    destroy_friendship = bind_api(
        path = '/friendships/destroy.json',
        method = 'DELETE',
240
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
241
242
243
244
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

245
    """ friendships/exists """
Josh Roesslein's avatar
Josh Roesslein committed
246
247
    exists_friendship = bind_api(
        path = '/friendships/exists.json',
248
        payload_type = 'json',
Josh Roesslein's avatar
Josh Roesslein committed
249
250
251
        allowed_param = ['user_a', 'user_b']
    )

252
    """ friendships/show """
Josh Roesslein's avatar
Josh Roesslein committed
253
254
    show_friendship = bind_api(
        path = '/friendships/show.json',
255
        payload_type = 'friendship',
Josh Roesslein's avatar
Josh Roesslein committed
256
257
258
259
        allowed_param = ['source_id', 'source_screen_name',
                          'target_id', 'target_screen_name']
    )

260
261
262
263
264
265
266
267
268
269
270
271
272

    """ Perform bulk look up of friendships from user ID or screenname """
    def lookup_friendships(self, user_ids=None, screen_names=None):
	    return self._lookup_friendships(list_to_csv(user_ids), list_to_csv(screen_names))

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


273
    """ friends/ids """
Josh Roesslein's avatar
Josh Roesslein committed
274
275
    friends_ids = bind_api(
        path = '/friends/ids.json',
276
        payload_type = 'ids',
277
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
278
279
    )

280
281
282
283
284
285
286
287
288
289
290
291
292
293
    """ 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']
    )

294
    """ followers/ids """
Josh Roesslein's avatar
Josh Roesslein committed
295
296
    followers_ids = bind_api(
        path = '/followers/ids.json',
297
        payload_type = 'ids',
298
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
299
300
    )

301
    """ account/verify_credentials """
302
    def verify_credentials(self, **kargs):
Josh Roesslein's avatar
Josh Roesslein committed
303
304
305
        try:
            return bind_api(
                path = '/account/verify_credentials.json',
306
                payload_type = 'user',
307
308
309
                require_auth = True,
                allowed_param = ['include_entities', 'skip_status'],
            )(self, **kargs)
310
311
312
313
        except TweepError, e:
            if e.response and e.response.status == 401:
                return False
            raise
Josh Roesslein's avatar
Josh Roesslein committed
314

315
    """ account/rate_limit_status """
Josh Roesslein's avatar
Josh Roesslein committed
316
317
    rate_limit_status = bind_api(
        path = '/account/rate_limit_status.json',
318
319
        payload_type = 'json',
        use_cache = False
Josh Roesslein's avatar
Josh Roesslein committed
320
321
    )

322
    """ account/update_delivery_device """
Josh Roesslein's avatar
Josh Roesslein committed
323
324
325
326
    set_delivery_device = bind_api(
        path = '/account/update_delivery_device.json',
        method = 'POST',
        allowed_param = ['device'],
327
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
328
329
330
        require_auth = True
    )

331
    """ account/update_profile_colors """
Josh Roesslein's avatar
Josh Roesslein committed
332
333
334
    update_profile_colors = bind_api(
        path = '/account/update_profile_colors.json',
        method = 'POST',
335
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
336
337
338
339
340
341
        allowed_param = ['profile_background_color', 'profile_text_color',
                          'profile_link_color', 'profile_sidebar_fill_color',
                          'profile_sidebar_border_color'],
        require_auth = True
    )

342
    """ account/update_profile_image """
Josh Roesslein's avatar
Josh Roesslein committed
343
    def update_profile_image(self, filename):
Josh Roesslein's avatar
Josh Roesslein committed
344
        headers, post_data = API._pack_image(filename, 700)
Josh Roesslein's avatar
Josh Roesslein committed
345
        return bind_api(
Josh Roesslein's avatar
Josh Roesslein committed
346
347
            path = '/account/update_profile_image.json',
            method = 'POST',
348
            payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
349
350
351
            require_auth = True
        )(self, post_data=post_data, headers=headers)

352
    """ account/update_profile_background_image """
Josh Roesslein's avatar
Josh Roesslein committed
353
    def update_profile_background_image(self, filename, *args, **kargs):
Josh Roesslein's avatar
Josh Roesslein committed
354
        headers, post_data = API._pack_image(filename, 800)
Josh Roesslein's avatar
Josh Roesslein committed
355
356
357
        bind_api(
            path = '/account/update_profile_background_image.json',
            method = 'POST',
358
            payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
359
360
361
362
            allowed_param = ['tile'],
            require_auth = True
        )(self, post_data=post_data, headers=headers)

363
    """ account/update_profile """
Josh Roesslein's avatar
Josh Roesslein committed
364
365
366
    update_profile = bind_api(
        path = '/account/update_profile.json',
        method = 'POST',
367
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
368
        allowed_param = ['name', 'url', 'location', 'description'],
369
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
370
371
    )

372
    """ favorites """
Josh Roesslein's avatar
Josh Roesslein committed
373
    favorites = bind_api(
374
        path = '/favorites/list.json',
375
        payload_type = 'status', payload_list = True,
376
        allowed_param = ['screen_name', 'user_id', 'max_id', 'count', 'since_id', 'max_id']
Josh Roesslein's avatar
Josh Roesslein committed
377
378
    )

379
    """ favorites/create """
380
    create_favorite = bind_api(
381
        path = '/favorites/create.json',
382
        method = 'POST',
383
        payload_type = 'status',
384
385
386
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
387

388
    """ favorites/destroy """
389
    destroy_favorite = bind_api(
390
391
        path = '/favorites/destroy.json',
        method = 'POST',
392
        payload_type = 'status',
393
394
395
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
396

397
    """ blocks/create """
Josh Roesslein's avatar
Josh Roesslein committed
398
399
400
    create_block = bind_api(
        path = '/blocks/create.json',
        method = 'POST',
401
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
402
        allowed_param = ['id', 'user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
403
404
405
        require_auth = True
    )

406
    """ blocks/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
407
408
409
    destroy_block = bind_api(
        path = '/blocks/destroy.json',
        method = 'DELETE',
410
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
411
        allowed_param = ['id', 'user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
412
413
414
        require_auth = True
    )

415
    """ blocks/blocking """
Josh Roesslein's avatar
Josh Roesslein committed
416
    blocks = bind_api(
Joshua Roesslein's avatar
Joshua Roesslein committed
417
        path = '/blocks/list.json',
418
        payload_type = 'user', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
419
420
421
422
        allowed_param = ['page'],
        require_auth = True
    )

423
    """ blocks/blocking/ids """
Josh Roesslein's avatar
Josh Roesslein committed
424
    blocks_ids = bind_api(
Joshua Roesslein's avatar
Joshua Roesslein committed
425
        path = '/blocks/ids.json',
426
        payload_type = 'json',
Josh Roesslein's avatar
Josh Roesslein committed
427
428
429
        require_auth = True
    )

430
    """ report_spam """
Josh Roesslein's avatar
Josh Roesslein committed
431
432
433
    report_spam = bind_api(
        path = '/report_spam.json',
        method = 'POST',
434
        payload_type = 'user',
Josh Roesslein's avatar
Josh Roesslein committed
435
436
437
438
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

439
    """ saved_searches """
Josh Roesslein's avatar
Josh Roesslein committed
440
441
    saved_searches = bind_api(
        path = '/saved_searches.json',
442
        payload_type = 'saved_search', payload_list = True,
Josh Roesslein's avatar
Josh Roesslein committed
443
444
445
        require_auth = True
    )

446
    """ saved_searches/show """
447
448
    get_saved_search = bind_api(
        path = '/saved_searches/show/{id}.json',
449
        payload_type = 'saved_search',
450
451
452
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
453

454
    """ saved_searches/create """
Josh Roesslein's avatar
Josh Roesslein committed
455
456
457
    create_saved_search = bind_api(
        path = '/saved_searches/create.json',
        method = 'POST',
458
        payload_type = 'saved_search',
Josh Roesslein's avatar
Josh Roesslein committed
459
460
461
462
        allowed_param = ['query'],
        require_auth = True
    )

463
    """ saved_searches/destroy """
464
465
466
    destroy_saved_search = bind_api(
        path = '/saved_searches/destroy/{id}.json',
        method = 'DELETE',
467
        payload_type = 'saved_search',
468
469
470
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
471

472
    """ help/test """
Josh Roesslein's avatar
Josh Roesslein committed
473
    def test(self):
474
        try:
475
            bind_api(
476
477
478
479
                path = '/help/test.json',
            )(self)
        except TweepError:
            return False
480
        return True
481

482
483
484
485
486
487
488
    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
489

490
491
492
493
494
495
496
    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
497

498
499
500
501
502
503
504
    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
505

506
507
    lists = bind_api(
        path = '/{user}/lists.json',
508
        payload_type = 'list', payload_list = True,
509
510
511
        allowed_param = ['user', 'cursor'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
512

513
514
    lists_memberships = bind_api(
        path = '/{user}/lists/memberships.json',
515
        payload_type = 'list', payload_list = True,
516
517
518
        allowed_param = ['user', 'cursor'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
519

520
521
    lists_subscriptions = bind_api(
        path = '/{user}/lists/subscriptions.json',
522
        payload_type = 'list', payload_list = True,
523
524
525
        allowed_param = ['user', 'cursor'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
526

527
528
    list_timeline = bind_api(
        path = '/{owner}/lists/{slug}/statuses.json',
529
        payload_type = 'status', payload_list = True,
530
        allowed_param = ['owner', 'slug', 'since_id', 'max_id', 'per_page', 'page']
531
    )
Josh Roesslein's avatar
Josh Roesslein committed
532

533
534
    get_list = bind_api(
        path = '/{owner}/lists/{slug}.json',
535
        payload_type = 'list',
536
537
        allowed_param = ['owner', 'slug']
    )
Josh Roesslein's avatar
Josh Roesslein committed
538

539
540
541
542
543
544
545
    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
546

547
548
549
550
551
552
553
    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
554

555
556
    list_members = bind_api(
        path = '/{owner}/{slug}/members.json',
557
        payload_type = 'user', payload_list = True,
558
559
        allowed_param = ['owner', 'slug', 'cursor']
    )
Josh Roesslein's avatar
Josh Roesslein committed
560
561
562
563
564

    def is_list_member(self, owner, slug, user_id):
        try:
            return bind_api(
                path = '/%s/%s/members/%s.json' % (owner, slug, user_id),
565
                payload_type = 'user'
Josh Roesslein's avatar
Josh Roesslein committed
566
567
568
569
            )(self)
        except TweepError:
            return False

570
571
572
    subscribe_list = bind_api(
        path = '/{owner}/{slug}/subscribers.json',
        method = 'POST',
573
        payload_type = 'list',
574
575
576
        allowed_param = ['owner', 'slug'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
577

578
579
580
    unsubscribe_list = bind_api(
        path = '/{owner}/{slug}/subscribers.json',
        method = 'DELETE',
581
        payload_type = 'list',
582
583
584
        allowed_param = ['owner', 'slug'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
585

586
587
    list_subscribers = bind_api(
        path = '/{owner}/{slug}/subscribers.json',
588
        payload_type = 'user', payload_list = True,
589
590
        allowed_param = ['owner', 'slug', 'cursor']
    )
Josh Roesslein's avatar
Josh Roesslein committed
591
592
593
594
595

    def is_subscribed_list(self, owner, slug, user_id):
        try:
            return bind_api(
                path = '/%s/%s/subscribers/%s.json' % (owner, slug, user_id),
596
                payload_type = 'user'
Josh Roesslein's avatar
Josh Roesslein committed
597
598
599
600
            )(self)
        except TweepError:
            return False

601
    """ trends/available """
602
603
    trends_available = bind_api(
        path = '/trends/available.json',
604
        payload_type = 'json',
605
606
607
        allowed_param = ['lat', 'long']
    )

608
    """ trends/location """
609
610
    trends_location = bind_api(
        path = '/trends/{woeid}.json',
611
        payload_type = 'json',
612
613
        allowed_param = ['woeid']
    )
614

615
    """ search """
616
617
618
    search = bind_api(
        search_api = True,
        path = '/search.json',
619
        payload_type = 'search_result', payload_list = True,
620
        allowed_param = ['q', 'lang', 'locale', 'rpp', 'page', 'since_id', 'geocode', 'show_user', 'max_id', 'since', 'until', 'result_type']
621
    )
622
    search.pagination_mode = 'page'
Josh Roesslein's avatar
Josh Roesslein committed
623

624
    """ trends/daily """
625
626
    trends_daily = bind_api(
        path = '/trends/daily.json',
627
        payload_type = 'json',
628
629
        allowed_param = ['date', 'exclude']
    )
630

631
    """ trends/weekly """
632
633
    trends_weekly = bind_api(
        path = '/trends/weekly.json',
634
        payload_type = 'json',
635
636
        allowed_param = ['date', 'exclude']
    )
637

638
639
640
    """ geo/reverse_geocode """
    reverse_geocode = bind_api(
        path = '/geo/reverse_geocode.json',
641
        payload_type = 'place', payload_list = True,
642
643
644
645
646
647
        allowed_param = ['lat', 'long', 'accuracy', 'granularity', 'max_results']
    )

    """ geo/id """
    geo_id = bind_api(
        path = '/geo/id/{id}.json',
648
        payload_type = 'place',
649
650
651
        allowed_param = ['id']
    )

652
653
654
    """ geo/search """
    geo_search = bind_api(
        path = '/geo/search.json',
655
        payload_type = 'place', payload_list = True,
656
657
658
        allowed_param = ['lat', 'long', 'query', 'ip', 'granularity', 'accuracy', 'max_results', 'contained_within']
    )

659
660
661
662
663
664
665
    """ 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']
    )

666
    """ Internal use only """
Josh Roesslein's avatar
Josh Roesslein committed
667
    @staticmethod
Josh Roesslein's avatar
Josh Roesslein committed
668
669
670
671
672
673
    def _pack_image(filename, max_size):
        """Pack image from file into multipart-formdata post body"""
        # image must be less than 700kb in size
        try:
            if os.path.getsize(filename) > (max_size * 1024):
                raise TweepError('File is too big, must be less than 700kb.')
674
        except os.error:
Josh Roesslein's avatar
Josh Roesslein committed
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
            raise TweepError('Unable to access file')

        # 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)

        # build the mulitpart-formdata body
        fp = open(filename, 'rb')
        BOUNDARY = 'Tw3ePy'
        body = []
        body.append('--' + BOUNDARY)
        body.append('Content-Disposition: form-data; name="image"; filename="%s"' % filename)
        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',
702
            'Content-Length': str(len(body))
Josh Roesslein's avatar
Josh Roesslein committed
703
704
705
        }

        return headers, body
706