def _pack_image(filename, contentname, max_size=1024, **params): """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 QWeiboError('File is too big, must be less than 700kb.') except os.error: raise QWeiboError('Unable to access file') # image must be gif, jpeg, or png file_type = mimetypes.guess_type(filename) if file_type is None: raise QWeiboError('Could not determine file type') file_type = file_type[0] if file_type.split('/')[0] != 'image': raise QWeiboError('Invalid file type for image: %s' % file_type) # build the mulitpart-formdata body BOUNDARY = 'QqWeIbObYaNdElF----' # qqweibo by andelf body = [] for key, val in params.items(): if val is not None: body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="%s"' % key) body.append('Content-Type: text/plain; charset=UTF-8') body.append('Content-Transfer-Encoding: 8bit') body.append('') val = convert_to_utf8_bytes(val) body.append(val) fp = open(filename, 'rb') body.append('--' + BOUNDARY) body.append( 'Content-Disposition: form-data; name="%s"; filename="%s"' % (contentname, filename.encode('utf-8'))) body.append('Content-Type: %s' % file_type) body.append('Content-Transfer-Encoding: binary') body.append('') body.append(fp.read()) body.append('--%s--' % BOUNDARY) body.append('') fp.close() body.append('--%s--' % BOUNDARY) body.append('') # fix py3k for i in range(len(body)): body[i] = convert_to_utf8_bytes(body[i]) body = b'\r\n'.join(body) # build headers headers = { 'Content-Type': 'multipart/form-data; boundary=%s' % BOUNDARY, 'Content-Length': len(body) } return headers, body
def get_access_token(self, verifier=None): """ After user has authorized the request token, get access token with user supplied verifier. """ try: url = self._get_oauth_url('access_token') # build request request = oauth.OAuthRequest.from_consumer_and_token( self._consumer, token=self.request_token, http_url=url, verifier=str(verifier)) request.sign_request(self._sigmethod, self._consumer, self.request_token) # send request resp = urlopen(Request(request.to_url())) # must self.access_token = oauth.OAuthToken.from_string( resp.read().decode('ascii')) #print ('Access token key: ' + str(self.access_token.key)) #print ('Access token secret: ' + str(self.access_token.secret)) return self.access_token except Exception as e: raise QWeiboError(e)
def parse(self, method, payload): try: if method.payload_type is None: return model = getattr(self.model_factory, method.payload_type) except AttributeError: raise QWeiboError('No model for this payload type: %s' % method.payload_type) json = JSONParser.parse(self, method, payload) data = json['data'] # TODO: add pager if 'pagetime' in method.allowed_param: pass if method.payload_list: # sometimes data will be a None if data: if 'hasnext' in data: # need pager here hasnext = data['hasnext'] in [0, 2] # hasNext:2表示不能往上翻 1 表示不能往下翻, # 0表示两边都可以翻 3表示两边都不能翻了 else: hasnext = False if 'info' in data: data = data['info'] else: hasnext = False result = model.parse_list(method.api, data) result.hasnext = hasnext else: result = model.parse(method.api, data) return result
def __init__(self, api, args, kargs): # If authentication is required and no credentials # are provided, throw an error. if self.require_auth and not api.auth: raise QWeiboError('Authentication required!') self.api = api self.payload_format = api.parser.payload_format self.post_data = kargs.pop('post_data', None) self.retry_count = kargs.pop('retry_count', api.retry_count) self.retry_delay = kargs.pop('retry_delay', api.retry_delay) self.retry_errors = kargs.pop('retry_errors', api.retry_errors) self.headers = kargs.pop('headers', {}) self.build_parameters(args, kargs) self.api_root = api.api_root # Perform any path variable substitution self.build_path() self.scheme = 'http://' self.host = api.host # Manually set Host header to fix an issue in python 2.5 # or older where Host is set including the 443 port. # This causes Twitter to issue 301 redirect. # See Issue http://github.com/joshthecoder/tweepy/issues/#issue/12 self.headers['Host'] = self.host
def parse(self, method, payload): try: json = self.json_lib.loads(payload, encoding='utf-8') except Exception as e: print("Failed to parse JSON payload:" + repr(payload)) raise QWeiboError('Failed to parse JSON payload: %s' % e) return json
def _get_request_token(self): try: url = self._get_oauth_url('request_token') request = oauth.OAuthRequest.from_consumer_and_token( self._consumer, http_url=url, callback=self.callback) request.sign_request(self._sigmethod, self._consumer, None) resp = urlopen(Request(request.to_url())) # must return oauth.OAuthToken.from_string(resp.read().decode('ascii')) except RuntimeError as e: raise QWeiboError(e)
def get_username(self): if self.username is None: api = API(self) user = api.user.info() if user: self.username = user.name else: raise QWeiboError( "Unable to get username, invalid oauth token!") return self.username
def build_parameters(self, args, kargs): # bind here, as default self.parameters = {'format': self.payload_format} for idx, arg in enumerate(args): try: self.parameters[self.allowed_param[idx]] = quote( convert_to_utf8_str(arg)) except IndexError: raise QWeiboError('Too many parameters supplied!') for k, arg in kargs.items(): if bool(arg) == False: continue if k in self.parameters: raise QWeiboError( 'Multiple values for parameter `%s` supplied!' % k) #if k not in self.allowed_param: # raise QWeiboError('`%s` is not allowd in this API function.' % k) self.parameters[k] = quote(convert_to_utf8_str(arg))
def build_path(self): for variable in re_path_template.findall(self.path): name = variable.strip('{}') if name == 'user' and self.api.auth: value = self.api.auth.get_username() else: try: value = quote(self.parameters[name]) except KeyError: raise QWeiboError( 'No parameter value found for path variable: %s' % name) del self.parameters[name] self.path = self.path.replace(variable, value)
def get_authorization_url(self, signin_with_weibo=False): """Get the authorization URL to redirect the user""" try: # get the request token self.request_token = self._get_request_token() # build auth request and return as url if signin_with_weibo: url = self._get_oauth_url('authenticate') else: url = self._get_oauth_url('authorize') request = oauth.OAuthRequest.from_token_and_callback( token=self.request_token, http_url=url, callback=self.callback) return request.to_url() except RuntimeError as e: raise QWeiboError(e)
def __init__(self, api, args, kargs): # If authentication is required and no credentials # are provided, throw an error. if self.require_auth and not api.auth: raise QWeiboError('Authentication required!') self.api = api self.payload_format = api.parser.payload_format self.post_data = kargs.pop('post_data', None) self.retry_count = kargs.pop('retry_count', api.retry_count) self.retry_delay = kargs.pop('retry_delay', api.retry_delay) self.retry_errors = kargs.pop('retry_errors', api.retry_errors) self.headers = kargs.pop('headers', {}) self.build_parameters(args, kargs) self.api_root = api.api_root self.scheme = 'https://' if api.auth.AUTH_TYPE == "OAuth2.0" else 'http://' self.host = api.host
def delete(self): if self.self: return self._api.t.delete(self.id) else: raise QWeiboError("You can't delete others' tweet")
def execute(self): # Build the request URL url = self.scheme + self.host + self.api_root + self.path full_url, parameters = self.api.auth.authorize_request( url, self.method, self.headers, self.parameters) self.headers.setdefault("User-Agent", "pyqqweibo") if self.method == 'POST': if self.post_data is None: self.headers.setdefault( "Content-Type", "application/x-www-form-urlencoded") # asure in bytes format self.post_data = '&'.join( ("%s=%s" % kv) for kv in parameters) req = Request(full_url, data=self.post_data, headers=self.headers) elif self.method == 'GET': req = Request(full_url) try: resp = urlopen(req) except Exception as e: raise QWeiboError("Failed to request %s headers=%s %s" % \ (url, self.headers, e)) body = resp.read() self.api.last_response = resp # log handling if self.api.log is not None: requestUrl = "URL:http://" + self.host + url eTime = '%.0f' % ((time.time() - sTime) * 1000) postData = "" if self.post_data is not None: postData = ",post:" + self.post_data[:500] self.api.log.debug("%s, time: %s, %s result: %s" % (requestUrl, eTime, postData, body)) retcode = 0 errcode = 0 # for py3k, ^_^ if not hasattr(body, 'encode'): body = str(body, 'utf-8') # if self.api.parser.payload_format == 'json': # try: # # BUG: API BUG, refer api.doc.rst # if body.endswith('out of memery'): # body = body[:body.rfind('}')+1] # json = self.api.parser.parse_error(self, body) # retcode = json.get('ret', 0) # msg = json.get('msg', '') # # only in some post request # errcode = json.get('errcode', 0) # except ValueError as e: # retcode = -1 # msg = "Bad json format (%s)" % e # finally: # if retcode + errcode != 0: # raise QWeiboError("Response error: %s. (ret=%s, errcode=%s)" % \ # (msg, retcode, errcode)) # Parse the response payload result = self.api.parser.parse(self, body) # Store result into cache if one is available. if self.api.cache and self.method == 'GET' and result: self.api.cache.store(url, result) return result
def execute(self): # Build the request URL url = self.api_root + self.path #if self.api.source is not None: # self.parameters.setdefault('source',self.api.source) if len(self.parameters): if self.method == 'GET': url = '%s?%s' % (url, urlencode(self.parameters)) else: self.headers.setdefault("User-Agent", "pyqqweibo") if self.post_data is None: self.headers.setdefault("Accept", "text/html") self.headers.setdefault( "Content-Type", "application/x-www-form-urlencoded") # asure in bytes format self.post_data = urlencode( self.parameters).encode('ascii') # Query the cache if one is available # and this request uses a GET method. if self.api.cache and self.method == 'GET': cache_result = self.api.cache.get(url) # if cache result found and not expired, return it if cache_result: # must restore api reference if isinstance(cache_result, list): for result in cache_result: result._api = self.api else: cache_result._api = self.api return cache_result #urllib.urlencode(self.parameters) # Continue attempting request until successful # or maximum number of retries is reached. sTime = time.time() retries_performed = 0 while retries_performed < self.retry_count + 1: # Open connection # FIXME: add timeout # Apply authentication if self.require_auth and self.api.auth: url_full = self.api.auth.get_authed_url( self.scheme + self.host + url, self.method, self.headers, self.parameters) else: # this brunch is never accoured url_full = self.api.auth.get_signed_url( self.scheme + self.host + url, self.method, self.headers, self.parameters) try: if self.method == 'POST': req = Request(url_full, data=self.post_data, headers=self.headers) else: req = Request(url_full) resp = urlopen(req, timeout=20) except Exception as e: raise QWeiboError("Failed to request %s headers=%s %s" % \ (url, self.headers, e)) # Exit request loop if non-retry error code if self.retry_errors: if resp.code not in self.retry_errors: break else: if resp.code == 200: break # Sleep before retrying request again time.sleep(self.retry_delay) retries_performed += 1 # If an error was returned, throw an exception body = resp.read() self.api.last_response = resp if self.api.log is not None: requestUrl = "URL:http://" + self.host + url eTime = '%.0f' % ((time.time() - sTime) * 1000) postData = "" if self.post_data is not None: postData = ",post:" + self.post_data[:500] self.api.log.debug("%s, time: %s, %s result: %s" % (requestUrl, eTime, postData, body)) retcode = 0 errcode = 0 # for py3k, ^_^ if not hasattr(body, 'encode'): body = str(body, 'utf-8') if self.api.parser.payload_format == 'json': try: # BUG: API BUG, refer api.doc.rst if body.endswith('out of memery'): body = body[:body.rfind('}') + 1] json = self.api.parser.parse_error(self, body) retcode = json.get('ret', 0) msg = json.get('msg', '') # only in some post request errcode = json.get('errcode', 0) except ValueError as e: retcode = -1 msg = "Bad json format (%s)" % e finally: if retcode + errcode != 0: raise QWeiboError("Response error: %s. (ret=%s, errcode=%s)" % \ (msg, retcode, errcode)) # Parse the response payload result = self.api.parser.parse(self, body) # Store result into cache if one is available. if self.api.cache and self.method == 'GET' and result: self.api.cache.store(url, result) return result