diff --git a/openapi_core/schema/schemas/models.py b/openapi_core/schema/schemas/models.py index fd26ce7..7353dd0 100644 --- a/openapi_core/schema/schemas/models.py +++ b/openapi_core/schema/schemas/models.py @@ -161,6 +161,13 @@ class Schema(object): return defaultdict(lambda: lambda x: x, mapping) + 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 cast(self, value, custom_formatters=None, strict=True): """Cast value to schema type""" if value is None: @@ -311,7 +318,9 @@ class Schema(object): value_props_names = value.keys() extra_props = set(value_props_names) - set(all_props_names) - if extra_props and self.additional_properties is False: + extra_props_allowed = self.are_additional_properties_allowed( + one_of_schema) + if extra_props and not extra_props_allowed: raise UndefinedSchemaProperty(extra_props) properties = {} @@ -543,7 +552,9 @@ class Schema(object): value_props_names = value.keys() extra_props = set(value_props_names) - set(all_props_names) - if extra_props and self.additional_properties is False: + extra_props_allowed = self.are_additional_properties_allowed( + one_of_schema) + if extra_props and not extra_props_allowed: raise UndefinedSchemaProperty(extra_props) if self.additional_properties is not True: diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index fa608e2..b66dad7 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -711,6 +711,39 @@ class TestSchemaValidate(object): with pytest.raises(NoOneOfSchema): schema.validate(value) + @pytest.mark.parametrize('value', [ + Model({ + 'foo': u("FOO"), + }), + Model({ + 'foo': u("FOO"), + 'bar': u("BAR"), + }), + ]) + def test_unambiguous_one_of(self, value): + one_of = [ + Schema( + 'object', + properties={ + 'foo': Schema('string'), + }, + additional_properties=False, + required=['foo'], + ), + Schema( + 'object', + properties={ + 'foo': Schema('string'), + 'bar': Schema('string'), + }, + additional_properties=False, + required=['foo', 'bar'], + ), + ] + schema = Schema('object', one_of=one_of) + + schema.validate(value) + @pytest.mark.parametrize('value', [Model(), ]) def test_object_default_property(self, value): schema = Schema('object', default='value1')