def generate_response_header_validator(headers, context, **kwargs): validators = ValidationDict() for key, header_definition in headers.items(): # generate a function that will attempt to cast the header to the # appropriate type. header_processor = generate_value_processor( context=context, **header_definition ) # generate a function that will validate the header. header_validator = functools.partial( validate_object, field_validators=construct_header_validators(header_definition, context=context), ) # Chain the type casting function, the individual header validation # function with a methodcaller that will fetch the header with # `response.headers.get(header_name, EMPTY)` and then feed that into # the type casting function and then into the validation function. validators.add_validator(key, chain_reduce_partial( methodcaller('get', key, EMPTY), header_processor, header_validator, )) return chain_reduce_partial( attrgetter('headers'), functools.partial(validate_object, field_validators=validators), )
def generate_response_header_validator(headers, context, **kwargs): validators = ValidationDict() for key, header_definition in headers.items(): # generate a function that will attempt to cast the header to the # appropriate type. header_processor = generate_value_processor( context=context, **header_definition ) # generate a function that will validate the header. header_validator = functools.partial( validate_object, field_validators=construct_header_validators(header_definition, context=context), ) # Chain the type casting function, the individual header validation # function with a methodcaller that will fetch the header with # `response.headers.get(header_name, EMPTY)` and then feed that into # the type casting function and then into the validation function. validators.add_validator(key, chain_reduce_partial( methodcaller('get', key, EMPTY), header_processor, header_validator, )) return chain_reduce_partial( attrgetter('headers'), functools.partial(validate_object, field_validators=validators), )
def generate_path_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a callable for validating the parameters in a response object. """ path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), context, ) operation_level_parameters = dereference_parameter_list( parameters, context, ) all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) return chain_reduce_partial( attrgetter('path'), generate_path_parameters_validator(api_path, in_path_parameters, context), )
def generate_path_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a callable for validating the parameters in a response object. """ path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), context, ) operation_level_parameters = dereference_parameter_list( parameters, context, ) all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) return chain_reduce_partial( attrgetter('path'), generate_path_parameters_validator(api_path, in_path_parameters, context), )
def generate_response_body_validator(schema, context, **kwargs): return chain_reduce_partial( attrgetter('data'), functools.partial( validate_object, schema=schema, context=context, ), )
def generate_response_body_validator(schema, context, **kwargs): return chain_reduce_partial( attrgetter('data'), functools.partial( validate_object, schema=schema, context=context, ), )
def test_chain_reduce_partial(): def fn_a(v): return v * 3 def fn_b(v): return v * 5 fn_c = chain_reduce_partial(fn_a, fn_b) for _ in range(100): v = random.randint(-1000000, 1000000) assert fn_c(v) == fn_b(fn_a(v))
def test_chain_reduce_partial(): def fn_a(v): return v * 3 def fn_b(v): return v * 5 fn_c = chain_reduce_partial(fn_a, fn_b) for _ in range(100): v = random.randint(-1000000, 1000000) assert fn_c(v) == fn_b(fn_a(v))
def generate_header_validator(headers, context, **kwargs): """ Generates a validation function that will validate a dictionary of headers. """ validators = ValidationDict() for header_definition in headers: header_processor = generate_value_processor( context=context, **header_definition ) header_validator = generate_object_validator( field_validators=construct_header_validators(header_definition, context=context), ) validators.add_property_validator( header_definition['name'], chain_reduce_partial( header_processor, header_validator, ), ) return generate_object_validator(field_validators=validators)
def generate_parameters_validator(api_path, path_definition, parameters, context, **kwargs): """ Generates a validator function to validate. - request.path against the path parameters. - request.query against the query parameters. - request.headers against the header parameters. - TODO: request.body against the body parameters. - TODO: request.formData against any form data. """ # TODO: figure out how to merge this with the same code in response # validation. validators = ValidationDict() path_level_parameters = dereference_parameter_list( path_definition.get('parameters', []), context, ) operation_level_parameters = dereference_parameter_list( parameters, context, ) all_parameters = merge_parameter_lists( path_level_parameters, operation_level_parameters, ) # PATH in_path_parameters = filter_parameters(all_parameters, in_=PATH) validators.add_validator( 'path', chain_reduce_partial( attrgetter('path'), generate_path_parameters_validator(api_path, in_path_parameters, context), ), ) # QUERY in_query_parameters = filter_parameters(all_parameters, in_=QUERY) validators.add_validator( 'query', chain_reduce_partial( attrgetter('query_data'), functools.partial( validate_query_parameters, query_parameters=in_query_parameters, context=context, ), ), ) # HEADERS in_header_parameters = filter_parameters(all_parameters, in_=HEADER) validators.add_validator( 'headers', chain_reduce_partial( attrgetter('headers'), generate_header_validator(in_header_parameters, context), ), ) # FORM_DATA # in_form_data_parameters = filter_parameters(all_parameters, in_=FORM_DATA) # validators.add_validator( # 'form_data', # chain_reduce_partial( # attrgetter('data'), # generate_form_data_validator(in_form_data_parameters, context), # ) # ) # REQUEST_BODY in_request_body_parameters = filter_parameters(all_parameters, in_=BODY) validators.add_validator( 'request_body', chain_reduce_partial( attrgetter('data'), generate_request_body_validator(in_request_body_parameters, context), ) ) return generate_object_validator(field_validators=validators)
def processor(value, **kwargs): try: return chain_reduce_partial(*processors)(value) except (ValueError, TypeError): return value
def generate_value_processor(type_, collectionFormat=None, items=None, **kwargs): """ Create a callable that will take the string value of a header and cast it to the appropriate type. This can involve: - splitting a header of type 'array' by its delimeters. - type casting the internal elements of the array. """ processors = [] if is_non_string_iterable(type_): assert False, "This should not be possible" else: if type_ == ARRAY and collectionFormat: if collectionFormat in DELIMETERS: delimeter = DELIMETERS[collectionFormat] # split the string based on the delimeter specified by the # `collectionFormat` processors.append(operator.methodcaller('split', delimeter)) else: if collectionFormat != MULTI: raise TypeError("collectionFormat not implemented") processors.append(add_string_into_list) # remove any Falsy values like empty strings. processors.append(functools.partial(filter, bool)) # strip off any whitespace processors.append( functools.partial(map, operator.methodcaller('strip'))) if items is not None: if isinstance(items, collections.Mapping): items_processors = itertools.repeat( generate_value_processor(**items)) elif isinstance(items, collections.Sequence): items_processors = itertools.chain( (generate_value_processor(**item) for item in items), itertools.repeat(lambda v: v), ) elif isinstance(items, six.string_types): raise NotImplementedError("Not implemented") else: assert False, "Should not be possible" # 1. zip the processor and the array items together # 2. apply the processor to each array item. # 3. cast the starmap generator to a list. processors.append( chain_reduce_partial( functools.partial(zip, items_processors), functools.partial(itertools.starmap, lambda fn, v: fn(v)), list, )) else: processors.append( functools.partial(cast_value_to_type, type_=type_)) def processor(value, **kwargs): try: return chain_reduce_partial(*processors)(value) except (ValueError, TypeError): return value return processor