def enum_validator(swagger_spec, validator, enums, instance, schema): """Swagger 2.0 allows enums to be validated against objects of type arrays, like query parameter (collectionFormat: multi) :param swagger_spec: needed for access to deref() :type swagger_spec: :class:`bravado_core.spec.Spec` :param validator: Validator class used to validate the object :type validator: :class: `Swagger20Validator` or :class: `jsonschema.validators.Draft4Validator` :param enums: allowed enum values :type enums: list :param instance: enum instance value :param schema: swagger spec for the object :type schema: dict """ if schema.get('type') == 'array': for element in instance: for error in _validators.enum(validator, enums, element, schema): yield error return # Handle optional enum params with no value if is_param_spec(swagger_spec, schema): if not is_required(swagger_spec, schema) and instance is None: return for error in _validators.enum(validator, enums, instance, schema): yield error
def marshal_primitive(swagger_spec, primitive_spec, value): """Marshal a python primitive type into a jsonschema primitive. :type swagger_spec: :class:`bravado_core.spec.Spec` :type primitive_spec: dict :type value: int, long, float, boolean, string, unicode, or an object based on 'format' :rtype: int, long, float, boolean, string, unicode, etc :raises: SwaggerMappingError """ default_used = False if value is None and schema.has_default(swagger_spec, primitive_spec): default_used = True value = schema.get_default(swagger_spec, primitive_spec) if value is None and schema.is_required(swagger_spec, primitive_spec): raise SwaggerMappingError( 'Spec {0} is a required value'.format(primitive_spec)) if not default_used: value = formatter.to_wire(swagger_spec, primitive_spec, value) return value
def unmarshal_collection_format(swagger_spec, param_spec, value): """For a non-body parameter of type array, unmarshal the value into an array of elements. Input: param_spec = { 'name': 'status' 'in': 'query', 'collectionFormat': 'psv', # pipe separated value 'type': 'array', 'items': { 'type': 'string', } } value="pending|completed|started" Output: ['pending', 'completed', 'started'] :type swagger_spec: :class:`bravado_core.spec.Spec` :param param_spec: param_spec of the parameter with 'type': 'array' :type param_spec: dict :param value: parameter value :type value: string :rtype: list """ deref = swagger_spec.deref param_spec = deref(param_spec) collection_format = param_spec.get('collectionFormat', 'csv') if value is None: if not schema.is_required(swagger_spec, param_spec): # Just pass through an optional array that has no value return None return schema.handle_null_value(swagger_spec, param_spec) if schema.is_list_like(value): value_array = value elif collection_format == 'multi': # http client lib should have already unmarshalled the value value_array = [value] else: sep = COLLECTION_FORMATS[collection_format] if value == '': value_array = [] else: value_array = value.split(sep) items_spec = param_spec['items'] items_type = deref(items_spec).get('type') param_name = param_spec['name'] return [ cast_request_param(items_type, param_name, item) for item in value_array ]
def unmarshal_collection_format(swagger_spec, param_spec, value): """For a non-body parameter of type array, unmarshal the value into an array of elements. Input: param_spec = { 'name': 'status' 'in': 'query', 'collectionFormat': 'psv', # pipe separated value 'type': 'array', 'items': { 'type': 'string', } } value="pending|completed|started" Output: ['pending', 'completed', 'started'] :type swagger_spec: :class:`bravado_core.spec.Spec` :param param_spec: param_spec of the parameter with 'type': 'array' :type param_spec: dict :param value: parameter value :type value: string :rtype: list """ deref = swagger_spec.deref param_spec = deref(param_spec) collection_format = param_spec.get('collectionFormat', 'csv') if value is None: if not schema.is_required(swagger_spec, param_spec): # Just pass through an optional array that has no value return None return schema.handle_null_value(swagger_spec, param_spec) if schema.is_list_like(value): value_array = value elif collection_format == 'multi': # http client lib should have already unmarshaled the value value_array = [value] else: sep = COLLECTION_FORMATS[collection_format] if value == '': value_array = [] else: value_array = value.split(sep) items_spec = param_spec['items'] items_type = deref(items_spec).get('type') param_name = param_spec['name'] return [ cast_request_param(items_type, param_name, item) for item in value_array ]
def marshal_param(param, value, request): """Given an operation's parameter and its value, marshal the value and place it in the proper request destination. Destination is one of: - path - can accept primitive and array of primitive types - query - can accept primitive and array of primitive types - header - can accept primitive and array of primitive types - body - can accept any type - formData - can accept primitive and array of primitive types :type param: :class:`bravado_core.param.Param` :param value: The value to assign to the parameter :type request: dict """ swagger_spec = param.swagger_spec deref = swagger_spec.deref param_spec = deref(get_param_type_spec(param)) location = param.location # Rely on unmarshalling behavior on the other side of the pipe to use # the default value if one is available. if value is None and not schema.is_required(swagger_spec, param_spec): return value = marshal_schema_object(swagger_spec, param_spec, value) if swagger_spec.config['validate_requests']: validate_schema_object(swagger_spec, param_spec, value) param_type = param_spec.get('type') if param_type == 'array' and location != 'body': value = marshal_collection_format(swagger_spec, param_spec, value) if location == 'path': token = u'{%s}' % param.name quoted_value = quote_plus(six.text_type(value).encode('utf8'), safe=',') request['url'] = request['url'].replace(token, quoted_value) elif location == 'query': request['params'][param.name] = value elif location == 'header': request['headers'][param.name] = str(value) elif location == 'formData': if param_type == 'file': add_file(param, value, request) else: request.setdefault('data', {})[param.name] = value elif location == 'body': request['headers']['Content-Type'] = APP_JSON request['data'] = json.dumps(value) else: raise SwaggerMappingError( "Don't know how to marshal_param with location {0}".format( location))
def marshal_param(param, value, request): """Given an operation's parameter and its value, marshal the value and place it in the proper request destination. Destination is one of: - path - can accept primitive and array of primitive types - query - can accept primitive and array of primitive types - header - can accept primitive and array of primitive types - body - can accept any type - formData - can accept primitive and array of primitive types :type param: :class:`bravado_core.param.Param` :param value: The value to assign to the parameter :type request: dict """ swagger_spec = param.swagger_spec deref = swagger_spec.deref param_spec = deref(get_param_type_spec(param)) location = param.location # Rely on unmarshalling behavior on the other side of the pipe to use # the default value if one is availabe. if value is None and not schema.is_required(swagger_spec, param_spec): return value = marshal_schema_object(swagger_spec, param_spec, value) if swagger_spec.config['validate_requests']: validate_schema_object(swagger_spec, param_spec, value) param_type = param_spec.get('type') if param_type == 'array' and location != 'body': value = marshal_collection_format(swagger_spec, param_spec, value) if location == 'path': token = u'{%s}' % param.name # Don't do any escaping/encoding - http_client will take care of it request['url'] = request['url'].replace(token, six.text_type(value)) elif location == 'query': request['params'][param.name] = value elif location == 'header': request['headers'][param.name] = value elif location == 'formData': if param_type == 'file': add_file(param, value, request) else: request.setdefault('data', {})[param.name] = value elif location == 'body': request['headers']['Content-Type'] = APP_JSON request['data'] = json.dumps(value) else: raise SwaggerMappingError( "Don't know how to marshal_param with location {0}". format(location))
def unmarshal_param(param, request): """Unmarshal the given parameter from the passed in request like object. :type param: :class:`bravado_core.param.Param` :type request: :class:`bravado_core.request.IncomingRequest` :return: value of parameter """ swagger_spec = param.swagger_spec deref = swagger_spec.deref param_spec = deref(get_param_type_spec(param)) location = param.location param_type = deref(param_spec.get('type')) cast_param = partial(cast_request_param, param_type, param.name) default_value = schema.get_default(swagger_spec, param_spec) if location == 'path': raw_value = cast_param(request.path.get(param.name, None)) elif location == 'query': raw_value = cast_param(request.query.get(param.name, default_value)) elif location == 'header': raw_value = cast_param(request.headers.get(param.name, default_value)) elif location == 'formData': if param_type == 'file': raw_value = request.files.get(param.name, None) else: raw_value = cast_param(request.form.get(param.name, default_value)) elif location == 'body': # TODO: verify content-type header try: raw_value = request.json() except ValueError as json_error: raise SwaggerMappingError("Error reading request body JSON: {0}". format(str(json_error))) else: raise SwaggerMappingError( "Don't know how to unmarshal_param with location {0}". format(location)) if raw_value is None and not schema.is_required(swagger_spec, param_spec): return None if param_type == 'array' and location != 'body': raw_value = unmarshal_collection_format(swagger_spec, param_spec, raw_value) if swagger_spec.config['validate_requests']: validate_schema_object(swagger_spec, param_spec, raw_value) value = unmarshal_schema_object(swagger_spec, param_spec, raw_value) return value
def unmarshal_primitive(swagger_spec, primitive_spec, value): """Unmarshal a jsonschema primitive type into a python primitive. :type swagger_spec: :class:`bravado_core.spec.Spec` :type primitive_spec: dict :type value: int, long, float, boolean, string, unicode, etc :rtype: int, long, float, boolean, string, unicode, or an object based on 'format' :raises: SwaggerMappingError """ if value is None and schema.is_required(swagger_spec, primitive_spec): raise SwaggerMappingError( 'Spec {0} says this is a required value'.format(primitive_spec)) value = formatter.to_python(swagger_spec, primitive_spec, value) return value
def unmarshal_primitive(spec, value): """Unmarshal a jsonschema primitive type into a python primitive. :type spec: dict or jsonref.JsonRef :type value: int, long, float, boolean, string, unicode, etc :rtype: int, long, float, boolean, string, unicode, or an object based on 'format' :raises: TypeError """ if value is None and schema.is_required(spec): # TODO: Error message needs more context. Consider adding a stack like # `context` object to each `unmarshal_*` method that acts like # breadcrumbs. raise TypeError('Spec {0} says this is a required value'.format(spec)) value = formatter.to_python(spec, value) return value
def unmarshal_primitive(swagger_spec, primitive_spec, value): """Unmarshal a jsonschema primitive type into a python primitive. :type swagger_spec: :class:`bravado_core.spec.Spec` :type primitive_spec: dict or jsonref.JsonRef :type value: int, long, float, boolean, string, unicode, etc :rtype: int, long, float, boolean, string, unicode, or an object based on 'format' :raises: SwaggerMappingError """ if value is None and schema.is_required(primitive_spec): # TODO: Error message needs more context. Consider adding a stack like # `context` object to each `unmarshal_*` method that acts like # breadcrumbs. raise SwaggerMappingError( 'Spec {0} says this is a required value'.format(primitive_spec)) value = formatter.to_python(swagger_spec, primitive_spec, value) return value
def unmarshal_array(swagger_spec, array_spec, array_value): """Unmarshal a jsonschema type of 'array' into a python list. :type swagger_spec: :class:`bravado_core.spec.Spec` :type array_spec: dict :type array_value: list :rtype: list :raises: SwaggerMappingError """ if not is_list_like(array_value): if array_value is None and not schema.is_required(swagger_spec, array_spec): return None raise SwaggerMappingError('Expected list like type for {0}:{1}'.format( type(array_value), array_value)) item_spec = swagger_spec.deref(array_spec).get('items') return [ unmarshal_schema_object(swagger_spec, item_spec, item) for item in array_value ]
def unmarshal_array(swagger_spec, array_spec, array_value): """Unmarshal a jsonschema type of 'array' into a python list. :type swagger_spec: :class:`bravado_core.spec.Spec` :type array_spec: dict :type array_value: list :rtype: list :raises: SwaggerMappingError """ if not is_list_like(array_value): if array_value is None and not schema.is_required( swagger_spec, array_spec): return None raise SwaggerMappingError('Expected list like type for {0}:{1}'.format( type(array_value), array_value)) item_spec = swagger_spec.deref(array_spec).get('items') return [ unmarshal_schema_object(swagger_spec, item_spec, item) for item in array_value ]
def enum_validator( swagger_spec, # type: Spec validator, # type: Draft4Validator enums, # type: typing.Any instance, # type: typing.Any schema, # type: JSONDict ): # type: (...) -> typing.Generator[ValidationError, None, None] """Swagger 2.0 allows enums to be validated against objects of type arrays, like query parameter (collectionFormat: multi) :param swagger_spec: needed for access to deref() :type swagger_spec: :class:`bravado_core.spec.Spec` :param validator: Validator class used to validate the object :type validator: :class: `Swagger20Validator` or :class: `jsonschema.validators.Draft4Validator` :param enums: allowed enum values :type enums: list :param instance: enum instance value :param schema: swagger spec for the object :type schema: dict """ if instance is None and is_prop_nullable(swagger_spec, schema): return if schema.get('type') == 'array': for element in instance: for error in _DRAFT4_ENUM_VALIDATOR(validator, enums, element, schema): yield error return # Handle optional enum params with no value if is_param_spec(swagger_spec, schema): if instance is None and not is_required(swagger_spec, schema): return for error in _DRAFT4_ENUM_VALIDATOR(validator, enums, instance, schema): yield error
def marshal_primitive(spec, value): """Marshal a python primitive type into a jsonschema primitive. :type spec: dict or jsonref.JsonRef :type value: int, long, float, boolean, string, unicode, or an object based on 'format' :rtype: int, long, float, boolean, string, unicode, etc :raises: TypeError """ default_used = False if value is None and schema.has_default(spec): default_used = True value = schema.get_default(spec) if value is None and schema.is_required(spec): raise TypeError('Spec {0} is a required value'.format(spec)) if not default_used: value = formatter.to_wire(spec, value) return value
def test_ref_default_to_false(minimal_swagger_dict): minimal_swagger_dict['definitions']['Foo'] = {'type': 'integer'} swagger_spec = Spec.from_dict(minimal_swagger_dict) assert not is_required(swagger_spec, {'$ref': '#/definitions/Foo'})
def test_ref_false(minimal_swagger_dict, required_false): minimal_swagger_dict["definitions"]["Foo"] = required_false swagger_spec = Spec(minimal_swagger_dict) assert not is_required(swagger_spec, {"$ref": "#/definitions/Foo"})
def test_ref_default_to_false(minimal_swagger_dict): minimal_swagger_dict["definitions"]["Foo"] = {"type": "integer"} swagger_spec = Spec.from_dict(minimal_swagger_dict) assert not is_required(swagger_spec, {"$ref": "#/definitions/Foo"})
def test_false(minimal_swagger_spec, object_spec): assert not is_required(minimal_swagger_spec, object_spec)
def test_true(minimal_swagger_spec, required_true): assert is_required(minimal_swagger_spec, required_true)
def test_false(minimal_swagger_spec, required_false): assert not is_required(minimal_swagger_spec, required_false)
def test_defaults_to_false(minimal_swagger_spec): assert not is_required(minimal_swagger_spec, {'type': 'integer'})
def test_ref_false(minimal_swagger_dict, required_false): minimal_swagger_dict['definitions']['Foo'] = required_false swagger_spec = Spec(minimal_swagger_dict) assert not is_required(swagger_spec, {'$ref': '#/definitions/Foo'})
def test_defaults_to_false(minimal_swagger_spec): assert not is_required(minimal_swagger_spec, {"type": "integer"})