def rest(self, url, data=None, parse_json=True, **kwargs): """Makes a v3 REST API call. Uses HTTP POST if data is provided, otherwise GET. Args: data: dict, JSON payload for POST requests json: boolean, whether to parse the response body as JSON and return it as a dict. If False, returns a :class:`requests.Response` instead. Returns: dict decoded from JSON response if json=True, otherwise :class:`requests.Response` """ kwargs['headers'] = kwargs.get('headers') or {} kwargs['headers'].update({ 'Authorization': 'token %s' % self.access_token, # enable the beta Reactions API # https://developer.github.com/v3/reactions/ 'Accept': 'application/vnd.github.squirrel-girl-preview+json', }) if data is None: resp = util.requests_get(url, **kwargs) else: resp = util.requests_post(url, json=data, **kwargs) resp.raise_for_status() return json_loads(resp.text) if parse_json else resp
def upload_images(self, urls): """Uploads one or more images from web URLs. https://dev.twitter.com/rest/reference/post/media/upload Args: urls: sequence of string URLs of images Returns: list of string media ids """ ids = [] for url in urls: image_resp = util.urlopen(url) bad_type = self._check_mime_type(url, image_resp, IMAGE_MIME_TYPES, 'JPG, PNG, GIF, and WEBP images') if bad_type: return bad_type headers = twitter_auth.auth_header( API_UPLOAD_MEDIA, self.access_token_key, self.access_token_secret, 'POST') resp = util.requests_post(API_UPLOAD_MEDIA, files={'media': image_resp}, headers=headers) resp.raise_for_status() logging.info('Got: %s', resp.text) try: ids.append(json.loads(resp.text)['media_id_string']) except ValueError, KeyError: logging.exception("Couldn't parse response: %s", resp.text) raise
def upload_images(self, urls): """Uploads one or more images from web URLs. https://dev.twitter.com/rest/reference/post/media/upload Args: urls: sequence of string URLs of images Returns: list of string media ids """ ids = [] for url in urls: image_resp = util.urlopen(url) bad_type = self._check_mime_type(url, image_resp, IMAGE_MIME_TYPES, 'JPG, PNG, GIF, and WEBP images') if bad_type: return bad_type headers = twitter_auth.auth_header( API_UPLOAD_MEDIA, self.access_token_key, self.access_token_secret, 'POST') resp = util.requests_post(API_UPLOAD_MEDIA, files={'media': image_resp}, headers=headers) resp.raise_for_status() logging.info('Got: %s', resp.text) ids.append(source.load_json(resp.text, API_UPLOAD_MEDIA)['media_id_string']) return ids
def graphql(self, graphql, kwargs): """Makes a v4 GraphQL API call. Args: graphql: string GraphQL operation Returns: dict, parsed JSON response """ escaped = { k: (email.utils.quote(v) if isinstance(v, str) else v) for k, v in kwargs.items() } resp = util.requests_post(GRAPHQL_BASE, json={'query': graphql % escaped}, headers={ 'Authorization': 'bearer %s' % self.access_token, }) resp.raise_for_status() result = json_loads(resp.text) errs = result.get('errors') if errs: logging.warning(result) raise ValueError('\n'.join(e.get('message') for e in errs)) return result['data']
def rest(self, url, data=None, **kwargs): """Makes a v3 REST API call. Uses HTTP POST if data is provided, otherwise GET. Args: data: dict, JSON payload for POST requests Returns: `requests.Response` """ kwargs['headers'] = kwargs.get('headers') or {} kwargs['headers'].update({ 'Authorization': 'token %s' % self.access_token, # enable the beta Reactions API # https://developer.github.com/v3/reactions/ 'Accept': 'application/vnd.github.squirrel-girl-preview+json', }) if data is None: resp = util.requests_get(url, **kwargs) else: resp = util.requests_post(url, json=data, **kwargs) resp.raise_for_status() return resp
def graphql(self, graphql, kwargs): """Makes a v4 GraphQL API call. Args: graphql: string GraphQL operation Returns: dict, parsed JSON response """ escaped = {k: (email.utils.quote(v) if isinstance(v, basestring) else v) for k, v in kwargs.items()} resp = util.requests_post( GRAPHQL_BASE, json={'query': graphql % escaped}, headers={ 'Authorization': 'bearer %s' % self.access_token, }) resp.raise_for_status() result = resp.json() errs = result.get('errors') if errs: logging.warning(result) raise ValueError('\n'.join(e.get('message') for e in errs)) return result['data']
def upload_images(self, urls): """Uploads one or more images from web URLs. https://dev.twitter.com/rest/reference/post/media/upload Args: urls: sequence of string URLs of images Returns: list of string media ids """ ids = [] for url in urls: headers = twitter_auth.auth_header( API_UPLOAD_MEDIA, self.access_token_key, self.access_token_secret, 'POST') resp = util.requests_post(API_UPLOAD_MEDIA, files={'media': util.urlopen(url)}, headers=headers) resp.raise_for_status() logging.info('Got: %s', resp.text) try: ids.append(json.loads(resp.text)['media_id_string']) except ValueError, KeyError: logging.exception("Couldn't parse response: %s", resp.text) raise
def requests_post(url, **kwargs): """Wraps :func:`requests.get` with our user agent.""" kwargs.setdefault('headers', {}).update(request_headers(url=url)) return util.requests_post(url, **kwargs)
def upload_video(self, url): """Uploads a video from web URLs using the chunked upload process. Chunked upload consists of multiple API calls: * command=INIT, which allocates the media id * command=APPEND for each 5MB block, up to 15MB total * command=FINALIZE https://dev.twitter.com/rest/reference/post/media/upload-chunked https://dev.twitter.com/rest/public/uploading-media#chunkedupload Args: url: string URL of images Returns: string media id or CreationResult on error """ video_resp = util.urlopen(url) # check format and size type = video_resp.headers.get('Content-Type') if not type: type, _ = mimetypes.guess_type(url) if type and type not in VIDEO_MIME_TYPES: msg = 'Twitter only supports MP4 videos; yours looks like a %s.' % type return source.creation_result(abort=True, error_plain=msg, error_html=msg) length = video_resp.headers.get('Content-Length') if not util.is_int(length): msg = "Couldn't determine your video's size." return source.creation_result(abort=True, error_plain=msg, error_html=msg) length = int(length) if int(length) > MAX_VIDEO_SIZE: msg = "Your %sMB video is larger than Twitter's %dMB limit." % ( length // MB, MAX_VIDEO_SIZE // MB) return source.creation_result(abort=True, error_plain=msg, error_html=msg) # INIT media_id = self.urlopen(API_UPLOAD_MEDIA, data=urllib.urlencode({ 'command': 'INIT', 'media_type': 'video/mp4', 'total_bytes': length, }))['media_id_string'] # APPEND headers = twitter_auth.auth_header( API_UPLOAD_MEDIA, self.access_token_key, self.access_token_secret, 'POST') i = 0 while True: chunk = util.FileLimiter(video_resp, UPLOAD_CHUNK_SIZE) data = { 'command': 'APPEND', 'media_id': media_id, 'segment_index': i, } resp = util.requests_post(API_UPLOAD_MEDIA, data=data, files={'media': chunk}, headers=headers) resp.raise_for_status() if chunk.ateof: break i += 1 # FINALIZE self.urlopen(API_UPLOAD_MEDIA, data=urllib.urlencode({ 'command': 'FINALIZE', 'media_id': media_id, })) return media_id
def upload_video(self, url): """Uploads a video from web URLs using the chunked upload process. Chunked upload consists of multiple API calls: * command=INIT, which allocates the media id * command=APPEND for each 5MB block, up to 15MB total * command=FINALIZE https://dev.twitter.com/rest/reference/post/media/upload-chunked https://dev.twitter.com/rest/public/uploading-media#chunkedupload Args: url: string URL of images Returns: string media id or CreationResult on error """ video_resp = util.urlopen(url) bad_type = self._check_mime_type(url, video_resp, VIDEO_MIME_TYPES, 'MP4 videos') if bad_type: return bad_type length = video_resp.headers.get('Content-Length') if not util.is_int(length): msg = "Couldn't determine your video's size." return source.creation_result(abort=True, error_plain=msg, error_html=msg) length = int(length) if int(length) > MAX_VIDEO_SIZE: msg = "Your %sMB video is larger than Twitter's %dMB limit." % ( length // MB, MAX_VIDEO_SIZE // MB) return source.creation_result(abort=True, error_plain=msg, error_html=msg) # INIT media_id = self.urlopen(API_UPLOAD_MEDIA, data=urllib.urlencode({ 'command': 'INIT', 'media_type': 'video/mp4', 'total_bytes': length, }))['media_id_string'] # APPEND headers = twitter_auth.auth_header( API_UPLOAD_MEDIA, self.access_token_key, self.access_token_secret, 'POST') i = 0 while True: chunk = util.FileLimiter(video_resp, UPLOAD_CHUNK_SIZE) data = { 'command': 'APPEND', 'media_id': media_id, 'segment_index': i, } resp = util.requests_post(API_UPLOAD_MEDIA, data=data, files={'media': chunk}, headers=headers) resp.raise_for_status() if chunk.ateof: break i += 1 # FINALIZE self.urlopen(API_UPLOAD_MEDIA, data=urllib.urlencode({ 'command': 'FINALIZE', 'media_id': media_id, })) return media_id