api.py 19.5 KB
Newer Older
1
2
3
4
# Tweepy
# Copyright 2009 Joshua Roesslein
# See LICENSE

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
Josh Roesslein's avatar
Josh Roesslein committed
10
from tweepy.parsers import *
11
from tweepy.models import ModelFactory
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
19
    def __init__(self, auth_handler=None,
            host='api.twitter.com', search_host='search.twitter.com',
             cache=None, secure=False, api_root='/1', search_root='',
20
21
            retry_count=0, retry_delay=0, retry_errors=None,
            model_factory=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.model_factory = model_factory or ModelFactory
Josh Roesslein's avatar
Josh Roesslein committed
33

34
    """ statuses/public_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
35
36
37
38
39
40
    public_timeline = bind_api(
        path = '/statuses/public_timeline.json',
        parser = parse_statuses,
        allowed_param = []
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
41
    """ statuses/home_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
42
43
44
45
46
47
48
    home_timeline = bind_api(
        path = '/statuses/home_timeline.json',
        parser = parse_statuses,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

49
    """ statuses/friends_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
50
51
52
53
54
55
56
    friends_timeline = bind_api(
        path = '/statuses/friends_timeline.json',
        parser = parse_statuses,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

57
    """ statuses/user_timeline """
Josh Roesslein's avatar
Josh Roesslein committed
58
59
60
61
62
63
64
    user_timeline = bind_api(
        path = '/statuses/user_timeline.json',
        parser = parse_statuses,
        allowed_param = ['id', 'user_id', 'screen_name', 'since_id',
                          'max_id', 'count', 'page']
    )

65
    """ statuses/mentions """
Josh Roesslein's avatar
Josh Roesslein committed
66
67
68
69
70
71
72
    mentions = bind_api(
        path = '/statuses/mentions.json',
        parser = parse_statuses,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
73
    """ statuses/retweeted_by_me """
Josh Roesslein's avatar
Josh Roesslein committed
74
75
76
77
78
79
80
    retweeted_by_me = bind_api(
        path = '/statuses/retweeted_by_me.json',
        parser = parse_statuses,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

81
    """ statuses/retweeted_to_me """
Josh Roesslein's avatar
Josh Roesslein committed
82
83
84
85
86
87
88
    retweeted_to_me = bind_api(
        path = '/statuses/retweeted_to_me.json',
        parser = parse_statuses,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

89
    """ statuses/retweets_of_me """
Josh Roesslein's avatar
Josh Roesslein committed
90
91
92
93
94
95
96
    retweets_of_me = bind_api(
        path = '/statuses/retweets_of_me.json',
        parser = parse_statuses,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

97
    """ statuses/show """
Josh Roesslein's avatar
Josh Roesslein committed
98
99
100
101
102
103
    get_status = bind_api(
        path = '/statuses/show.json',
        parser = parse_status,
        allowed_param = ['id']
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
104
    """ statuses/update """
Josh Roesslein's avatar
Josh Roesslein committed
105
106
107
108
    update_status = bind_api(
        path = '/statuses/update.json',
        method = 'POST',
        parser = parse_status,
109
        allowed_param = ['status', 'in_reply_to_status_id', 'lat', 'long', 'source'],
Josh Roesslein's avatar
Josh Roesslein committed
110
111
112
        require_auth = True
    )

113
    """ statuses/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
114
115
116
117
118
119
120
121
    destroy_status = bind_api(
        path = '/statuses/destroy.json',
        method = 'DELETE',
        parser = parse_status,
        allowed_param = ['id'],
        require_auth = True
    )

Ferenc Szalai's avatar
Ferenc Szalai committed
122
    """ statuses/retweet """
123
124
125
126
127
128
129
    retweet = bind_api(
        path = '/statuses/retweet/{id}.json',
        method = 'POST',
        parser = parse_status,
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
130

Ferenc Szalai's avatar
Ferenc Szalai committed
131
    """ statuses/retweets """
132
133
134
135
136
137
    retweets = bind_api(
        path = '/statuses/retweets/{id}.json',
        parser = parse_statuses,
        allowed_param = ['id', 'count'],
        require_auth = True
    )
138

139
    """ users/show """
Josh Roesslein's avatar
Josh Roesslein committed
140
141
142
143
144
145
    get_user = bind_api(
        path = '/users/show.json',
        parser = parse_user,
        allowed_param = ['id', 'user_id', 'screen_name']
    )

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

150
151
152
153
154
155
156
157
    """ users/search """
    search_users = bind_api(
        path = '/users/search.json',
        parser = parse_users,
        require_auth = True,
        allowed_param = ['q', 'per_page', 'page']
    )

158
    """ statuses/friends """
Josh Roesslein's avatar
Josh Roesslein committed
159
160
161
    friends = bind_api(
        path = '/statuses/friends.json',
        parser = parse_users,
162
        allowed_param = ['id', 'user_id', 'screen_name', 'page', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
163
164
    )

165
    """ statuses/followers """
Josh Roesslein's avatar
Josh Roesslein committed
166
167
168
    followers = bind_api(
        path = '/statuses/followers.json',
        parser = parse_users,
169
        allowed_param = ['id', 'user_id', 'screen_name', 'page', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
170
171
    )

172
    """ direct_messages """
Josh Roesslein's avatar
Josh Roesslein committed
173
174
175
176
177
178
179
    direct_messages = bind_api(
        path = '/direct_messages.json',
        parser = parse_directmessages,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )

180
    """ direct_messages/sent """
Josh Roesslein's avatar
Josh Roesslein committed
181
182
183
184
185
186
    sent_direct_messages = bind_api(
        path = '/direct_messages/sent.json',
        parser = parse_directmessages,
        allowed_param = ['since_id', 'max_id', 'count', 'page'],
        require_auth = True
    )
187

188
    """ direct_messages/new """
Josh Roesslein's avatar
Josh Roesslein committed
189
190
    send_direct_message = bind_api(
        path = '/direct_messages/new.json',
191
        method = 'POST',
Josh Roesslein's avatar
Josh Roesslein committed
192
        parser = parse_dm,
193
        allowed_param = ['user', 'screen_name', 'user_id', 'text'],
194
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
195
    )
196

197
    """ direct_messages/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
198
199
200
201
202
203
204
205
    destroy_direct_message = bind_api(
        path = '/direct_messages/destroy.json',
        method = 'DELETE',
        parser = parse_dm,
        allowed_param = ['id'],
        require_auth = True
    )

206
    """ friendships/create """
Josh Roesslein's avatar
Josh Roesslein committed
207
208
    create_friendship = bind_api(
        path = '/friendships/create.json',
209
        method = 'POST',
Josh Roesslein's avatar
Josh Roesslein committed
210
211
        parser = parse_user,
        allowed_param = ['id', 'user_id', 'screen_name', 'follow'],
212
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
213
214
    )

215
    """ friendships/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
216
217
218
219
220
221
222
223
    destroy_friendship = bind_api(
        path = '/friendships/destroy.json',
        method = 'DELETE',
        parser = parse_user,
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

224
    """ friendships/exists """
Josh Roesslein's avatar
Josh Roesslein committed
225
226
227
228
229
230
    exists_friendship = bind_api(
        path = '/friendships/exists.json',
        parser = parse_json,
        allowed_param = ['user_a', 'user_b']
    )

231
    """ friendships/show """
Josh Roesslein's avatar
Josh Roesslein committed
232
233
234
235
236
237
238
    show_friendship = bind_api(
        path = '/friendships/show.json',
        parser = parse_friendship,
        allowed_param = ['source_id', 'source_screen_name',
                          'target_id', 'target_screen_name']
    )

239
    """ friends/ids """
Josh Roesslein's avatar
Josh Roesslein committed
240
241
    friends_ids = bind_api(
        path = '/friends/ids.json',
242
        parser = parse_ids,
243
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
244
245
    )

246
    """ followers/ids """
Josh Roesslein's avatar
Josh Roesslein committed
247
248
    followers_ids = bind_api(
        path = '/followers/ids.json',
249
        parser = parse_ids,
250
        allowed_param = ['id', 'user_id', 'screen_name', 'cursor']
Josh Roesslein's avatar
Josh Roesslein committed
251
252
    )

253
    """ account/verify_credentials """
Josh Roesslein's avatar
Josh Roesslein committed
254
255
256
257
    def verify_credentials(self):
        try:
            return bind_api(
                path = '/account/verify_credentials.json',
Josh Roesslein's avatar
Josh Roesslein committed
258
                parser = parse_user,
Josh Roesslein's avatar
Josh Roesslein committed
259
260
261
262
263
                require_auth = True
            )(self)
        except TweepError:
            return False

264
    """ account/rate_limit_status """
Josh Roesslein's avatar
Josh Roesslein committed
265
266
267
268
269
    rate_limit_status = bind_api(
        path = '/account/rate_limit_status.json',
        parser = parse_json
    )

270
    """ account/update_delivery_device """
Josh Roesslein's avatar
Josh Roesslein committed
271
272
273
274
275
276
277
278
    set_delivery_device = bind_api(
        path = '/account/update_delivery_device.json',
        method = 'POST',
        allowed_param = ['device'],
        parser = parse_user,
        require_auth = True
    )

279
    """ account/update_profile_colors """
Josh Roesslein's avatar
Josh Roesslein committed
280
281
282
283
284
285
286
287
288
289
    update_profile_colors = bind_api(
        path = '/account/update_profile_colors.json',
        method = 'POST',
        parser = parse_user,
        allowed_param = ['profile_background_color', 'profile_text_color',
                          'profile_link_color', 'profile_sidebar_fill_color',
                          'profile_sidebar_border_color'],
        require_auth = True
    )

290
    """ account/update_profile_image """
Josh Roesslein's avatar
Josh Roesslein committed
291
    def update_profile_image(self, filename):
Josh Roesslein's avatar
Josh Roesslein committed
292
        headers, post_data = API._pack_image(filename, 700)
Josh Roesslein's avatar
Josh Roesslein committed
293
        return bind_api(
Josh Roesslein's avatar
Josh Roesslein committed
294
295
            path = '/account/update_profile_image.json',
            method = 'POST',
Josh Roesslein's avatar
Josh Roesslein committed
296
            parser = parse_user,
Josh Roesslein's avatar
Josh Roesslein committed
297
298
299
            require_auth = True
        )(self, post_data=post_data, headers=headers)

300
    """ account/update_profile_background_image """
Josh Roesslein's avatar
Josh Roesslein committed
301
    def update_profile_background_image(self, filename, *args, **kargs):
Josh Roesslein's avatar
Josh Roesslein committed
302
        headers, post_data = API._pack_image(filename, 800)
Josh Roesslein's avatar
Josh Roesslein committed
303
304
305
        bind_api(
            path = '/account/update_profile_background_image.json',
            method = 'POST',
Josh Roesslein's avatar
Josh Roesslein committed
306
            parser = parse_user,
Josh Roesslein's avatar
Josh Roesslein committed
307
308
309
310
            allowed_param = ['tile'],
            require_auth = True
        )(self, post_data=post_data, headers=headers)

311
    """ account/update_profile """
Josh Roesslein's avatar
Josh Roesslein committed
312
313
314
315
    update_profile = bind_api(
        path = '/account/update_profile.json',
        method = 'POST',
        parser = parse_user,
Josh Roesslein's avatar
Josh Roesslein committed
316
        allowed_param = ['name', 'url', 'location', 'description'],
317
        require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
318
319
    )

320
    """ favorites """
Josh Roesslein's avatar
Josh Roesslein committed
321
322
323
324
325
326
    favorites = bind_api(
        path = '/favorites.json',
        parser = parse_statuses,
        allowed_param = ['id', 'page']
    )

327
    """ favorites/create """
328
329
330
331
332
333
334
    create_favorite = bind_api(
        path = '/favorites/create/{id}.json',
        method = 'POST',
        parser = parse_status,
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
335

336
    """ favorites/destroy """
337
338
339
340
341
342
343
    destroy_favorite = bind_api(
        path = '/favorites/destroy/{id}.json',
        method = 'DELETE',
        parser = parse_status,
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
344

345
    """ notifications/follow """
Josh Roesslein's avatar
Josh Roesslein committed
346
347
348
349
350
351
352
353
    enable_notifications = bind_api(
        path = '/notifications/follow.json',
        method = 'POST',
        parser = parse_user,
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

354
    """ notifications/leave """
Josh Roesslein's avatar
Josh Roesslein committed
355
356
357
358
359
360
361
362
    disable_notifications = bind_api(
        path = '/notifications/leave.json',
        method = 'POST',
        parser = parse_user,
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

363
    """ blocks/create """
Josh Roesslein's avatar
Josh Roesslein committed
364
365
366
367
    create_block = bind_api(
        path = '/blocks/create.json',
        method = 'POST',
        parser = parse_user,
Josh Roesslein's avatar
Josh Roesslein committed
368
        allowed_param = ['id', 'user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
369
370
371
        require_auth = True
    )

372
    """ blocks/destroy """
Josh Roesslein's avatar
Josh Roesslein committed
373
374
375
376
    destroy_block = bind_api(
        path = '/blocks/destroy.json',
        method = 'DELETE',
        parser = parse_user,
Josh Roesslein's avatar
Josh Roesslein committed
377
        allowed_param = ['id', 'user_id', 'screen_name'],
Josh Roesslein's avatar
Josh Roesslein committed
378
379
380
        require_auth = True
    )

381
    """ blocks/exists """
Josh Roesslein's avatar
Josh Roesslein committed
382
    def exists_block(self, *args, **kargs):
Josh Roesslein's avatar
Josh Roesslein committed
383
384
385
386
387
388
        try:
            bind_api(
                path = '/blocks/exists.json',
                parser = parse_none,
                allowed_param = ['id', 'user_id', 'screen_name'],
                require_auth = True
Josh Roesslein's avatar
Josh Roesslein committed
389
            )(self, *args, **kargs)
Josh Roesslein's avatar
Josh Roesslein committed
390
391
392
393
        except TweepError:
            return False
        return True

394
    """ blocks/blocking """
Josh Roesslein's avatar
Josh Roesslein committed
395
396
397
398
399
400
401
    blocks = bind_api(
        path = '/blocks/blocking.json',
        parser = parse_users,
        allowed_param = ['page'],
        require_auth = True
    )

402
    """ blocks/blocking/ids """
Josh Roesslein's avatar
Josh Roesslein committed
403
404
405
406
407
408
    blocks_ids = bind_api(
        path = '/blocks/blocking/ids.json',
        parser = parse_json,
        require_auth = True
    )

409
    """ report_spam """
Josh Roesslein's avatar
Josh Roesslein committed
410
411
412
413
414
415
416
417
    report_spam = bind_api(
        path = '/report_spam.json',
        method = 'POST',
        parser = parse_user,
        allowed_param = ['id', 'user_id', 'screen_name'],
        require_auth = True
    )

418
    """ saved_searches """
Josh Roesslein's avatar
Josh Roesslein committed
419
420
421
422
423
424
    saved_searches = bind_api(
        path = '/saved_searches.json',
        parser = parse_saved_searches,
        require_auth = True
    )

425
    """ saved_searches/show """
426
427
428
429
430
431
    get_saved_search = bind_api(
        path = '/saved_searches/show/{id}.json',
        parser = parse_saved_search,
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
432

433
    """ saved_searches/create """
Josh Roesslein's avatar
Josh Roesslein committed
434
435
436
437
438
439
440
441
    create_saved_search = bind_api(
        path = '/saved_searches/create.json',
        method = 'POST',
        parser = parse_saved_search,
        allowed_param = ['query'],
        require_auth = True
    )

442
    """ saved_searches/destroy """
443
444
445
446
447
448
449
    destroy_saved_search = bind_api(
        path = '/saved_searches/destroy/{id}.json',
        method = 'DELETE',
        parser = parse_saved_search,
        allowed_param = ['id'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
450

451
    """ help/test """
Josh Roesslein's avatar
Josh Roesslein committed
452
    def test(self):
453
454
455
456
457
458
459
460
        try:
            return bind_api(
                path = '/help/test.json',
                parser = parse_return_true
            )(self)
        except TweepError:
            return False

Josh Roesslein's avatar
Josh Roesslein committed
461
462
    def create_list(self, *args, **kargs):
        return bind_api(
Josh Roesslein's avatar
Josh Roesslein committed
463
            path = '/%s/lists.json' % self.auth.get_username(),
Josh Roesslein's avatar
Josh Roesslein committed
464
465
            method = 'POST',
            parser = parse_list,
466
            allowed_param = ['name', 'mode', 'description'],
Josh Roesslein's avatar
Josh Roesslein committed
467
468
469
            require_auth = True
        )(self, *args, **kargs)

Josh Roesslein's avatar
Josh Roesslein committed
470
471
472
473
474
475
476
477
    def destroy_list(self, slug):
        return bind_api(
            path = '/%s/lists/%s.json' % (self.auth.get_username(), slug),
            method = 'DELETE',
            parser = parse_list,
            require_auth = True
        )(self)

Josh Roesslein's avatar
Josh Roesslein committed
478
479
    def update_list(self, slug, *args, **kargs):
        return bind_api(
Josh Roesslein's avatar
Josh Roesslein committed
480
            path = '/%s/lists/%s.json' % (self.auth.get_username(), slug),
Josh Roesslein's avatar
Josh Roesslein committed
481
482
            method = 'POST',
            parser = parse_list,
483
            allowed_param = ['name', 'mode', 'description'],
Josh Roesslein's avatar
Josh Roesslein committed
484
485
486
            require_auth = True
        )(self, *args, **kargs)

487
488
489
490
491
492
    lists = bind_api(
        path = '/{user}/lists.json',
        parser = parse_lists,
        allowed_param = ['user', 'cursor'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
493

494
495
496
497
498
499
    lists_memberships = bind_api(
        path = '/{user}/lists/memberships.json',
        parser = parse_lists,
        allowed_param = ['user', 'cursor'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
500

501
502
503
504
505
506
    lists_subscriptions = bind_api(
        path = '/{user}/lists/subscriptions.json',
        parser = parse_lists,
        allowed_param = ['user', 'cursor'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
507

508
509
510
511
512
    list_timeline = bind_api(
        path = '/{owner}/lists/{slug}/statuses.json',
        parser = parse_statuses,
        allowed_param = ['owner', 'slug', 'since_id', 'max_id', 'count', 'page']
    )
Josh Roesslein's avatar
Josh Roesslein committed
513

514
515
516
517
518
    get_list = bind_api(
        path = '/{owner}/lists/{slug}.json',
        parser = parse_list,
        allowed_param = ['owner', 'slug']
    )
Josh Roesslein's avatar
Josh Roesslein committed
519
520
521
522
523

    def add_list_member(self, slug, *args, **kargs):
        return bind_api(
            path = '/%s/%s/members.json' % (self.auth.get_username(), slug),
            method = 'POST',
Josh Roesslein's avatar
Josh Roesslein committed
524
            parser = parse_list,
Josh Roesslein's avatar
Josh Roesslein committed
525
526
527
528
529
530
531
532
            allowed_param = ['id'],
            require_auth = True
        )(self, *args, **kargs)

    def remove_list_member(self, slug, *args, **kargs):
        return bind_api(
            path = '/%s/%s/members.json' % (self.auth.get_username(), slug),
            method = 'DELETE',
533
            parser = parse_list,
Josh Roesslein's avatar
Josh Roesslein committed
534
535
536
537
            allowed_param = ['id'],
            require_auth = True
        )(self, *args, **kargs)

538
539
540
541
542
    list_members = bind_api(
        path = '/{owner}/{slug}/members.json',
        parser = parse_users,
        allowed_param = ['owner', 'slug', 'cursor']
    )
Josh Roesslein's avatar
Josh Roesslein committed
543
544
545
546
547
548
549
550
551
552

    def is_list_member(self, owner, slug, user_id):
        try:
            return bind_api(
                path = '/%s/%s/members/%s.json' % (owner, slug, user_id),
                parser = parse_user
            )(self)
        except TweepError:
            return False

553
554
555
556
557
558
559
    subscribe_list = bind_api(
        path = '/{owner}/{slug}/subscribers.json',
        method = 'POST',
        parser = parse_list,
        allowed_param = ['owner', 'slug'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
560

561
562
563
564
565
566
567
    unsubscribe_list = bind_api(
        path = '/{owner}/{slug}/subscribers.json',
        method = 'DELETE',
        parser = parse_list,
        allowed_param = ['owner', 'slug'],
        require_auth = True
    )
Josh Roesslein's avatar
Josh Roesslein committed
568

569
570
571
572
573
    list_subscribers = bind_api(
        path = '/{owner}/{slug}/subscribers.json',
        parser = parse_users,
        allowed_param = ['owner', 'slug', 'cursor']
    )
Josh Roesslein's avatar
Josh Roesslein committed
574
575
576
577
578

    def is_subscribed_list(self, owner, slug, user_id):
        try:
            return bind_api(
                path = '/%s/%s/subscribers/%s.json' % (owner, slug, user_id),
579
                parser = parse_user
Josh Roesslein's avatar
Josh Roesslein committed
580
581
582
583
            )(self)
        except TweepError:
            return False

584
585
586
587
588
589
590
591
    """ trends/available [coming soon] """
    trends_available = bind_api(
        path = '/trends/available.json',
        parser = parse_json,
        allowed_param = ['lat', 'long']
    )

    """ trends/location [coming soon] """
592
593
594
595
596
    trends_location = bind_api(
        path = '/trends/{woeid}.json',
        parser = parse_json,
        allowed_param = ['woeid']
    )
597

598
    """ search """
599
600
601
602
603
604
    search = bind_api(
        search_api = True,
        path = '/search.json',
        parser = parse_search_results,
        allowed_param = ['q', 'lang', 'locale', 'rpp', 'page', 'since_id', 'geocode', 'show_user']
    )
605
    search.pagination_mode = 'page'
Josh Roesslein's avatar
Josh Roesslein committed
606

607
    """ trends """
608
609
610
611
612
    trends = bind_api(
        search_api = True,
        path = '/trends.json',
        parser = parse_json
    )
Josh Roesslein's avatar
Josh Roesslein committed
613

614
    """ trends/current """
615
616
617
618
619
620
    trends_current = bind_api(
        search_api = True,
        path = '/trends/current.json',
        parser = parse_json,
        allowed_param = ['exclude']
    )
621

622
    """ trends/daily """
623
624
625
626
627
628
    trends_daily = bind_api(
        search_api = True,
        path = '/trends/daily.json',
        parser = parse_json,
        allowed_param = ['date', 'exclude']
    )
629

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

638
    """ Internal use only """
Josh Roesslein's avatar
Josh Roesslein committed
639
    @staticmethod
Josh Roesslein's avatar
Josh Roesslein committed
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
    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.')
        except os.error, e:
            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',
            'Content-Length': len(body)
        }

        return headers, body
678