def parse(self, method, payload): json = JSONParser.parse(self, method, payload) if len(json) == 1 and json.has_key('error_response'): raise TopError(payload) title_key = method.method_name.replace('taobao.', '').replace( '.', '_') + '_response' if not json.has_key(title_key): raise TopError('wrong response data') return TopObjectParser.json_to_object(json[title_key], method.field_mapping)
def prev(self): if self.current_page is None: raise TopError('Can not go back more, at first page') if self.page_index == 0: # At the beginning of the current page, move to next... self.current_page = self.page_iterator.prev() self.page_index = len(self.current_page) if self.page_index == 0: raise TopError('No more items') self.page_index -= 1 self.count -= 1 return self.current_page[self.page_index]
def prev(self): if self.prev_cursor == 0: raise TopError('Can not page back more, at first page') data, self.next_cursor, self.prev_cursor = self.method( cursor=self.prev_cursor, *self.args, **self.kargs) self.count -= 1 return data
def parse(self, method, payload): try: json = self.json_lib.loads(payload, strict=False) except Exception, e: # print "Failed to parse JSON payload:" + str(payload) from apps.common.utils.utils_log import log log.error('Failed to parse JSON payload: e=%s' % e) raise TopError(payload)
def __init__(self, method, *args, **kargs): if hasattr(method, 'pagination_mode'): if method.pagination_mode == 'cursor': self.iterator = CursorIterator(method, args, kargs) else: self.iterator = PageIterator(method, args, kargs) else: raise TopError('This method does not perform pagination')
def build_parameters(self, args, kargs): if args: raise TopError('argument name is necessary for API function!') self.parameters = {} for k, arg in kargs.items(): # if arg is None: 最初代码是这样,不知道为什么,先注释掉吧 # continue if k == self.multi_para: # 如果是数据字段则不进行编码 self.parameters[k] = kargs[k] continue if k in self.parameters: raise TopError('Multiple values for parameter %s supplied!' % k) # self.parameters[k] = convert_2utf8_str(arg) is_str, self.parameters[k] = convert_arg_2utf8_str(arg) if not is_str and self.app_name: # 非字符串类型、并且是ztcjl的api self.parameters[k + '__eval'] = convert_2utf8_str(1) if self.app_name: # added for ztcjl api_router self.parameters['app'] = self.app_name self.parameters['method'] = self.method_name
def _pack_file(fieldname=None, filename=None, other_args={}, max_size=1024 * 10): # build the mulitpart-formdata body BOUNDARY = 'Tw3ePy' body = [] for k, v in other_args.items(): body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="%s"' % (k)) body.append('Content-Type: text/plain; charset=US-ASCII') body.append('Content-Transfer-Encoding: 8bit') body.append('') body.append(str(v)) if filename: try: if max_size == -1: pass elif os.path.getsize(filename) > (max_size * 1024): raise TopError('File is too big, must be less than 10MB.') except os.error, e: raise TopError('Unable to access file, e=%s' % (e)) file_type = mimetypes.guess_type(filename) file_type = file_type[0] if file_type is None: raise TopError('Could not determine file type') body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="' + fieldname + '"; filename="%s"' % filename) body.append('Content-Type: %s' % file_type) body.append('Content-Transfer-Encoding: binary') body.append('') fp = open(filename, 'rb') body.append(fp.read()) fp.close() body.append('--' + BOUNDARY + '--') body.append('')
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 or not api.auth.session_key): raise TopError('Authentication required!') self.api = api 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.is_quick_send = kargs.pop('is_quick_send', api.is_quick_send) self.headers = kargs.pop('headers', {}) self.build_parameters(args, kargs) # Pick correct URL root to use if api.secure: self.scheme = 'https://' else: self.scheme = 'http://'
def parse(self, method, payload): try: if method.payload_type is None: return model = getattr(self.model_factory, method.payload_type) except AttributeError: raise TopError('No model for this payload type: %s' % method.payload_type) json = JSONParser.parse(self, method, payload) if isinstance(json, tuple): json, cursors = json else: cursors = None if method.payload_list: result = model.parse_list(method.api, json) else: result = model.parse(method.api, json) if cursors: return result, cursors else: return result
def _pack_image(filename, max_size, source=None, status=None, lat=None, long=None, contentname="image"): """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 TopError('File is too big, must be less than 700kb.') # except os.error, e: except os.error: raise TopError('Unable to access file') # image must be gif, jpeg, or png file_type = mimetypes.guess_type(filename) if file_type is None: raise TopError('Could not determine file type') file_type = file_type[0] if file_type not in ['image/gif', 'image/jpeg', 'image/png']: raise TopError('Invalid file type for image: %s' % file_type) # build the mulitpart-formdata body fp = open(filename, 'rb') BOUNDARY = 'Tw3ePy' body = [] if status is not None: body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="status"') body.append('Content-Type: text/plain; charset=US-ASCII') body.append('Content-Transfer-Encoding: 8bit') body.append('') body.append(status) if source is not None: body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="source"') body.append('Content-Type: text/plain; charset=US-ASCII') body.append('Content-Transfer-Encoding: 8bit') body.append('') body.append(source) if lat is not None: body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="lat"') body.append('Content-Type: text/plain; charset=US-ASCII') body.append('Content-Transfer-Encoding: 8bit') body.append('') body.append(lat) if long is not None: body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="long"') body.append('Content-Type: text/plain; charset=US-ASCII') body.append('Content-Transfer-Encoding: 8bit') body.append('') body.append(long) body.append('--' + BOUNDARY) body.append('Content-Disposition: form-data; name="' + contentname + '"; filename="%s"' % filename) body.append('Content-Type: %s' % file_type) body.append('Content-Transfer-Encoding: binary') body.append('') body.append(fp.read()) body.append('--' + BOUNDARY + '--') body.append('') fp.close() body.append('--' + BOUNDARY + '--') body.append('') body = '\r\n'.join(body) # build headers headers = { 'Content-Type': 'multipart/form-data; boundary=Tw3ePy', 'Content-Length': len(body) } return headers, body
class APIMethod(object): app_name = config.get('app_name', None) method_name = config.get('method_name', None) payload_type = config.get('payload_type', None) payload_list = config.get('payload_list', False) field_mapping = config.get('field_mapping', None) method = config.get('method', 'GET') require_auth = config.get('require_auth', False) multi_para = config.get('multi_para', None) # by:zhongjinfeng此字段是用来提交二进制数据的,比如上传图片的接口 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 or not api.auth.session_key): raise TopError('Authentication required!') self.api = api 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.is_quick_send = kargs.pop('is_quick_send', api.is_quick_send) self.headers = kargs.pop('headers', {}) self.build_parameters(args, kargs) # Pick correct URL root to use if api.secure: self.scheme = 'https://' else: self.scheme = 'http://' # 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 # 由于后面会使用到headers,因此这里并不需要,反而会造成connection与headers不一致(API流控) # 上面的英文说是修复Twitter的一个重定向bug,这里注释掉下面这句是可以的。 # self.headers['Host'] = self.api.host def build_parameters(self, args, kargs): if args: raise TopError('argument name is necessary for API function!') self.parameters = {} for k, arg in kargs.items(): # if arg is None: 最初代码是这样,不知道为什么,先注释掉吧 # continue if k == self.multi_para: # 如果是数据字段则不进行编码 self.parameters[k] = kargs[k] continue if k in self.parameters: raise TopError('Multiple values for parameter %s supplied!' % k) # self.parameters[k] = convert_2utf8_str(arg) is_str, self.parameters[k] = convert_arg_2utf8_str(arg) if not is_str and self.app_name: # 非字符串类型、并且是ztcjl的api self.parameters[k + '__eval'] = convert_2utf8_str(1) if self.app_name: # added for ztcjl api_router self.parameters['app'] = self.app_name self.parameters['method'] = self.method_name def execute(self): # Build the request URL url = self.api.api_root parameters = {} parameters.update(self.parameters) if self.api.auth: if self.multi_para: # by:zhongjingfeng 此处如果是数据字段,则去除不参与签名 self.multi_para_data = parameters.pop(self.multi_para) self.api.auth.apply_auth(parameters = parameters) if len(parameters): if self.method == 'GET': url = '%s?%s' % (url, urllib.urlencode(parameters)) else: self.headers.setdefault("User-Agent", "python") if self.post_data is None: self.headers.setdefault("Accept", "text/html") self.headers.setdefault("Content-Type", "application/x-www-form-urlencoded") self.post_data = urllib.urlencode(parameters) if self.multi_para: form = MultiPartForm() for key, value in parameters.items(): form.add_field(key, value) fileitem = self.multi_para_data if(fileitem and isinstance(fileitem, FileItem)): form.add_file(self.multi_para, fileitem.filename, fileitem.content) self.post_data = str(form) self.headers["Content-Type"] = form.get_content_type() # 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 # Continue attempting request until successful or maximum number of retries is reached. resp = None sTime = time.time() retries_performed = 0 # API_LOG = Config.get_value('common.API_LOG_OUTPUT', default = 0) while retries_performed < self.retry_count + 1: # Open connection api_host = self.api.host if self.api.timeout: if self.api.secure: conn = httplib.HTTPSConnection(api_host, timeout = self.api.timeout) else: conn = httplib.HTTPConnection(api_host, timeout = self.api.timeout) else: if self.api.secure: conn = httplib.HTTPSConnection(api_host) else: conn = httplib.HTTPConnection(api_host) # if API_LOG in [1, 3]: # log.info('url=%s, headers=%s, retries_performed=%s, retry_delay=%s' % (url, self.headers, retries_performed, self.retry_delay)) # Execute request try: conn.request(self.method, url, headers = self.headers, body = self.post_data) if self.is_quick_send: return {'result': True} resp = conn.getresponse() except Exception, e: log.error('Failed to send request, host=%s, url=%s, headers=%s, retries_performed=%s, retry_delay=%s, e=%s' % (api_host, url, self.headers, retries_performed, self.retry_delay, e)) time.sleep(self.retry_delay) retries_performed += 1 continue # Exit request loop if non-retry error code if self.retry_errors: # if resp.status not in self.retry_errors: break pass else: if resp.status == 200: break # Sleep before retrying request again time.sleep(self.retry_delay) retries_performed += 1 # If an error was returned, throw an exception try: body = resp.read() conn.close() except Exception, e: conn.close() raise TopError('%s' % e)
def prev(self): if (self.current_page == 1): raise TopError('Can not page back more, at first page') self.current_page -= 1 return self.method(page=self.current_page, *self.args, **self.kargs)