def get_authorized_tokens(self, oauth_verifier): """Returns a dict of authorized tokens after they go through the :class:`get_authentication_tokens` phase. :param oauth_verifier: (required) The oauth_verifier (or a.k.a PIN for non web apps) retrieved from the callback url querystring :rtype: dict """ if self.oauth_version != 1: raise TwythonError('This method can only be called when your OAuth version is 1.0.') response = self.client.get(self.access_token_url, params={'oauth_verifier': oauth_verifier}, headers={'Content-Type': 'application/json'}) if response.status_code == 401: try: try: # try to get json content = response.json() except AttributeError: # pragma: no cover # if unicode detected content = json.loads(response.content) except ValueError: content = {} raise TwythonError(content.get('error', 'Invalid / expired Token'), error_code=response.status_code) authorized_tokens = dict(parse_qsl(response.content.decode('utf-8'))) if not authorized_tokens: raise TwythonError('Unable to decode authorized tokens.') return authorized_tokens # pragma: no cover
def _request(self, url, method='GET', params=None): """Internal stream request handling""" self.connected = True retry_counter = 0 method = method.lower() func = getattr(self.client, method) params, _ = _transparent_params(params) def _send(retry_counter): requests_args = {} for k, v in self.client_args.items(): # Maybe this should be set as a class variable and only done once? if k in ('timeout', 'allow_redirects', 'verify'): requests_args[k] = v while self.connected: try: if method == 'get': requests_args['params'] = params else: requests_args['data'] = params response = func(url, **requests_args) except requests.exceptions.Timeout: self.on_timeout() else: if response.status_code != 200: self.on_error(response.status_code, response.content) if self.retry_count and (self.retry_count - retry_counter) > 0: time.sleep(self.retry_in) retry_counter += 1 _send(retry_counter) return response while self.connected: response = _send(retry_counter) for line in response.iter_lines(self.chunk_size): if not self.connected: break if line: try: if is_py3: line = line.decode('utf-8') data = json.loads(line) except ValueError: # pragma: no cover self.on_error(response.status_code, 'Unable to decode response, not valid JSON.') else: if self.on_success(data): # pragma: no cover for message_type in self.handlers: if message_type in data: handler = getattr(self, 'on_' + message_type, None) if handler and callable(handler) and not handler(data.get(message_type)): break response.close()
def obtain_access_token(self): """Returns an OAuth 2 access token to make OAuth 2 authenticated read-only calls. :rtype: string """ if self.oauth_version != 2: raise TwythonError('This method can only be called when your OAuth version is 2.0.') data = {'grant_type': 'client_credentials'} basic_auth = HTTPBasicAuth(self.app_key, self.app_secret) try: response = self.client.post(self.request_token_url, data=data, auth=basic_auth) content = response.content.decode('utf-8') try: content = content.json() except AttributeError: content = json.loads(content) access_token = content['access_token'] except (KeyError, ValueError, requests.exceptions.RequestException): raise TwythonAuthError('Unable to obtain OAuth 2 access token.') else: return access_token
def _request(self, url, method='GET', params=None, api_call=None): """Internal request method""" method = method.lower() params = params or {} func = getattr(self.client, method) params, files = _transparent_params(params) requests_args = {} for k, v in self.client_args.items(): # Maybe this should be set as a class variable and only done once? if k in ('timeout', 'allow_redirects', 'stream', 'verify'): requests_args[k] = v if method == 'get': requests_args['params'] = params else: requests_args.update({ 'data': params, 'files': files, }) try: response = func(url, **requests_args) except requests.RequestException as e: raise TwythonError(str(e)) content = response.content.decode('utf-8') # create stash for last function intel self._last_call = { 'api_call': api_call, 'api_error': None, 'cookies': response.cookies, 'headers': response.headers, 'status_code': response.status_code, 'url': response.url, 'content': content, } # Wrap the json loads in a try, and defer an error # Twitter will return invalid json with an error code in the headers json_error = False try: try: # try to get json content = content.json() except AttributeError: # if unicode detected content = json.loads(content) except ValueError: json_error = True content = {} if response.status_code > 304: # If there is no error message, use a default. errors = content.get('errors', [{'message': 'An error occurred processing your request.'}]) if errors and isinstance(errors, list): error_message = errors[0]['message'] else: error_message = errors # pragma: no cover self._last_call['api_error'] = error_message ExceptionType = TwythonError if response.status_code == 429: # Twitter API 1.1, always return 429 when rate limit is exceeded ExceptionType = TwythonRateLimitError # pragma: no cover elif response.status_code == 401 or 'Bad Authentication data' in error_message: # Twitter API 1.1, returns a 401 Unauthorized or # a 400 "Bad Authentication data" for invalid/expired app keys/user tokens ExceptionType = TwythonAuthError raise ExceptionType(error_message, error_code=response.status_code, retry_after=response.headers.get('retry-after')) # if we have a json error here, then it's not an official Twitter API error if json_error and not response.status_code in (200, 201, 202): # pragma: no cover raise TwythonError('Response was not valid JSON, unable to decode.') return content
def _request(self, url, method='GET', params=None): """Internal stream request handling""" self.connected = True retry_counter = 0 method = method.lower() func = getattr(self.client, method) params, _ = _transparent_params(params) def _send(retry_counter): requests_args = {} for k, v in self.client_args.items(): # Maybe this should be set as a class variable and only done once? if k in ('timeout', 'allow_redirects', 'verify'): requests_args[k] = v while self.connected: try: if method == 'get': requests_args['params'] = params else: requests_args['data'] = params response = func(url, **requests_args) except requests.exceptions.Timeout: self.on_timeout() else: if response.status_code != 200: self.on_error(response.status_code, response.content) if self.retry_count and (self.retry_count - retry_counter) > 0: time.sleep(self.retry_in) retry_counter += 1 _send(retry_counter) return response while self.connected: response = _send(retry_counter) for line in response.iter_lines(self.chunk_size): if not self.connected: break if line: try: if is_py3: line = line.decode('utf-8') data = json.loads(line) except ValueError: # pragma: no cover self.on_error( response.status_code, 'Unable to decode response, not valid JSON.') else: if self.on_success(data): # pragma: no cover for message_type in self.handlers: if message_type in data: handler = getattr(self, 'on_' + message_type, None) if handler and callable( handler) and not handler( data.get(message_type)): break response.close()