diff --git a/openapi_core/schema/media_types/models.py b/openapi_core/schema/media_types/models.py index 61b2e3d..e593a1a 100644 --- a/openapi_core/schema/media_types/models.py +++ b/openapi_core/schema/media_types/models.py @@ -4,7 +4,9 @@ from collections import defaultdict from json import loads from openapi_core.schema.media_types.exceptions import InvalidMediaTypeValue -from openapi_core.schema.schemas.exceptions import OpenAPISchemaError +from openapi_core.schema.schemas.exceptions import ( + CastError, ValidateError, UnmarshalError, +) MEDIA_TYPE_DESERIALIZERS = { @@ -37,20 +39,25 @@ class MediaType(object): return value try: - return self.deserialize(value) + deserialized = self.deserialize(value) except ValueError as exc: raise InvalidMediaTypeValue(exc) + try: + return self.schema.cast(deserialized) + except CastError as exc: + raise InvalidMediaTypeValue(exc) + def unmarshal(self, value, custom_formatters=None, resolver=None): if not self.schema: return value try: self.schema.validate(value, resolver=resolver) - except OpenAPISchemaError as exc: + except ValidateError as exc: raise InvalidMediaTypeValue(exc) try: return self.schema.unmarshal(value, custom_formatters=custom_formatters) - except OpenAPISchemaError as exc: + except UnmarshalError as exc: raise InvalidMediaTypeValue(exc) diff --git a/openapi_core/schema/parameters/exceptions.py b/openapi_core/schema/parameters/exceptions.py index bcaf13f..79b61c4 100644 --- a/openapi_core/schema/parameters/exceptions.py +++ b/openapi_core/schema/parameters/exceptions.py @@ -7,8 +7,13 @@ class OpenAPIParameterError(OpenAPIMappingError): pass +class MissingParameterError(OpenAPIParameterError): + """Missing parameter error""" + pass + + @attr.s(hash=True) -class MissingParameter(OpenAPIParameterError): +class MissingParameter(MissingParameterError): name = attr.ib() def __str__(self): @@ -16,7 +21,7 @@ class MissingParameter(OpenAPIParameterError): @attr.s(hash=True) -class MissingRequiredParameter(OpenAPIParameterError): +class MissingRequiredParameter(MissingParameterError): name = attr.ib() def __str__(self): diff --git a/openapi_core/schema/parameters/models.py b/openapi_core/schema/parameters/models.py index 612b062..98af859 100644 --- a/openapi_core/schema/parameters/models.py +++ b/openapi_core/schema/parameters/models.py @@ -10,7 +10,9 @@ from openapi_core.schema.parameters.exceptions import ( EmptyParameterValue, ) from openapi_core.schema.schemas.enums import SchemaType -from openapi_core.schema.schemas.exceptions import OpenAPISchemaError +from openapi_core.schema.schemas.exceptions import ( + CastError, ValidateError, UnmarshalError, +) log = logging.getLogger(__name__) @@ -110,7 +112,7 @@ class Parameter(object): try: return self.schema.cast(deserialized) - except OpenAPISchemaError as exc: + except CastError as exc: raise InvalidParameterValue(self.name, exc) def unmarshal(self, value, custom_formatters=None, resolver=None): @@ -119,7 +121,7 @@ class Parameter(object): try: self.schema.validate(value, resolver=resolver) - except OpenAPISchemaError as exc: + except ValidateError as exc: raise InvalidParameterValue(self.name, exc) try: @@ -128,5 +130,5 @@ class Parameter(object): custom_formatters=custom_formatters, strict=True, ) - except OpenAPISchemaError as exc: + except UnmarshalError as exc: raise InvalidParameterValue(self.name, exc) diff --git a/openapi_core/schema/schemas/exceptions.py b/openapi_core/schema/schemas/exceptions.py index 2adcde5..2b87923 100644 --- a/openapi_core/schema/schemas/exceptions.py +++ b/openapi_core/schema/schemas/exceptions.py @@ -8,72 +8,95 @@ class OpenAPISchemaError(OpenAPIMappingError): @attr.s(hash=True) -class NoValidSchema(OpenAPISchemaError): - value = attr.ib() - - def __str__(self): - return "No valid schema found for value: {0}".format(self.value) - - -@attr.s(hash=True) -class UndefinedItemsSchema(OpenAPISchemaError): - type = attr.ib() - - def __str__(self): - return "Null value for schema type {0}".format(self.type) - - -@attr.s(hash=True) -class InvalidSchemaValue(OpenAPISchemaError): - msg = attr.ib() +class CastError(OpenAPISchemaError): + """Schema cast operation error""" value = attr.ib() type = attr.ib() def __str__(self): - return self.msg.format(value=self.value, type=self.type) + return "Failed to cast value {value} to type {type}".format( + value=self.value, type=self.type) -@attr.s(hash=True) -class InvalidCustomFormatSchemaValue(InvalidSchemaValue): - original_exception = attr.ib() - - def __str__(self): - return self.msg.format(value=self.value, type=self.type, exception=self.original_exception) - - -@attr.s(hash=True) -class UndefinedSchemaProperty(OpenAPISchemaError): - extra_props = attr.ib() - - def __str__(self): - return "Extra unexpected properties found in schema: {0}".format(self.extra_props) - - -@attr.s(hash=True) -class InvalidSchemaProperty(OpenAPISchemaError): - property_name = attr.ib() - original_exception = attr.ib() - - def __str__(self): - return "Invalid schema property {0}: {1}".format(self.property_name, self.original_exception) - - -@attr.s(hash=True) -class MissingSchemaProperty(OpenAPISchemaError): - property_name = attr.ib() - - def __str__(self): - return "Missing schema property: {0}".format(self.property_name) - - -class UnmarshallerError(OpenAPIMappingError): +class ValidateError(OpenAPISchemaError): + """Schema validate operation error""" pass +class UnmarshalError(OpenAPISchemaError): + """Schema unmarshal operation error""" + pass + + +@attr.s(hash=True) +class UnmarshalValueError(UnmarshalError): + """Failed to unmarshal value to type""" + value = attr.ib() + type = attr.ib() + original_exception = attr.ib(default=None) + + def __str__(self): + return ( + "Failed to unmarshal value {value} to type {type}: {exception}" + ).format( + value=self.value, type=self.type, + exception=self.original_exception, + ) + + +@attr.s(hash=True) +class InvalidSchemaValue(ValidateError): + value = attr.ib() + type = attr.ib() + schema_errors = attr.ib() + + def __str__(self): + errors = list(self.schema_errors) + return ( + "Value {value} not valid for schema of type {type}: {errors}" + ).format(value=self.value, type=self.type, errors=errors) + + +class UnmarshallerError(UnmarshalError): + """Unmarshaller error""" + pass + + +@attr.s(hash=True) +class InvalidCustomFormatSchemaValue(UnmarshallerError): + """Value failed to format with custom formatter""" + value = attr.ib() + type = attr.ib() + original_exception = attr.ib() + + def __str__(self): + return ( + "Failed to format value {value} to format {type}: {exception}" + ).format( + value=self.value, type=self.type, + exception=self.original_exception, + ) + + +@attr.s(hash=True) +class FormatterNotFoundError(UnmarshallerError): + """Formatter not found to unmarshal""" + value = attr.ib() + type_format = attr.ib() + + def __str__(self): + return ( + "Formatter not found for {format} format " + "to unmarshal value {value}" + ).format(format=self.type_format, value=self.value) + + +@attr.s(hash=True) class UnmarshallerStrictTypeError(UnmarshallerError): value = attr.ib() types = attr.ib() def __str__(self): - return "Value {value} is not one of types {types}".format( - self.value, self.types) + types = ', '.join(list(map(str, self.types))) + return "Value {value} is not one of types: {types}".format( + value=self.value, types=types) diff --git a/openapi_core/schema/schemas/models.py b/openapi_core/schema/schemas/models.py index 44ca3e6..534c7b7 100644 --- a/openapi_core/schema/schemas/models.py +++ b/openapi_core/schema/schemas/models.py @@ -15,10 +15,8 @@ from openapi_core.extensions.models.factories import ModelFactory from openapi_core.schema.schemas._format import oas30_format_checker from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType from openapi_core.schema.schemas.exceptions import ( - InvalidSchemaValue, UndefinedSchemaProperty, MissingSchemaProperty, - OpenAPISchemaError, NoValidSchema, - UndefinedItemsSchema, InvalidCustomFormatSchemaValue, InvalidSchemaProperty, - UnmarshallerStrictTypeError, + CastError, InvalidSchemaValue, + UnmarshallerError, UnmarshalValueError, UnmarshalError, ) from openapi_core.schema.schemas.util import ( forcebool, format_date, format_datetime, format_byte, format_uuid, @@ -141,13 +139,6 @@ class Schema(object): return set(required) - def are_additional_properties_allowed(self, one_of_schema=None): - return ( - (self.additional_properties is not False) and - (one_of_schema is None or - one_of_schema.additional_properties is not False) - ) - def get_cast_mapping(self): mapping = self.TYPE_CAST_CALLABLE_GETTER.copy() mapping.update({ @@ -167,8 +158,7 @@ class Schema(object): try: return cast_callable(value) except ValueError: - raise InvalidSchemaValue( - "Failed to cast value {value} to type {type}", value, self.type) + raise CastError(value, self.type) def _cast_collection(self, value): return list(map(self.items.cast, value)) @@ -203,8 +193,8 @@ class Schema(object): try: return validator.validate(value) except ValidationError: - # TODO: pass validation errors - raise InvalidSchemaValue("Value not valid for schema", value, self.type) + errors_iter = validator.iter_errors(value) + raise InvalidSchemaValue(value, self.type, errors_iter) def unmarshal(self, value, custom_formatters=None, strict=True): """Unmarshal parameter from the value.""" @@ -212,12 +202,12 @@ class Schema(object): warnings.warn("The schema is deprecated", DeprecationWarning) if value is None: if not self.nullable: - raise InvalidSchemaValue("Null value for non-nullable schema", value, self.type) + raise UnmarshalError( + "Null value for non-nullable schema", value, self.type) return self.default if self.enum and value not in self.enum: - raise InvalidSchemaValue( - "Value {value} not in enum choices: {type}", value, self.enum) + raise UnmarshalError("Invalid value for enum: {0}".format(value)) unmarshal_mapping = self.get_unmarshal_mapping( custom_formatters=custom_formatters, strict=strict) @@ -228,12 +218,8 @@ class Schema(object): unmarshal_callable = unmarshal_mapping[self.type] try: unmarshalled = unmarshal_callable(value) - except UnmarshallerStrictTypeError: - raise InvalidSchemaValue( - "Value {value} is not of type {type}", value, self.type) - except ValueError: - raise InvalidSchemaValue( - "Failed to unmarshal value {value} to type {type}", value, self.type) + except ValueError as exc: + raise UnmarshalValueError(value, self.type, exc) return unmarshalled @@ -268,7 +254,7 @@ class Schema(object): for subschema in self.one_of: try: unmarshalled = subschema.unmarshal(value, custom_formatters) - except (OpenAPISchemaError, TypeError, ValueError): + except UnmarshalError: continue else: if result is not None: @@ -285,9 +271,7 @@ class Schema(object): unmarshal_callable = unmarshal_mapping[schema_type] try: return unmarshal_callable(value) - except UnmarshallerStrictTypeError: - continue - except (OpenAPISchemaError, TypeError): + except (UnmarshalError, ValueError): continue log.warning("failed to unmarshal any type") @@ -295,7 +279,7 @@ class Schema(object): def _unmarshal_collection(self, value, custom_formatters=None, strict=True): if not isinstance(value, (list, tuple)): - raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type) + raise ValueError("Invalid value for collection: {0}".format(value)) f = functools.partial( self.items.unmarshal, @@ -306,7 +290,7 @@ class Schema(object): def _unmarshal_object(self, value, model_factory=None, custom_formatters=None, strict=True): if not isinstance(value, (dict, )): - raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type) + raise ValueError("Invalid value for object: {0}".format(value)) model_factory = model_factory or ModelFactory() @@ -316,7 +300,7 @@ class Schema(object): try: unmarshalled = self._unmarshal_properties( value, one_of_schema, custom_formatters=custom_formatters) - except OpenAPISchemaError: + except (UnmarshalError, ValueError): pass else: if properties is not None: @@ -348,10 +332,6 @@ class Schema(object): value_props_names = value.keys() extra_props = set(value_props_names) - set(all_props_names) - extra_props_allowed = self.are_additional_properties_allowed( - one_of_schema) - if extra_props and not extra_props_allowed: - raise UndefinedSchemaProperty(extra_props) properties = {} if self.additional_properties is not True: @@ -364,8 +344,6 @@ class Schema(object): try: prop_value = value[prop_name] except KeyError: - if prop_name in all_req_props_names: - raise MissingSchemaProperty(prop_name) if not prop.nullable and not prop.default: continue prop_value = prop.default diff --git a/openapi_core/schema/schemas/unmarshallers.py b/openapi_core/schema/schemas/unmarshallers.py index 31ba5b6..b3d0ece 100644 --- a/openapi_core/schema/schemas/unmarshallers.py +++ b/openapi_core/schema/schemas/unmarshallers.py @@ -2,10 +2,9 @@ from six import text_type, binary_type, integer_types from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType from openapi_core.schema.schemas.exceptions import ( - InvalidSchemaValue, InvalidCustomFormatSchemaValue, - OpenAPISchemaError, - InvalidSchemaProperty, + InvalidCustomFormatSchemaValue, UnmarshallerStrictTypeError, + FormatterNotFoundError, ) from openapi_core.schema.schemas.util import ( forcebool, format_date, format_datetime, format_byte, format_uuid, @@ -49,17 +48,12 @@ class PrimitiveTypeUnmarshaller(StrictUnmarshaller): formatter = formatters.get(schema_format) if formatter is None: - raise InvalidSchemaValue( - "Unsupported format {type} unmarshalling " - "for value {value}", - value, type_format) + raise FormatterNotFoundError(value, type_format) try: return formatter(value) except ValueError as exc: - raise InvalidCustomFormatSchemaValue( - "Failed to format value {value} to format {type}: {exception}", - value, type_format, exc) + raise InvalidCustomFormatSchemaValue(value, type_format, exc) def get_formatters(self): return self.FORMATTERS diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index dd726d9..f41008e 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -2,8 +2,16 @@ from itertools import chain from six import iteritems -from openapi_core.schema.exceptions import OpenAPIMappingError -from openapi_core.schema.parameters.exceptions import MissingParameter +from openapi_core.schema.media_types.exceptions import ( + InvalidMediaTypeValue, InvalidContentType, +) +from openapi_core.schema.operations.exceptions import InvalidOperation +from openapi_core.schema.parameters.exceptions import ( + OpenAPIParameterError, MissingRequiredParameter, +) +from openapi_core.schema.paths.exceptions import InvalidPath +from openapi_core.schema.request_bodies.exceptions import MissingRequestBody +from openapi_core.schema.servers.exceptions import InvalidServer from openapi_core.validation.request.datatypes import ( RequestParameters, RequestValidationResult, ) @@ -20,7 +28,7 @@ class RequestValidator(object): try: server = self.spec.get_server(request.full_url_pattern) # don't process if server errors - except OpenAPIMappingError as exc: + except InvalidServer as exc: return RequestValidationResult([exc, ], None, None) operation_pattern = get_operation_pattern( @@ -29,10 +37,14 @@ class RequestValidator(object): try: path = self.spec[operation_pattern] + except InvalidPath as exc: + return RequestValidationResult([exc, ], None, None) + + try: operation = self.spec.get_operation( operation_pattern, request.method) # don't process if operation errors - except OpenAPIMappingError as exc: + except InvalidOperation as exc: return RequestValidationResult([exc, ], None, None) params, params_errors = self._get_parameters( @@ -59,15 +71,15 @@ class RequestValidator(object): seen.add((param_name, param.location.value)) try: raw_value = param.get_raw_value(request) - except MissingParameter: - continue - except OpenAPIMappingError as exc: + except MissingRequiredParameter as exc: errors.append(exc) continue + except OpenAPIParameterError: + continue try: casted = param.cast(raw_value) - except OpenAPIMappingError as exc: + except OpenAPIParameterError as exc: errors.append(exc) continue @@ -76,7 +88,7 @@ class RequestValidator(object): casted, self.custom_formatters, resolver=self.spec._resolver, ) - except OpenAPIMappingError as exc: + except OpenAPIParameterError as exc: errors.append(exc) else: locations.setdefault(param.location.value, {}) @@ -93,17 +105,17 @@ class RequestValidator(object): body = None try: media_type = operation.request_body[request.mimetype] - except OpenAPIMappingError as exc: + except InvalidContentType as exc: errors.append(exc) else: try: raw_body = operation.request_body.get_value(request) - except OpenAPIMappingError as exc: + except MissingRequestBody as exc: errors.append(exc) else: try: casted = media_type.cast(raw_body) - except OpenAPIMappingError as exc: + except InvalidMediaTypeValue as exc: errors.append(exc) else: try: @@ -111,7 +123,7 @@ class RequestValidator(object): casted, self.custom_formatters, resolver=self.spec._resolver, ) - except OpenAPIMappingError as exc: + except InvalidMediaTypeValue as exc: errors.append(exc) return body, errors diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py index 341b294..4859f19 100644 --- a/openapi_core/validation/response/validators.py +++ b/openapi_core/validation/response/validators.py @@ -1,5 +1,12 @@ """OpenAPI core validation response validators module""" -from openapi_core.schema.exceptions import OpenAPIMappingError +from openapi_core.schema.operations.exceptions import InvalidOperation +from openapi_core.schema.media_types.exceptions import ( + InvalidMediaTypeValue, InvalidContentType, +) +from openapi_core.schema.responses.exceptions import ( + InvalidResponse, MissingResponseContent, +) +from openapi_core.schema.servers.exceptions import InvalidServer from openapi_core.validation.response.datatypes import ResponseValidationResult from openapi_core.validation.util import get_operation_pattern @@ -14,7 +21,7 @@ class ResponseValidator(object): try: server = self.spec.get_server(request.full_url_pattern) # don't process if server errors - except OpenAPIMappingError as exc: + except InvalidServer as exc: return ResponseValidationResult([exc, ], None, None) operation_pattern = get_operation_pattern( @@ -25,14 +32,14 @@ class ResponseValidator(object): operation = self.spec.get_operation( operation_pattern, request.method) # don't process if operation errors - except OpenAPIMappingError as exc: + except InvalidOperation as exc: return ResponseValidationResult([exc, ], None, None) try: operation_response = operation.get_response( str(response.status_code)) # don't process if operation response errors - except OpenAPIMappingError as exc: + except InvalidResponse as exc: return ResponseValidationResult([exc, ], None, None) data, data_errors = self._get_data(response, operation_response) @@ -52,17 +59,17 @@ class ResponseValidator(object): data = None try: media_type = operation_response[response.mimetype] - except OpenAPIMappingError as exc: + except InvalidContentType as exc: errors.append(exc) else: try: raw_data = operation_response.get_value(response) - except OpenAPIMappingError as exc: + except MissingResponseContent as exc: errors.append(exc) else: try: casted = media_type.cast(raw_data) - except OpenAPIMappingError as exc: + except InvalidMediaTypeValue as exc: errors.append(exc) else: try: @@ -70,7 +77,7 @@ class ResponseValidator(object): casted, self.custom_formatters, resolver=self.spec._resolver, ) - except OpenAPIMappingError as exc: + except InvalidMediaTypeValue as exc: errors.append(exc) return data, errors diff --git a/tests/integration/validation/test_petstore.py b/tests/integration/validation/test_petstore.py index 0e06022..38ab8ba 100644 --- a/tests/integration/validation/test_petstore.py +++ b/tests/integration/validation/test_petstore.py @@ -175,12 +175,13 @@ class TestPetstore(object): response_result = response_validator.validate(request, response) + errors = response_result.errors[0].original_exception.schema_errors assert response_result.errors == [ InvalidMediaTypeValue( original_exception=InvalidSchemaValue( - msg='Value not valid for schema', type=SchemaType.OBJECT, value=data_json, + schema_errors=errors, ), ), ] diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index f8d9a88..74fe396 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -7,7 +7,9 @@ import pytest from openapi_core.extensions.models.models import Model from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType from openapi_core.schema.schemas.exceptions import ( - InvalidSchemaValue, OpenAPISchemaError, + InvalidSchemaValue, OpenAPISchemaError, UnmarshallerStrictTypeError, + UnmarshalValueError, UnmarshalError, InvalidCustomFormatSchemaValue, + FormatterNotFoundError, ) from openapi_core.schema.schemas.models import Schema @@ -88,14 +90,14 @@ class TestSchemaUnmarshal(object): schema = Schema('string') value = 1.23 - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshallerStrictTypeError): schema.unmarshal(value) def test_string_none(self): schema = Schema('string') value = None - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalError): schema.unmarshal(value) def test_string_default(self): @@ -103,7 +105,7 @@ class TestSchemaUnmarshal(object): schema = Schema('string', default=default_value) value = None - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalError): schema.unmarshal(value) def test_string_default_nullable(self): @@ -150,7 +152,7 @@ class TestSchemaUnmarshal(object): schema = Schema('string', schema_format=custom_format) value = 'x' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(InvalidCustomFormatSchemaValue): schema.unmarshal( value, custom_formatters={custom_format: custom_formatter}) @@ -168,7 +170,10 @@ class TestSchemaUnmarshal(object): value = 'x' with pytest.raises( - InvalidSchemaValue, message='Failed to format value' + FormatterNotFoundError, + message=( + 'Formatter not found for custom format to unmarshal value x' + ), ): schema.unmarshal(value) @@ -184,14 +189,14 @@ class TestSchemaUnmarshal(object): schema = Schema('integer') value = '123' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshallerStrictTypeError): schema.unmarshal(value) def test_integer_enum_invalid(self): schema = Schema('integer', enum=[1, 2, 3]) value = '123' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalError): schema.unmarshal(value) def test_integer_enum(self): @@ -206,7 +211,7 @@ class TestSchemaUnmarshal(object): schema = Schema('integer', enum=[1, 2, 3]) value = '2' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalError): schema.unmarshal(value) def test_integer_default(self): @@ -214,7 +219,7 @@ class TestSchemaUnmarshal(object): schema = Schema('integer', default=default_value) value = None - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalError): schema.unmarshal(value) def test_integer_default_nullable(self): @@ -230,7 +235,7 @@ class TestSchemaUnmarshal(object): schema = Schema('integer') value = 'abc' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshallerStrictTypeError): schema.unmarshal(value) def test_array_valid(self): @@ -245,14 +250,14 @@ class TestSchemaUnmarshal(object): schema = Schema('array', items=Schema('string')) value = '123' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalValueError): schema.unmarshal(value) def test_array_of_integer_string_invalid(self): schema = Schema('array', items=Schema('integer')) value = '123' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshalValueError): schema.unmarshal(value) def test_boolean_valid(self): @@ -267,7 +272,7 @@ class TestSchemaUnmarshal(object): schema = Schema('boolean') value = 'True' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshallerStrictTypeError): schema.unmarshal(value) def test_number_valid(self): @@ -282,7 +287,7 @@ class TestSchemaUnmarshal(object): schema = Schema('number') value = '1.23' - with pytest.raises(InvalidSchemaValue): + with pytest.raises(UnmarshallerStrictTypeError): schema.unmarshal(value) def test_number_int(self):