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

Mark Smith's avatar
Mark Smith committed
5
6
from __future__ import print_function

7
8
9
import os
import mimetypes

Mark Smith's avatar
Mark Smith committed
10
11
import six

Josh Roesslein's avatar
Josh Roesslein committed
12
13
from tweepy.binder import bind_api
from tweepy.error import TweepError
14
from tweepy.parsers import ModelParser, Parser
15
from tweepy.utils import list_to_csv
16

Josh Roesslein's avatar
Josh Roesslein committed
17

18
class API(object):
Josh Roesslein's avatar
Josh Roesslein committed
19
20
    """Twitter API"""

21
    def __init__(self, auth_handler=None,
22
                 host='api.twitter.com', search_host='search.twitter.com',
Florent Espanet's avatar
Florent Espanet committed
23
24
25
26
                 upload_host='upload.twitter.com', cache=None, api_root='/1.1',
                 search_root='', upload_root='/1.1', retry_count=0,
                 retry_delay=0, retry_errors=None, timeout=60, parser=None,
                 compression=False, wait_on_rate_limit=False,
27
28
29
30
31
32
                 wait_on_rate_limit_notify=False, proxy=''):
        """ Api instance Constructor

        :param auth_handler:
        :param host:  url of the server of the rest api, default:'api.twitter.com'
        :param search_host: url of the search server, default:'search.twitter.com'
Florent Espanet's avatar
Florent Espanet committed
33
        :param upload_host: url of the upload server, default:'upload.twitter.com'
34
35
36
        :param cache: Cache to query if a GET method is used, default:None
        :param api_root: suffix of the api version, default:'/1.1'
        :param search_root: suffix of the search version, default:''
Florent Espanet's avatar
Florent Espanet committed
37
        :param upload_root: suffix of the upload version, default:'/1.1'
38
39
40
41
42
43
44
45
46
47
48
49
        :param retry_count: number of allowed retries, default:0
        :param retry_delay: delay in second between retries, default:0
        :param retry_errors: default:None
        :param timeout: delay before to consider the request as timed out in seconds, default:60
        :param parser: ModelParser instance to parse the responses, default:None
        :param compression: If the response is compressed, default:False
        :param wait_on_rate_limit: If the api wait when it hits the rate limit, default:False
        :param wait_on_rate_limit_notify: If the api print a notification when the rate limit is hit, default:False
        :param proxy: Url to use as proxy during the HTTP request, default:''

        :raise TypeError: If the given parser is not a ModelParser instance.
        """
Josh Roesslein's avatar
Josh Roesslein committed
50
        self.auth = auth_handler
Josh Roesslein's avatar
Josh Roesslein committed
51
        self.host = host
52
        self.search_host = search_host
Florent Espanet's avatar
Florent Espanet committed
53
        self.upload_host = upload_host
Josh Roesslein's avatar
Josh Roesslein committed
54
        self.api_root = api_root
55
        self.search_root = search_root
Florent Espanet's avatar
Florent Espanet committed
56
        self.upload_root = upload_root
Josh Roesslein's avatar
Josh Roesslein committed
57
        self.cache = cache
Mike's avatar
Mike committed
58
        self.compression = compression
59
60
        self.retry_count = retry_count
        self.retry_delay = retry_delay
61
        self.retry_errors = retry_errors
62
        self.timeout = timeout
63
        self.wait_on_rate_limit = wait_on_rate_limit
64
        self.wait_on_rate_limit_notify = wait_on_rate_limit_notify
65
        self.parser = parser or ModelParser()
Aaron Hill's avatar
Aaron Hill committed
66
67
68
        self.proxy = {}
        if proxy:
            self.proxy['https'] = proxy
Josh Roesslein's avatar
Josh Roesslein committed
69

70
71
72
73
74
75
        # 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(
Mark Smith's avatar
Mark Smith committed
76
77
78
79
80
                '"parser" argument has to be an instance of "{required}".'
                ' It is currently a {actual}.'.format(
                    required=parser_type.__name__,
                    actual=type(self.parser)
                )
81
            )
Josh Roesslein's avatar
Josh Roesslein committed
82

83
84
    @property
    def home_timeline(self):
85
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/home_timeline
86
87
88
89
90
91
92
93
94
95
            :allowed_param:'since_id', 'max_id', 'count'
        """
        return bind_api(
            api=self,
            path='/statuses/home_timeline.json',
            payload_type='status', payload_list=True,
            allowed_param=['since_id', 'max_id', 'count'],
            require_auth=True
        )

Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
96
97
    def statuses_lookup(self, id_, include_entities=None,
                        trim_user=None, map_=None):
98
99
100
101
102
        return self._statuses_lookup(list_to_csv(id_), include_entities,
                                     trim_user, map_)

    @property
    def _statuses_lookup(self):
103
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/lookup
104
105
106
107
108
109
110
111
112
113
114
115
            :allowed_param:'id', 'include_entities', 'trim_user', 'map'
        """
        return bind_api(
            api=self,
            path='/statuses/lookup.json',
            payload_type='status', payload_list=True,
            allowed_param=['id', 'include_entities', 'trim_user', 'map'],
            require_auth=True
        )

    @property
    def user_timeline(self):
116
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/user_timeline
117
118
119
120
121
122
123
124
125
126
127
128
            :allowed_param:'id', 'user_id', 'screen_name', 'since_id'
        """
        return bind_api(
            api=self,
            path='/statuses/user_timeline.json',
            payload_type='status', payload_list=True,
            allowed_param=['id', 'user_id', 'screen_name', 'since_id',
                           'max_id', 'count', 'include_rts']
        )

    @property
    def mentions_timeline(self):
129
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/mentions_timeline
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
            :allowed_param:'since_id', 'max_id', 'count'
        """
        return bind_api(
            api=self,
            path='/statuses/mentions_timeline.json',
            payload_type='status', payload_list=True,
            allowed_param=['since_id', 'max_id', 'count'],
            require_auth=True
        )

    @property
    def related_results(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/related_results/show/%3id.format
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/related_results/show/{id}.json',
            payload_type='relation', payload_list=True,
            allowed_param=['id'],
            require_auth=False
        )

    @property
    def retweets_of_me(self):
155
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/retweets_of_me
156
157
158
159
160
161
162
163
164
165
166
167
            :allowed_param:'since_id', 'max_id', 'count'
        """
        return bind_api(
            api=self,
            path='/statuses/retweets_of_me.json',
            payload_type='status', payload_list=True,
            allowed_param=['since_id', 'max_id', 'count'],
            require_auth=True
        )

    @property
    def get_status(self):
168
169
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
            :allowed_param:'id'
170
171
172
173
174
175
176
177
        """
        return bind_api(
            api=self,
            path='/statuses/show.json',
            payload_type='status',
            allowed_param=['id']
        )

178
    def update_status(self, media_ids=None, *args, **kwargs):
179
        """ :reference: https://dev.twitter.com/rest/reference/post/statuses/update
180
            :allowed_param:'status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id', 'display_coordinates', 'media_ids'
181
        """
182
183
184
185
        post_data = {}
        if media_ids is not None:
            post_data["media_ids"] = list_to_csv(media_ids)
        
186
187
188
189
190
191
192
        return bind_api(
            api=self,
            path='/statuses/update.json',
            method='POST',
            payload_type='status',
            allowed_param=['status', 'in_reply_to_status_id', 'lat', 'long', 'source', 'place_id', 'display_coordinates'],
            require_auth=True
193
        )(post_data=post_data, *args, **kwargs)
194

Florent Espanet's avatar
Florent Espanet committed
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    def media_upload(self, filename, *args, **kwargs):
        """ :reference: https://dev.twitter.com/rest/reference/post/media/upload
            :allowed_param:
        """
        f = kwargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 3072, form_field='media', f=f)
        kwargs.update({'headers': headers, 'post_data': post_data})

        return bind_api(
            api=self,
            path='/media/upload.json',
            method='POST',
            payload_type='media',
            allowed_param=[],
            require_auth=True,
            upload_api=True
        )(*args, **kwargs)

213
    def update_with_media(self, filename, *args, **kwargs):
214
215
216
        """ :reference: https://dev.twitter.com/rest/reference/post/statuses/update_with_media
            :allowed_param:'status', 'possibly_sensitive', 'in_reply_to_status_id', 'lat', 'long', 'place_id', 'display_coordinates'
        """
217
218
        f = kwargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 3072, form_field='media[]', f=f)
219
220
221
        kwargs.update({'headers': headers, 'post_data': post_data})

        return bind_api(
222
            api=self,
223
            path='/statuses/update_with_media.json',
224
            method='POST',
225
            payload_type='status',
226
            allowed_param=[
227
228
229
230
                'status', 'possibly_sensitive', 'in_reply_to_status_id', 'lat', 'long',
                'place_id', 'display_coordinates'
            ],
            require_auth=True
Aaron Hill's avatar
Aaron Hill committed
231
        )(*args, **kwargs)
232

233
234
    @property
    def destroy_status(self):
235
        """ :reference: https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
236
237
238
239
240
241
242
243
244
245
246
247
248
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/statuses/destroy/{id}.json',
            method='POST',
            payload_type='status',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def retweet(self):
249
        """ :reference: https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
250
251
252
253
254
255
256
257
258
259
260
261
262
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/statuses/retweet/{id}.json',
            method='POST',
            payload_type='status',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def retweets(self):
263
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/retweets/%3Aid
264
265
266
267
268
269
270
271
272
273
274
275
            :allowed_param:'id', 'count'
        """
        return bind_api(
            api=self,
            path='/statuses/retweets/{id}.json',
            payload_type='status', payload_list=True,
            allowed_param=['id', 'count'],
            require_auth=True
        )

    @property
    def retweeters(self):
276
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/retweeters/ids
277
278
279
280
281
282
283
284
285
286
287
            :allowed_param:'id', 'cursor', 'stringify_ids
        """
        return bind_api(
            api=self,
            path='/statuses/retweeters/ids.json',
            payload_type='ids',
            allowed_param=['id', 'cursor', 'stringify_ids']
        )

    @property
    def get_user(self):
288
289
        """ :reference: https://dev.twitter.com/rest/reference/get/users/show
            :allowed_param:'id', 'user_id', 'screen_name'
290
291
292
293
294
295
296
297
298
299
        """
        return bind_api(
            api=self,
            path='/users/show.json',
            payload_type='user',
            allowed_param=['id', 'user_id', 'screen_name']
        )

    @property
    def get_oembed(self):
300
301
        """ :reference: https://dev.twitter.com/rest/reference/get/statuses/oembed
            :allowed_param:'id', 'url', 'maxwidth', 'hide_media', 'omit_script', 'align', 'related', 'lang'
302
303
304
305
306
307
308
309
        """
        return bind_api(
            api=self,
            path='/statuses/oembed.json',
            payload_type='json',
            allowed_param=['id', 'url', 'maxwidth', 'hide_media', 'omit_script', 'align', 'related', 'lang']
        )

chebee7i's avatar
chebee7i committed
310
    def lookup_users(self, user_ids=None, screen_names=None, include_entities=None):
311
        """ Perform bulk look up of users from user ID or screenname """
chebee7i's avatar
chebee7i committed
312
313
314
315
316
317
318
319
320
321
        post_data = {}
        if include_entities is not None:
            include_entities = 'true' if include_entities else 'false'
            post_data['include_entities'] = include_entities
        if user_ids:
            post_data['user_id'] = list_to_csv(user_ids)
        if screen_names:
            post_data['screen_name'] = list_to_csv(screen_names)

        return self._lookup_users(post_data=post_data)
322

323
324
    @property
    def _lookup_users(self):
325
        """ :reference: https://dev.twitter.com/rest/reference/get/users/lookup
chebee7i's avatar
chebee7i committed
326
            allowed_param='user_id', 'screen_name', 'include_entities'
327
328
329
330
331
        """
        return bind_api(
            api=self,
            path='/users/lookup.json',
            payload_type='user', payload_list=True,
chebee7i's avatar
chebee7i committed
332
            method='POST',
333
        )
334

Josh Roesslein's avatar
Josh Roesslein committed
335
    def me(self):
336
        """ Get the authenticated user """
Josh Roesslein's avatar
Josh Roesslein committed
337
        return self.get_user(screen_name=self.auth.get_username())
Josh Roesslein's avatar
Josh Roesslein committed
338

339
340
    @property
    def search_users(self):
341
        """ :reference: https://dev.twitter.com/rest/reference/get/users/search
342
343
344
345
346
347
348
349
350
351
352
353
            :allowed_param:'q', 'count', 'page'
        """
        return bind_api(
            api=self,
            path='/users/search.json',
            payload_type='user', payload_list=True,
            require_auth=True,
            allowed_param=['q', 'count', 'page']
        )

    @property
    def suggested_users(self):
354
355
        """ :reference: https://dev.twitter.com/rest/reference/get/users/suggestions/%3Aslug
            :allowed_param:'slug', 'lang'
356
357
358
359
360
361
362
363
364
365
366
        """
        return bind_api(
            api=self,
            path='/users/suggestions/{slug}.json',
            payload_type='user', payload_list=True,
            require_auth=True,
            allowed_param=['slug', 'lang']
        )

    @property
    def suggested_categories(self):
367
        """ :reference: https://dev.twitter.com/rest/reference/get/users/suggestions
368
369
370
371
372
373
374
375
376
377
378
379
            :allowed_param:'lang'
        """
        return bind_api(
            api=self,
            path='/users/suggestions.json',
            payload_type='category', payload_list=True,
            allowed_param=['lang'],
            require_auth=True
        )

    @property
    def suggested_users_tweets(self):
380
        """ :reference: https://dev.twitter.com/rest/reference/get/users/suggestions/%3Aslug/members
381
382
383
384
385
386
387
388
389
390
391
392
            :allowed_param:'slug'
        """
        return bind_api(
            api=self,
            path='/users/suggestions/{slug}/members.json',
            payload_type='status', payload_list=True,
            allowed_param=['slug'],
            require_auth=True
        )

    @property
    def direct_messages(self):
393
        """ :reference: https://dev.twitter.com/rest/reference/get/direct_messages
394
395
396
397
398
399
400
401
402
403
404
405
            :allowed_param:'since_id', 'max_id', 'count'
        """
        return bind_api(
            api=self,
            path='/direct_messages.json',
            payload_type='direct_message', payload_list=True,
            allowed_param=['since_id', 'max_id', 'count'],
            require_auth=True
        )

    @property
    def get_direct_message(self):
406
        """ :reference: https://dev.twitter.com/rest/reference/get/direct_messages/show
407
408
409
410
411
412
413
414
415
416
417
418
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/direct_messages/show/{id}.json',
            payload_type='direct_message',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def sent_direct_messages(self):
419
        """ :reference: https://dev.twitter.com/rest/reference/get/direct_messages/sent
420
421
422
423
424
425
426
427
428
429
430
431
            :allowed_param:'since_id', 'max_id', 'count', 'page'
        """
        return bind_api(
            api=self,
            path='/direct_messages/sent.json',
            payload_type='direct_message', payload_list=True,
            allowed_param=['since_id', 'max_id', 'count', 'page'],
            require_auth=True
        )

    @property
    def send_direct_message(self):
432
        """ :reference: https://dev.twitter.com/rest/reference/post/direct_messages/new
433
434
435
436
437
438
439
440
441
442
443
444
445
            :allowed_param:'user', 'screen_name', 'user_id', 'text'
        """
        return bind_api(
            api=self,
            path='/direct_messages/new.json',
            method='POST',
            payload_type='direct_message',
            allowed_param=['user', 'screen_name', 'user_id', 'text'],
            require_auth=True
        )

    @property
    def destroy_direct_message(self):
446
        """ :reference: https://dev.twitter.com/rest/reference/post/direct_messages/destroy
447
448
449
450
451
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/direct_messages/destroy.json',
452
            method='POST',
453
454
455
456
457
458
459
            payload_type='direct_message',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def create_friendship(self):
460
        """ :reference: https://dev.twitter.com/rest/reference/post/friendships/create
461
462
463
464
465
466
467
468
469
470
471
472
473
            :allowed_param:'id', 'user_id', 'screen_name', 'follow'
        """
        return bind_api(
            api=self,
            path='/friendships/create.json',
            method='POST',
            payload_type='user',
            allowed_param=['id', 'user_id', 'screen_name', 'follow'],
            require_auth=True
        )

    @property
    def destroy_friendship(self):
474
        """ :reference: https://dev.twitter.com/rest/reference/post/friendships/destroy
475
476
477
478
479
            :allowed_param:'id', 'user_id', 'screen_name'
        """
        return bind_api(
            api=self,
            path='/friendships/destroy.json',
480
            method='POST',
481
482
483
484
485
486
487
            payload_type='user',
            allowed_param=['id', 'user_id', 'screen_name'],
            require_auth=True
        )

    @property
    def show_friendship(self):
488
489
        """ :reference: https://dev.twitter.com/rest/reference/get/friendships/show
            :allowed_param:'source_id', 'source_screen_name'
490
491
492
493
494
495
496
497
498
        """
        return bind_api(
            api=self,
            path='/friendships/show.json',
            payload_type='friendship',
            allowed_param=['source_id', 'source_screen_name',
                           'target_id', 'target_screen_name']
        )

499
    def lookup_friendships(self, user_ids=None, screen_names=None):
500
        """ Perform bulk look up of friendships from user ID or screenname """
Santosh Kumar's avatar
Santosh Kumar committed
501
        return self._lookup_friendships(list_to_csv(user_ids), list_to_csv(screen_names))
502

503
504
    @property
    def _lookup_friendships(self):
505
        """ :reference: https://dev.twitter.com/rest/reference/get/friendships/lookup
506
507
508
509
510
511
512
513
514
515
516
517
            :allowed_param:'user_id', 'screen_name'
        """
        return bind_api(
            api=self,
            path='/friendships/lookup.json',
            payload_type='relationship', payload_list=True,
            allowed_param=['user_id', 'screen_name'],
            require_auth=True
        )

    @property
    def friends_ids(self):
518
519
        """ :reference: https://dev.twitter.com/rest/reference/get/friends/ids
            :allowed_param:'id', 'user_id', 'screen_name', 'cursor'
520
521
522
523
524
525
526
527
528
529
        """
        return bind_api(
            api=self,
            path='/friends/ids.json',
            payload_type='ids',
            allowed_param=['id', 'user_id', 'screen_name', 'cursor']
        )

    @property
    def friends(self):
530
531
        """ :reference: https://dev.twitter.com/rest/reference/get/friends/list
            :allowed_param:'id', 'user_id', 'screen_name', 'cursor'
532
533
534
535
536
537
538
539
540
541
        """
        return bind_api(
            api=self,
            path='/friends/list.json',
            payload_type='user', payload_list=True,
            allowed_param=['id', 'user_id', 'screen_name', 'cursor']
        )

    @property
    def friendships_incoming(self):
542
543
        """ :reference: https://dev.twitter.com/rest/reference/get/friendships/incoming
            :allowed_param:'cursor'
544
545
546
547
548
549
550
551
552
553
        """
        return bind_api(
            api=self,
            path='/friendships/incoming.json',
            payload_type='ids',
            allowed_param=['cursor']
        )

    @property
    def friendships_outgoing(self):
554
555
        """ :reference: https://dev.twitter.com/rest/reference/get/friendships/outgoing
            :allowed_param:'cursor'
556
557
558
559
560
561
562
563
564
565
        """
        return bind_api(
            api=self,
            path='/friendships/outgoing.json',
            payload_type='ids',
            allowed_param=['cursor']
        )

    @property
    def followers_ids(self):
566
567
        """ :reference: https://dev.twitter.com/rest/reference/get/followers/ids
            :allowed_param:'id', 'user_id', 'screen_name', 'cursor', 'count'
568
569
570
571
572
573
574
575
576
577
        """
        return bind_api(
            api=self,
            path='/followers/ids.json',
            payload_type='ids',
            allowed_param=['id', 'user_id', 'screen_name', 'cursor', 'count']
        )

    @property
    def followers(self):
578
        """ :reference: https://dev.twitter.com/rest/reference/get/followers/list
579
580
581
582
583
584
585
586
587
588
            :allowed_param:'id', 'user_id', 'screen_name', 'cursor', 'count', 'skip_status', 'include_user_entities'
        """
        return bind_api(
            api=self,
            path='/followers/list.json',
            payload_type='user', payload_list=True,
            allowed_param=['id', 'user_id', 'screen_name', 'cursor', 'count',
                           'skip_status', 'include_user_entities']
        )

589
    def verify_credentials(self, **kargs):
590
591
592
        """ :reference: https://dev.twitter.com/rest/reference/get/account/verify_credentials
            :allowed_param:'include_entities', 'skip_status'
        """
Josh Roesslein's avatar
Josh Roesslein committed
593
594
        try:
            return bind_api(
595
596
597
598
599
                api=self,
                path='/account/verify_credentials.json',
                payload_type='user',
                require_auth=True,
                allowed_param=['include_entities', 'skip_status'],
Aaron Hill's avatar
Aaron Hill committed
600
            )(**kargs)
601
        except TweepError as e:
602
603
604
            if e.response and e.response.status == 401:
                return False
            raise
Josh Roesslein's avatar
Josh Roesslein committed
605

606
607
    @property
    def rate_limit_status(self):
608
        """ :reference: https://dev.twitter.com/rest/reference/get/application/rate_limit_status
609
610
611
612
613
614
615
616
617
618
619
620
            :allowed_param:'resources'
        """
        return bind_api(
            api=self,
            path='/application/rate_limit_status.json',
            payload_type='json',
            allowed_param=['resources'],
            use_cache=False
        )

    @property
    def set_delivery_device(self):
621
        """ :reference: https://dev.twitter.com/rest/reference/post/account/update_delivery_device
622
623
624
625
626
627
628
629
630
631
632
633
634
635
            :allowed_param:'device'
        """
        return bind_api(
            api=self,
            path='/account/update_delivery_device.json',
            method='POST',
            allowed_param=['device'],
            payload_type='user',
            require_auth=True
        )

    @property
    def update_profile_colors(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/account/update_profile_colors
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
636
637
638
            :allowed_param:'profile_background_color', 'profile_text_color',
             'profile_link_color', 'profile_sidebar_fill_color',
             'profile_sidebar_border_color'],
639
640
641
642
643
644
645
646
647
648
649
650
651
        """
        return bind_api(
            api=self,
            path='/account/update_profile_colors.json',
            method='POST',
            payload_type='user',
            allowed_param=['profile_background_color', 'profile_text_color',
                           'profile_link_color', 'profile_sidebar_fill_color',
                           'profile_sidebar_border_color'],
            require_auth=True
        )

    def update_profile_image(self, filename, file_=None):
652
653
654
        """ :reference: https://dev.twitter.com/rest/reference/post/account/update_profile_image
            :allowed_param:'include_entities', 'skip_status'
        """
655
656
657
658
659
660
        headers, post_data = API._pack_image(filename, 700, f=file_)
        return bind_api(
            api=self,
            path='/account/update_profile_image.json',
            method='POST',
            payload_type='user',
661
            allowed_param=['include_entities', 'skip_status'],
662
            require_auth=True
Josh Roesslein's avatar
Josh Roesslein committed
663
664
        )(self, post_data=post_data, headers=headers)

665
    def update_profile_background_image(self, filename, **kargs):
666
667
668
        """ :reference: https://dev.twitter.com/rest/reference/post/account/update_profile_background_image
            :allowed_param:'tile', 'include_entities', 'skip_status', 'use'
        """
669
670
        f = kargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 800, f=f)
Josh Roesslein's avatar
Josh Roesslein committed
671
        bind_api(
Jordi Riera's avatar
Jordi Riera committed
672
            api=self,
673
674
675
            path='/account/update_profile_background_image.json',
            method='POST',
            payload_type='user',
Arudmin's avatar
Arudmin committed
676
            allowed_param=['tile', 'include_entities', 'skip_status', 'use'],
677
            require_auth=True
Mark Smith's avatar
Mark Smith committed
678
        )(post_data=post_data, headers=headers)
Josh Roesslein's avatar
Josh Roesslein committed
679

680
    def update_profile_banner(self, filename, **kargs):
681
682
683
        """ :reference: https://dev.twitter.com/rest/reference/post/account/update_profile_banner
            :allowed_param:'width', 'height', 'offset_left', 'offset_right'
        """
684
685
        f = kargs.pop('file', None)
        headers, post_data = API._pack_image(filename, 700, form_field="banner", f=f)
686
        bind_api(
Jordi Riera's avatar
Jordi Riera committed
687
            api=self,
688
689
690
691
            path='/account/update_profile_banner.json',
            method='POST',
            allowed_param=['width', 'height', 'offset_left', 'offset_right'],
            require_auth=True
Mark Smith's avatar
Mark Smith committed
692
        )(post_data=post_data, headers=headers)
693

694
695
    @property
    def update_profile(self):
696
        """ :reference: https://dev.twitter.com/rest/reference/post/account/update_profile
697
698
699
700
701
702
703
704
705
706
707
708
709
            :allowed_param:'name', 'url', 'location', 'description'
        """
        return bind_api(
            api=self,
            path='/account/update_profile.json',
            method='POST',
            payload_type='user',
            allowed_param=['name', 'url', 'location', 'description'],
            require_auth=True
        )

    @property
    def favorites(self):
710
711
        """ :reference: https://dev.twitter.com/rest/reference/get/favorites/list
            :allowed_param:'screen_name', 'user_id', 'max_id', 'count', 'since_id', 'max_id'
712
713
714
715
716
717
718
719
720
721
        """
        return bind_api(
            api=self,
            path='/favorites/list.json',
            payload_type='status', payload_list=True,
            allowed_param=['screen_name', 'user_id', 'max_id', 'count', 'since_id', 'max_id']
        )

    @property
    def create_favorite(self):
722
        """ :reference:https://dev.twitter.com/rest/reference/post/favorites/create
723
724
725
726
727
728
729
730
731
732
733
734
735
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/favorites/create.json',
            method='POST',
            payload_type='status',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def destroy_favorite(self):
736
        """ :reference: https://dev.twitter.com/rest/reference/post/favorites/destroy
737
738
739
740
741
742
743
744
745
746
747
748
749
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/favorites/destroy.json',
            method='POST',
            payload_type='status',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def create_block(self):
750
        """ :reference: https://dev.twitter.com/rest/reference/post/blocks/create
751
752
753
754
755
756
757
758
759
760
761
762
763
            :allowed_param:'id', 'user_id', 'screen_name'
        """
        return bind_api(
            api=self,
            path='/blocks/create.json',
            method='POST',
            payload_type='user',
            allowed_param=['id', 'user_id', 'screen_name'],
            require_auth=True
        )

    @property
    def destroy_block(self):
764
        """ :reference: https://dev.twitter.com/rest/reference/post/blocks/destroy
765
766
767
768
769
            :allowed_param:'id', 'user_id', 'screen_name'
        """
        return bind_api(
            api=self,
            path='/blocks/destroy.json',
770
            method='POST',
771
772
773
774
775
776
777
            payload_type='user',
            allowed_param=['id', 'user_id', 'screen_name'],
            require_auth=True
        )

    @property
    def blocks(self):
778
        """ :reference: https://dev.twitter.com/rest/reference/get/blocks/list
779
780
781
782
783
784
785
786
787
788
789
790
            :allowed_param:'cursor'
        """
        return bind_api(
            api=self,
            path='/blocks/list.json',
            payload_type='user', payload_list=True,
            allowed_param=['cursor'],
            require_auth=True
        )

    @property
    def blocks_ids(self):
791
        """ :reference: https://dev.twitter.com/rest/reference/get/blocks/ids """
792
793
794
795
796
797
798
799
800
        return bind_api(
            api=self,
            path='/blocks/ids.json',
            payload_type='json',
            require_auth=True
        )

    @property
    def report_spam(self):
801
        """ :reference: https://dev.twitter.com/rest/reference/post/users/report_spam
802
803
804
805
806
807
808
809
810
811
812
813
814
            :allowed_param:'user_id', 'screen_name'
        """
        return bind_api(
            api=self,
            path='/users/report_spam.json',
            method='POST',
            payload_type='user',
            allowed_param=['user_id', 'screen_name'],
            require_auth=True
        )

    @property
    def saved_searches(self):
815
        """ :reference: https://dev.twitter.com/rest/reference/get/saved_searches/show/%3Aid """
816
817
818
819
820
821
822
823
824
        return bind_api(
            api=self,
            path='/saved_searches/list.json',
            payload_type='saved_search', payload_list=True,
            require_auth=True
        )

    @property
    def get_saved_search(self):
825
        """ :reference: https://dev.twitter.com/rest/reference/get/saved_searches/show/%3Aid
826
827
828
829
830
831
832
833
834
835
836
837
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/saved_searches/show/{id}.json',
            payload_type='saved_search',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def create_saved_search(self):
838
        """ :reference: https://dev.twitter.com/rest/reference/post/saved_searches/create
839
840
841
842
843
844
845
846
847
848
849
850
851
            :allowed_param:'query'
        """
        return bind_api(
            api=self,
            path='/saved_searches/create.json',
            method='POST',
            payload_type='saved_search',
            allowed_param=['query'],
            require_auth=True
        )

    @property
    def destroy_saved_search(self):
852
        """ :reference: https://dev.twitter.com/rest/reference/post/saved_searches/destroy/%3Aid
853
854
855
856
857
858
859
860
861
862
863
864
865
            :allowed_param:'id'
        """
        return bind_api(
            api=self,
            path='/saved_searches/destroy/{id}.json',
            method='POST',
            payload_type='saved_search',
            allowed_param=['id'],
            require_auth=True
        )

    @property
    def create_list(self):
866
        """ :reference: https://dev.twitter.com/rest/reference/post/lists/create
867
868
869
870
871
872
873
874
875
876
877
878
879
            :allowed_param:'name', 'mode', 'description'
        """
        return bind_api(
            api=self,
            path='/lists/create.json',
            method='POST',
            payload_type='list',
            allowed_param=['name', 'mode', 'description'],
            require_auth=True
        )

    @property
    def destroy_list(self):
880
        """ :reference: https://dev.twitter.com/rest/reference/post/lists/destroy
881
882
883
884
885
886
887
888
889
890
891
892
893
            :allowed_param:'owner_screen_name', 'owner_id', 'list_id', 'slug'
        """
        return bind_api(
            api=self,
            path='/lists/destroy.json',
            method='POST',
            payload_type='list',
            allowed_param=['owner_screen_name', 'owner_id', 'list_id', 'slug'],
            require_auth=True
        )

    @property
    def update_list(self):
894
        """ :reference: https://dev.twitter.com/rest/reference/post/lists/update
895
896
897
898
899
900
901
902
903
904
905
906
907
            :allowed_param: list_id', 'slug', 'name', 'mode', 'description', 'owner_screen_name', 'owner_id'
        """
        return bind_api(
            api=self,
            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
        )

    @property
    def lists_all(self):
908
        """ :reference: https://dev.twitter.com/rest/reference/get/lists/list
909
910
911
912
913
914
915
916
917
918
919
920
            :allowed_param:'screen_name', 'user_id'
        """
        return bind_api(
            api=self,
            path='/lists/list.json',
            payload_type='list', payload_list=True,
            allowed_param=['screen_name', 'user_id'],
            require_auth=True
        )

    @property
    def lists_memberships(self):
921
        """ :reference: https://dev.twitter.com/rest/reference/get/lists/memberships
922
923
924
925
926
927
928
929
930
931
932
933
            :allowed_param:'screen_name', 'user_id', 'filter_to_owned_lists', 'cursor'
        """
        return bind_api(
            api=self,
            path='/lists/memberships.json',
            payload_type='list', payload_list=True,
            allowed_param=['screen_name', 'user_id', 'filter_to_owned_lists', 'cursor'],
            require_auth=True
        )

    @property
    def lists_subscriptions(self):
934
        """ :reference: https://dev.twitter.com/rest/reference/get/lists/subscriptions
935
936
937
938
939
940
941
942
943
944
945
946
947
            :allowed_param:'screen_name', 'user_id', 'cursor'
        """
        return bind_api(
            api=self,
            path='/lists/subscriptions.json',
            payload_type='list', payload_list=True,
            allowed_param=['screen_name', 'user_id', 'cursor'],
            require_auth=True
        )

    @property
    def list_timeline(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/lists/statuses
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
948
949
            :allowed_param:'owner_screen_name', 'slug', 'owner_id', 'list_id',
             'since_id', 'max_id', 'count', 'include_rts
950
951
952
953
954
        """
        return bind_api(
            api=self,
            path='/lists/statuses.json',
            payload_type='status', payload_list=True,
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
955
956
957
            allowed_param=['owner_screen_name', 'slug', 'owner_id',
                           'list_id', 'since_id', 'max_id', 'count',
                           'include_rts']
958
959
960
961
        )

    @property
    def get_list(self):
962
963
        """ :reference: https://dev.twitter.com/rest/reference/get/lists/show
            :allowed_param:'owner_screen_name', 'owner_id', 'slug', 'list_id'
964
965
966
967
968
969
970
971
972
973
974
        """
        return bind_api(
            api=self,
            path='/lists/show.json',
            payload_type='list',
            allowed_param=['owner_screen_name', 'owner_id', 'slug', 'list_id']
        )

    @property
    def add_list_member(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/create
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
975
976
            :allowed_param:'screen_name', 'user_id', 'owner_screen_name',
             'owner_id', 'slug', 'list_id'
977
978
979
980
981
982
        """
        return bind_api(
            api=self,
            path='/lists/members/create.json',
            method='POST',
            payload_type='list',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
983
984
            allowed_param=['screen_name', 'user_id', 'owner_screen_name',
                           'owner_id', 'slug', 'list_id'],
985
986
987
988
989
990
            require_auth=True
        )

    @property
    def remove_list_member(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/destroy
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
991
992
            :allowed_param:'screen_name', 'user_id', 'owner_screen_name',
             'owner_id', 'slug', 'list_id'
993
994
995
996
997
998
        """
        return bind_api(
            api=self,
            path='/lists/members/destroy.json',
            method='POST',
            payload_type='list',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
999
1000
            allowed_param=['screen_name', 'user_id', 'owner_screen_name',
                           'owner_id', 'slug', 'list_id'],
1001
1002
            require_auth=True
        )
1003

kk6's avatar
kk6 committed
1004
    def add_list_members(self, screen_name=None, user_id=None, slug=None,
1005
                         list_id=None, owner_id=None, owner_screen_name=None):
1006
        """ Perform bulk add of list members from user ID or screenname """
kk6's avatar
kk6 committed
1007
1008
        return self._add_list_members(list_to_csv(screen_name),
                                      list_to_csv(user_id),
1009
1010
1011
                                      slug, list_id, owner_id,
                                      owner_screen_name)

1012
1013
1014
    @property
    def _add_list_members(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/create_all
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1015
1016
            :allowed_param:'screen_name', 'user_id', 'slug', 'lit_id',
            'owner_id', 'owner_screen_name'
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1017

1018
1019
1020
1021
1022
1023
        """
        return bind_api(
            api=self,
            path='/lists/members/create_all.json',
            method='POST',
            payload_type='list',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1024
1025
            allowed_param=['screen_name', 'user_id', 'slug', 'lit_id',
                           'owner_id', 'owner_screen_name'],
1026
1027
1028
            require_auth=True
        )

kk6's avatar
kk6 committed
1029
    def remove_list_members(self, screen_name=None, user_id=None, slug=None,
1030
1031
                            list_id=None, owner_id=None, owner_screen_name=None):
        """ Perform bulk remove of list members from user ID or screenname """
kk6's avatar
kk6 committed
1032
        return self._remove_list_members(list_to_csv(screen_name),
1033
1034
1035
1036
1037
1038
1039
                                         list_to_csv(user_id),
                                         slug, list_id, owner_id,
                                         owner_screen_name)

    @property
    def _remove_list_members(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/lists/members/destroy_all
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1040
1041
            :allowed_param:'screen_name', 'user_id', 'slug', 'lit_id',
            'owner_id', 'owner_screen_name'
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1042

1043
1044
1045
1046
1047
1048
        """
        return bind_api(
            api=self,
            path='/lists/members/destroy_all.json',
            method='POST',
            payload_type='list',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1049
1050
            allowed_param=['screen_name', 'user_id', 'slug', 'lit_id',
                           'owner_id', 'owner_screen_name'],
1051
1052
            require_auth=True
        )
1053

1054
1055
1056
    @property
    def list_members(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/lists/members
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1057
1058
            :allowed_param:'owner_screen_name', 'slug', 'list_id',
             'owner_id', 'cursor
1059
1060
1061
1062
1063
        """
        return bind_api(
            api=self,
            path='/lists/members.json',
            payload_type='user', payload_list=True,
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1064
1065
            allowed_param=['owner_screen_name', 'slug', 'list_id',
                           'owner_id', 'cursor']
1066
1067
1068
1069
1070
        )

    @property
    def show_list_member(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/lists/members/show
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1071
1072
            :allowed_param:'list_id', 'slug', 'user_id', 'screen_name',
             'owner_screen_name', 'owner_id
1073
1074
1075
1076
1077
        """
        return bind_api(
            api=self,
            path='/lists/members/show.json',
            payload_type='user',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1078
1079
            allowed_param=['list_id', 'slug', 'user_id', 'screen_name',
                           'owner_screen_name', 'owner_id']
1080
1081
1082
1083
1084
        )

    @property
    def subscribe_list(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/lists/subscribers/create
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1085
1086
            :allowed_param:'owner_screen_name', 'slug', 'owner_id',
            'list_id'
1087
1088
1089
1090
1091
1092
        """
        return bind_api(
            api=self,
            path='/lists/subscribers/create.json',
            method='POST',
            payload_type='list',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1093
1094
            allowed_param=['owner_screen_name', 'slug', 'owner_id',
                           'list_id'],
1095
1096
1097
1098
1099
1100
            require_auth=True
        )

    @property
    def unsubscribe_list(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/post/lists/subscribers/destroy
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1101
1102
            :allowed_param:'owner_screen_name', 'slug', 'owner_id',
            'list_id'
1103
1104
1105
1106
1107
1108
        """
        return bind_api(
            api=self,
            path='/lists/subscribers/destroy.json',
            method='POST',
            payload_type='list',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1109
1110
            allowed_param=['owner_screen_name', 'slug', 'owner_id',
                           'list_id'],
1111
1112
1113
1114
1115
1116
            require_auth=True
        )

    @property
    def list_subscribers(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/lists/subscribers
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1117
1118
            :allowed_param:'owner_screen_name', 'slug', 'owner_id',
             'list_id', 'cursor
1119
1120
1121
1122
1123
        """
        return bind_api(
            api=self,
            path='/lists/subscribers.json',
            payload_type='user', payload_list=True,
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1124
1125
            allowed_param=['owner_screen_name', 'slug', 'owner_id',
                           'list_id', 'cursor']
1126
1127
1128
1129
1130
        )

    @property
    def show_list_subscriber(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/lists/subscribers/show
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1131
1132
            :allowed_param:'owner_screen_name', 'slug', 'screen_name',
             'owner_id', 'list_id', 'user_id
1133
1134
1135
1136
1137
        """
        return bind_api(
            api=self,
            path='/lists/subscribers/show.json',
            payload_type='user',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1138
1139
            allowed_param=['owner_screen_name', 'slug', 'screen_name',
                           'owner_id', 'list_id', 'user_id']
1140
1141
1142
1143
        )

    @property
    def trends_available(self):
1144
        """ :reference: https://dev.twitter.com/rest/reference/get/trends/available """
1145
1146
1147
1148
1149
1150
1151
1152
        return bind_api(
            api=self,
            path='/trends/available.json',
            payload_type='json'
        )

    @property
    def trends_place(self):
1153
1154
        """ :reference: https://dev.twitter.com/rest/reference/get/trends/place
            :allowed_param:'id', 'exclude'
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
        """
        return bind_api(
            api=self,
            path='/trends/place.json',
            payload_type='json',
            allowed_param=['id', 'exclude']
        )

    @property
    def trends_closest(self):
1165
1166
        """ :reference: https://dev.twitter.com/rest/reference/get/trends/closest
            :allowed_param:'lat', 'long'
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
        """
        return bind_api(
            api=self,
            path='/trends/closest.json',
            payload_type='json',
            allowed_param=['lat', 'long']
        )

    @property
    def search(self):
1177
        """ :reference: https://dev.twitter.com/rest/reference/get/search/tweets
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1178
1179
1180
            :allowed_param:'q', 'lang', 'locale', 'since_id', 'geocode',
             'max_id', 'since', 'until', 'result_type', 'count',
              'include_entities', 'from', 'to', 'source']
1181
1182
1183
1184
1185
        """
        return bind_api(
            api=self,
            path='/search/tweets.json',
            payload_type='search_results',
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1186
1187
1188
1189
            allowed_param=['q', 'lang', 'locale', 'since_id', 'geocode',
                           'max_id', 'since', 'until', 'result_type',
                           'count', 'include_entities', 'from',
                           'to', 'source']
1190
1191
1192
1193
        )

    @property
    def reverse_geocode(self):
1194
1195
        """ :reference: https://dev.twitter.com/rest/reference/get/geo/reverse_geocode
            :allowed_param:'lat', 'long', 'accuracy', 'granularity', 'max_results'
1196
1197
1198
1199
1200
        """
        return bind_api(
            api=self,
            path='/geo/reverse_geocode.json',
            payload_type='place', payload_list=True,
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1201
1202
            allowed_param=['lat', 'long', 'accuracy', 'granularity',
                           'max_results']
1203
1204
1205
1206
        )

    @property
    def geo_id(self):
1207
1208
        """ :reference: https://dev.twitter.com/rest/reference/get/geo/id/%3Aplace_id
            :allowed_param:'id'
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
        """
        return bind_api(
            api=self,
            path='/geo/id/{id}.json',
            payload_type='place',
            allowed_param=['id']
        )

    @property
    def geo_search(self):
        """ :reference: https://dev.twitter.com/docs/api/1.1/get/geo/search
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1220
1221
            :allowed_param:'lat', 'long', 'query', 'ip', 'granularity',
             'accuracy', 'max_results', 'contained_within
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1222

1223
1224
1225
1226
1227
        """
        return bind_api(
            api=self,
            path='/geo/search.json',
            payload_type='place', payload_list=True,
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1228
1229
            allowed_param=['lat', 'long', 'query', 'ip', 'granularity',
                           'accuracy', 'max_results', 'contained_within']
1230
1231
1232
1233
        )

    @property
    def geo_similar_places(self):
1234
1235
        """ :reference: https://dev.twitter.com/rest/reference/get/geo/similar_places
            :allowed_param:'lat', 'long', 'name', 'contained_within'
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
        """
        return bind_api(
            api=self,
            path='/geo/similar_places.json',
            payload_type='place', payload_list=True,
            allowed_param=['lat', 'long', 'name', 'contained_within']
        )

    @property
    def supported_languages(self):
1246
        """ :reference: https://dev.twitter.com/rest/reference/get/help/languages """
1247
1248
1249
1250
1251
1252
        return bind_api(
            api=self,
            path='/help/languages.json',
            payload_type='json',
            require_auth=True
        )
1253

1254
1255
    @property
    def configuration(self):
1256
        """ :reference: https://dev.twitter.com/rest/reference/get/help/configuration """
1257
1258
1259
1260
1261
1262
        return bind_api(
            api=self,
            path='/help/configuration.json',
            payload_type='json',
            require_auth=True
        )
1263

1264
    """ Internal use only """
1265

Josh Roesslein's avatar
Josh Roesslein committed
1266
    @staticmethod
1267
    def _pack_image(filename, max_size, form_field="image", f=None):
Josh Roesslein's avatar
Josh Roesslein committed
1268
1269
        """Pack image from file into multipart-formdata post body"""
        # image must be less than 700kb in size
1270
        if f is None:
1271
1272
            try:
                if os.path.getsize(filename) > (max_size * 1024):
Steven Skoczen's avatar
Steven Skoczen committed
1273
                    raise TweepError('File is too big, must be less than %skb.' % max_size)
1274
1275
1276
1277
1278
1279
            except os.error:
                raise TweepError('Unable to access file')

            # build the mulitpart-formdata body
            fp = open(filename, 'rb')
        else:
1280
            f.seek(0, 2)  # Seek to end of file
1281
            if f.tell() > (max_size * 1024):
Steven Skoczen's avatar
Steven Skoczen committed
1282
                raise TweepError('File is too big, must be less than %skb.' % max_size)
1283
            f.seek(0)  # Reset to beginning of file
1284
            fp = f
Josh Roesslein's avatar
Josh Roesslein committed
1285
1286
1287
1288
1289
1290
1291
1292
1293

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

Mark Smith's avatar
Mark Smith committed
1294
        if isinstance(filename, six.text_type):
1295
            filename = filename.encode("utf-8")
1296

Mark Smith's avatar
Mark Smith committed
1297
        BOUNDARY = b'Tw3ePy'
Omer Murat Yildirim's avatar
Omer Murat Yildirim committed
1298
        body = list()
Mark Smith's avatar
Mark Smith committed
1299
1300
1301
1302
1303
1304
        body.append(b'--' + BOUNDARY)
        body.append('Content-Disposition: form-data; name="{0}";'
                    ' filename="{1}"'.format(form_field, filename)
                    .encode('utf-8'))
        body.append('Content-Type: {0}'.format(file_type).encode('utf-8'))
        body.append(b'')
Josh Roesslein's avatar
Josh Roesslein committed
1305
        body.append(fp.read())
Mark Smith's avatar
Mark Smith committed
1306
1307
        body.append(b'--' + BOUNDARY + b'--')
        body.append(b'')
Josh Roesslein's avatar
Josh Roesslein committed
1308
        fp.close()
Mark Smith's avatar
Mark Smith committed
1309
        body = b'\r\n'.join(body)
Josh Roesslein's avatar
Josh Roesslein committed
1310
1311
1312
1313

        # build headers
        headers = {
            'Content-Type': 'multipart/form-data; boundary=Tw3ePy',
1314
            'Content-Length': str(len(body))
Josh Roesslein's avatar
Josh Roesslein committed
1315
1316
1317
        }

        return headers, body