diff --git a/openapi_core/unmarshalling/schemas/unmarshallers.py b/openapi_core/unmarshalling/schemas/unmarshallers.py index 53ddcc34..1df9ed09 100644 --- a/openapi_core/unmarshalling/schemas/unmarshallers.py +++ b/openapi_core/unmarshalling/schemas/unmarshallers.py @@ -137,6 +137,9 @@ def _unmarshal_properties( class MultiTypeUnmarshaller(PrimitiveUnmarshaller): def __call__(self, value: Any) -> Any: primitive_type = self.schema_validator.get_primitive_type(value) + # OpenAPI 3.0: handle no type for None + if primitive_type is None: + return None unmarshaller = self.schema_unmarshaller.get_type_unmarshaller( primitive_type ) @@ -247,6 +250,9 @@ def unmarshal(self, value: Any) -> Any: schema_type = self.schema.getkey("type") type_unmarshaller = self.get_type_unmarshaller(schema_type) typed = type_unmarshaller(value) + # skip finding format for None + if typed is None: + return None schema_format = self.find_format(value) if schema_format is None: return typed diff --git a/openapi_core/validation/schemas/validators.py b/openapi_core/validation/schemas/validators.py index c822a82f..7a764e31 100644 --- a/openapi_core/validation/schemas/validators.py +++ b/openapi_core/validation/schemas/validators.py @@ -94,6 +94,7 @@ def get_primitive_type(self, value: Any) -> Optional[str]: continue assert isinstance(schema_type, (str, type(None))) return schema_type + # OpenAPI 3.0: None is not a primitive type so None value will not find any type return None def iter_valid_schemas(self, value: Any) -> Iterator[SchemaPath]: diff --git a/tests/integration/unmarshalling/test_unmarshallers.py b/tests/integration/unmarshalling/test_unmarshallers.py index 764fc3af..54e944a3 100644 --- a/tests/integration/unmarshalling/test_unmarshallers.py +++ b/tests/integration/unmarshalling/test_unmarshallers.py @@ -1840,6 +1840,25 @@ def test_object_property_nullable(self, unmarshallers_factory): assert result == value + def test_subschema_nullable(self, unmarshallers_factory): + schema = { + "oneOf": [ + { + "type": "integer", + }, + { + "nullable": True, + }, + ] + } + spec = SchemaPath.from_dict(schema) + unmarshaller = unmarshallers_factory.create(spec) + value = None + + result = unmarshaller.unmarshal(value) + + assert result is None + class TestOAS30RequestSchemaUnmarshallersFactory( BaseTestOASSchemaUnmarshallersFactoryCall, @@ -2086,3 +2105,22 @@ def test_any_null(self, unmarshallers_factory): result = unmarshaller.unmarshal(None) assert result is None + + def test_subschema_null(self, unmarshallers_factory): + schema = { + "oneOf": [ + { + "type": "integer", + }, + { + "type": "null", + }, + ] + } + spec = SchemaPath.from_dict(schema) + unmarshaller = unmarshallers_factory.create(spec) + value = None + + result = unmarshaller.unmarshal(value) + + assert result is None