def _get_params(method, encoding, fields, params=None): """ Separate the params into the various types. """ if params is None: return empty_params field_map = {field.name: field for field in fields} path = {} query = {} data = {} files = {} errors = {} # Ensure graceful behavior in edge-case where both location='body' and # location='form' fields are present. seen_body = False for key, value in params.items(): if key not in field_map or not field_map[key].location: # Default is 'query' for 'GET' and 'DELETE', and 'form' for others. location = 'query' if method in ('GET', 'DELETE') else 'form' else: location = field_map[key].location if location == 'form' and encoding == 'application/octet-stream': # Raw uploads should always use 'body', not 'form'. location = 'body' try: if location == 'path': path[key] = utils.validate_path_param(value) elif location == 'query': query[key] = utils.validate_query_param(value) elif location == 'body': data = utils.validate_body_param(value, encoding=encoding) seen_body = True elif location == 'form': if not seen_body: data[key] = utils.validate_form_param(value, encoding=encoding) except exceptions.ParameterError as exc: errors[key] = "%s" % exc if errors: raise exceptions.ParameterError(errors) # Move any files from 'data' into 'files'. if isinstance(data, dict): for key, value in list(data.items()): if is_file(data[key]): files[key] = data.pop(key) return Params(path, query, data, files)
def _validate_form_object(value, allow_files=False): """ Ensure that `value` can be encoded as form data or as query parameters. """ if not isinstance(value, dict): msg = 'Must be an object.' raise exceptions.ParameterError(msg) return { text_type(item_key): _validate_form_field(item_val, allow_files=allow_files) for item_key, item_val in value.items() }
def validate_body_param(value, encoding): if encoding == 'application/json': return _validate_json_data(value) elif encoding == 'multipart/form-data': return _validate_form_object(value, allow_files=True) elif encoding == 'application/x-www-form-urlencoded': return _validate_form_object(value) elif encoding == 'application/octet-stream': if not is_file(value): msg = 'Must be an file upload.' raise exceptions.ParameterError(msg) return value msg = 'Unsupported encoding "%s" for outgoing request.' raise exceptions.NetworkError(msg % encoding)
def _validate_json_data(value): """ Ensure that `value` can be encoded into JSON. """ if (value is None) or isinstance(value, (bool, int, float, string_types)): return value elif isinstance(value, (list, tuple)) and not is_file(value): return [_validate_json_data(item) for item in value] elif isinstance(value, dict): return { text_type(item_key): _validate_json_data(item_val) for item_key, item_val in value.items() } msg = 'Must be a JSON primitive.' raise exceptions.ParameterError(msg)
def _validate_parameters(link, parameters): """ Ensure that parameters passed to the link are correct. Raises a `ParameterError` if any parameters do not validate. """ provided = set(parameters.keys()) required = set([field.name for field in link.fields if field.required]) optional = set([field.name for field in link.fields if not field.required]) errors = {} # Determine if any required field names not supplied. missing = required - provided for item in missing: errors[item] = 'This parameter is required.' # Determine any parameter names supplied that are not valid. unexpected = provided - (optional | required) for item in unexpected: errors[item] = 'Unknown parameter.' if errors: raise exceptions.ParameterError(errors)
def _validate_form_field(value, allow_files=False, allow_list=True): """ Ensure that `value` can be encoded as a single form data or a query parameter. Basic types that has a simple string representation are supported. A list of basic types is also valid. """ if isinstance(value, string_types): return value elif isinstance(value, bool) or (value is None): return {True: 'true', False: 'false', None: ''}[value] elif isinstance(value, (int, float)): return "%s" % value elif allow_list and isinstance(value, (list, tuple)) and not is_file(value): # Only the top-level element may be a list. return [ _validate_form_field(item, allow_files=False, allow_list=False) for item in value ] elif allow_files and is_file(value): return value msg = 'Must be a primitive type.' raise exceptions.ParameterError(msg)
def validate_path_param(value): value = _validate_form_field(value, allow_list=False) if not value: msg = 'Parameter %s: May not be empty.' raise exceptions.ParameterError(msg) return value