From 460acae6287ad8e566a053db98089fa273bfb86d Mon Sep 17 00:00:00 2001 From: Florent Espanet Date: Thu, 15 Jan 2015 11:49:41 +0100 Subject: [PATCH] Add media/upload endpoint. The media/upload endpoint is located on a different server : upload.twitter.com. It returns a unique result model called `Media` containing the `media_id` and the image infos. See also : * [doc](https://dev.twitter.com/rest/reference/post/media/upload) --- tweepy/api.py | 29 ++++++++++++++++++++++++++--- tweepy/binder.py | 6 +++++- tweepy/models.py | 11 +++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/tweepy/api.py b/tweepy/api.py index e822823..756839e 100644 --- a/tweepy/api.py +++ b/tweepy/api.py @@ -20,18 +20,21 @@ class API(object): def __init__(self, auth_handler=None, host='api.twitter.com', search_host='search.twitter.com', - cache=None, api_root='/1.1', search_root='', - retry_count=0, retry_delay=0, retry_errors=None, timeout=60, - parser=None, compression=False, wait_on_rate_limit=False, + 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, 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' + :param upload_host: url of the upload server, default:'upload.twitter.com' :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:'' + :param upload_root: suffix of the upload version, default:'/1.1' :param retry_count: number of allowed retries, default:0 :param retry_delay: delay in second between retries, default:0 :param retry_errors: default:None @@ -47,8 +50,10 @@ class API(object): self.auth = auth_handler self.host = host self.search_host = search_host + self.upload_host = upload_host self.api_root = api_root self.search_root = search_root + self.upload_root = upload_root self.cache = cache self.compression = compression self.retry_count = retry_count @@ -184,6 +189,24 @@ class API(object): require_auth=True ) + 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) + def update_with_media(self, filename, *args, **kwargs): """ :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' diff --git a/tweepy/binder.py b/tweepy/binder.py index 12011a8..2ac6146 100644 --- a/tweepy/binder.py +++ b/tweepy/binder.py @@ -33,6 +33,7 @@ def bind_api(**config): method = config.get('method', 'GET') require_auth = config.get('require_auth', False) search_api = config.get('search_api', False) + upload_api = config.get('upload_api', False) use_cache = config.get('use_cache', True) session = requests.Session() @@ -61,6 +62,8 @@ def bind_api(**config): # Pick correct URL root to use if self.search_api: self.api_root = api.search_root + elif self.upload_api: + self.api_root = api.upload_root else: self.api_root = api.api_root @@ -69,6 +72,8 @@ def bind_api(**config): if self.search_api: self.host = api.search_host + elif self.upload_api: + self.host = api.upload_host else: self.host = api.host @@ -181,7 +186,6 @@ def bind_api(**config): auth=auth, proxies=self.api.proxy) except Exception as e: - raise TweepError('Failed to send request: %s' % e) rem_calls = resp.headers.get('x-rate-limit-remaining') if rem_calls is not None: diff --git a/tweepy/models.py b/tweepy/models.py index b8a3c15..30456b2 100644 --- a/tweepy/models.py +++ b/tweepy/models.py @@ -458,6 +458,16 @@ class Place(Model): return results +class Media(Model): + + @classmethod + def parse(cls, api, json): + media = cls(api) + for k, v in json.items(): + setattr(media, k, v) + return media + + class ModelFactory(object): """ Used by parsers for creating instances @@ -475,6 +485,7 @@ class ModelFactory(object): list = List relation = Relation relationship = Relationship + media = Media json = JSONModel ids = IDModel -- 2.25.1