def merge_setting_safe(request_setting, session_setting, dict_class=OrderedDict): merged_setting = dict_class(to_key_val_list(session_setting or ())) merged_setting.update(to_key_val_list(request_setting or ())) for (k, v) in (request_setting or {}).items(): if v is None: del merged_setting[k] return merged_setting
def prepare_body(self, data, files, json=None): """Prepares the given HTTP body data.""" if not files: super().prepare_body(data, files, json) if self.body and not isinstance(self.body, bytes): self.body = StreamBody(self.body) return fields = [] for key, value in to_key_val_list(data or {}): fields.append(Field(key, content=value)) for (k, v) in to_key_val_list(files or {}): # support for explicit filename ft = None fh = None if isinstance(v, (tuple, list)): if len(v) == 2: fn, fp = v elif len(v) == 3: fn, fp, ft = v else: fn, fp, ft, fh = v else: fn = None fp = v if isinstance(fp, (str, bytes, bytearray)): content = fp fp = None else: content = None fields.append( Field( k, filename=fn, file=fp, content=content, content_type=ft, headers=fh, ) ) self.body = MultipartBody(fields) self.headers.setdefault('Content-Type', self.body.content_type) self.prepare_content_length(self.body)
def _merge_retain_none(request_setting, session_setting, dict_class=OrderedDict): if session_setting is None: return request_setting if request_setting is None: return session_setting # Bypass if not a dictionary (e.g. verify) if not (isinstance(session_setting, Mapping) and isinstance(request_setting, Mapping)): return request_setting merged_setting = dict_class(to_key_val_list(session_setting)) merged_setting.update(to_key_val_list(request_setting)) return merged_setting
def _build_query(self, query_params): result = [] for k, vs in to_key_val_list(query_params): if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): vs = [vs] for v in vs: if v is not None: result.append( (k.encode('utf-8') if isinstance(k, str) else k, v.encode('utf-8') if isinstance(v, str) else v) ) return urlencode(result, doseq=True)
def _create_operation_request(endpoint, operation=None, method="POST", data=None, files=None): """ Creates an operation request against a given ArcGIS Server endpoint. :param endpoint: The endpoint on which to perform the operation. :type base_url: str or object implementing agsadmin._endpoint_base :param operation: The operation to perform. If None, the endpoint metadata is returned. :type operation: str :param method: Overrides the HTTP verb to use on the request, default is POST but some operations accept/require GET :type method: str """ files = to_key_val_list(files or {}) # data may come in as an object containing other complex objects types (e.g. strings, lists), these should be # encoded to JSON strings if not data == None: encoded_data = {} for key, value in iteritems(data): if isinstance(value, collections.Mapping): encoded_data[key] = json.dumps(value) elif isinstance(value, list): encoded_data[key] = json.dumps(value) else: encoded_data[key] = value data = encoded_data # determine if we need to take any data paramaters and send them as files if "thumbnail" in data and not data["thumbnail"] is None: thumbnail_path = data["thumbnail"] files.append( ("thumbnail", (os.path.basename(thumbnail_path), open(thumbnail_path, "rb"), mimetypes.guess_type(thumbnail_path, False)[0]))) del data["thumbnail"] return Request(method, "{endpoint}/{operation}".format( endpoint=endpoint._url_full if isinstance( endpoint, EndpointBase) else endpoint, operation=operation if operation else ""), data=data, files=files if len(files) > 0 else None)
def _create_operation_request(endpoint, operation=None, method="POST", data=None, files=None): """ Creates an operation request against a given ArcGIS Server endpoint. :param endpoint: The endpoint on which to perform the operation. :type base_url: str or object implementing agsadmin._endpoint_base :param operation: The operation to perform. If None, the endpoint metadata is returned. :type operation: str :param method: Overrides the HTTP verb to use on the request, default is POST but some operations accept/require GET :type method: str """ files = to_key_val_list(files or {}) # data may come in as an object containing other complex objects types (e.g. strings, lists), these should be # encoded to JSON strings if not data == None: encoded_data = {} for key, value in iteritems(data): if isinstance(value, collections.Mapping): encoded_data[key] = json.dumps(value) elif isinstance(value, list): encoded_data[key] = json.dumps(value) else: encoded_data[key] = value data = encoded_data # determine if we need to take any data paramaters and send them as files if "thumbnail" in data and not data["thumbnail"] is None: thumbnail_path = data["thumbnail"] files.append(("thumbnail", (os.path.basename(thumbnail_path), open(thumbnail_path, "rb"), mimetypes.guess_type(thumbnail_path, False)[0]))) del data["thumbnail"] return Request( method, "{endpoint}/{operation}".format( endpoint=endpoint._url_full if isinstance(endpoint, EndpointBase) else endpoint, operation=operation if operation else ""), data=data, files=files if len(files) > 0 else None)
def encode_http_params(data): """ Encode HTTP parameters to URL query string :param data: data as text or tuple/list :type data: str or bytes or tuple or list :return: str -- encoded data """ if isinstance(data, (str, bytes)): return urlencode(data) elif hasattr(data, '__iter__'): result = [] for k, vs in to_key_val_list(data): if vs is not None: result.append( (k.encode('utf-8') if isinstance(k, str) else k, vs.encode('utf-8') if isinstance(vs, str) else vs)) return urlencode(result, doseq=True) else: raise ValueError('Invalid argument')
def _apply_options(self, kwargs): kwargs['timeout'] = self.timeout if self.auth is not None: kwargs['auth'] = self.auth # fix space quoting for query string: '%20' instead of '+' params = kwargs.get('params') if params and hasattr(params, '__iter__'): result = [] for k, vs in to_key_val_list(params): if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): vs = [vs] for v in vs: if v is not None: result.append( (k.encode('utf-8') if isinstance(k, str) else k, v.encode('utf-8') if isinstance(v, str) else v)) kwargs['params'] = urlencode(result, doseq=True, quote_via=quote)
def send_request(self, req): ''' returns requests.Response object raise ''' # requests gotcha: even if send through the session, request.prepare() # does not get merged with the session's attributes, so we have to call # session.prepare_request(...) # merge params with the api key req.params = to_key_val_list(req.params) + [('key', self.api_key)] prepared_req = self._session.prepare_request(req) logger.debug('req.params {} prepare_req {}'.format(req.params, prepared_req)) res = self._session.send(prepared_req) if res.status_code != 200: # CrowdFlower responds with a '202 Accepted' when we request a bulk # download which has not yet been generated, which means we simply # have to wait and try again raise CrowdFlowerError(req, res) return res
def send_request(self, req): ''' returns requests.Response object raise ''' # requests gotcha: even if send through the session, request.prepare() # does not get merged with the session's attributes, so we have to call # session.prepare_request(...) # merge params with the api key req.params = to_key_val_list(req.params) + [('key', self.api_key)] prepared_req = self._session.prepare_request(req) logger.debug('Request params: {}'.format(req.params)) res = self._session.send(prepared_req) if res.status_code != 200: # CrowdFlower responds with a '202 Accepted' when we request a bulk # download which has not yet been generated, which means we simply # have to wait and try again raise CrowdFlowerError(req, res) return res
def test_invalid(self): with pytest.raises(ValueError): to_key_val_list('string')
def test_valid(self, value, expected): assert to_key_val_list(value) == expected
def _prepare_files(files): if files is not None: files = [_prepare_file(k, v) for k, v in to_key_val_list(files)] return files