diff --git a/openapi_core/schema/schemas/models.py b/openapi_core/schema/schemas/models.py index b9784cf..9728ea9 100644 --- a/openapi_core/schema/schemas/models.py +++ b/openapi_core/schema/schemas/models.py @@ -2,7 +2,6 @@ import attr import functools import logging -from base64 import b64decode, b64encode from collections import defaultdict from datetime import date, datetime from uuid import UUID @@ -229,6 +228,9 @@ class Schema(object): else: raise InvalidSchemaValue(msg, value, self.format) else: + if self.enum and value not in self.enum: + raise InvalidSchemaValue( + "Value {value} not in enum choices: {type}", value, self.enum) formatstring = self.STRING_FORMAT_CALLABLE_GETTER[schema_format] try: @@ -278,13 +280,30 @@ class Schema(object): SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING, ] cast_mapping = self.get_cast_mapping() - for schema_type in types_resolve_order: - cast_callable = cast_mapping[schema_type] - try: - return cast_callable(value) - # @todo: remove ValueError when validation separated - except (OpenAPISchemaError, TypeError, ValueError): - continue + if self.one_of: + result = None + for subschema in self.one_of: + try: + casted = subschema.cast(value, custom_formatters) + except (OpenAPISchemaError, TypeError, ValueError): + continue + else: + if result is not None: + raise MultipleOneOfSchema(self.type) + result = casted + + if result is None: + raise NoOneOfSchema(self.type) + + return result + else: + for schema_type in types_resolve_order: + cast_callable = cast_mapping[schema_type] + try: + return cast_callable(value) + # @todo: remove ValueError when validation separated + except (OpenAPISchemaError, TypeError, ValueError): + continue raise NoValidSchema(value) diff --git a/tests/integration/test_petstore.py b/tests/integration/test_petstore.py index ceab793..4c92c91 100644 --- a/tests/integration/test_petstore.py +++ b/tests/integration/test_petstore.py @@ -1,5 +1,6 @@ import json import pytest +from datetime import datetime from base64 import b64encode from uuid import UUID from six import iteritems, text_type @@ -19,7 +20,7 @@ from openapi_core.schema.request_bodies.models import RequestBody from openapi_core.schema.responses.models import Response from openapi_core.schema.schemas.enums import SchemaType from openapi_core.schema.schemas.exceptions import ( - NoValidSchema, InvalidSchemaProperty, InvalidSchemaValue, + InvalidSchemaProperty, InvalidSchemaValue, ) from openapi_core.schema.schemas.models import Schema from openapi_core.schema.servers.exceptions import InvalidServer @@ -1213,7 +1214,7 @@ class TestPetstore(object): assert parameters == {} assert isinstance(body, BaseModel) - assert body.created == created + assert body.created == datetime(2016, 4, 16, 16, 6, 5) assert body.name == pet_name code = 400 @@ -1257,7 +1258,7 @@ class TestPetstore(object): ) parameters = request.get_parameters(spec) - with pytest.raises(NoValidSchema): + with pytest.raises(InvalidMediaTypeValue): request.get_body(spec) assert parameters == {} diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index 8efd96b..05dc599 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -300,6 +300,33 @@ class TestSchemaUnmarshal(object): assert result == 1.2 + def test_schema_any_one_of(self): + schema = Schema(one_of=[ + Schema('string'), + Schema('array', items=Schema('string')), + ]) + assert schema.unmarshal(['hello']) == ['hello'] + + def test_schema_any_one_of_mutiple(self): + schema = Schema(one_of=[ + Schema('array', items=Schema('string')), + Schema('array', items=Schema('number')), + ]) + with pytest.raises(MultipleOneOfSchema): + schema.unmarshal([]) + + def test_schema_any_one_of_no_valid(self): + schema = Schema(one_of=[ + Schema('array', items=Schema('string')), + Schema('array', items=Schema('number')), + ]) + with pytest.raises(NoOneOfSchema): + schema.unmarshal({}) + + def test_schema_any(self): + schema = Schema() + assert schema.unmarshal('string') == 'string' + class TestSchemaValidate(object):