From 7830605c1c4993df864d292c8555fa3cf414f6ca Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Thu, 17 Nov 2022 14:07:01 -0500 Subject: [PATCH] Emit a better error message for unevaluatedProperties with a subschema. Closes: #996 --- jsonschema/_validators.py | 25 +++++++++++++++++-------- jsonschema/tests/test_validators.py | 21 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/jsonschema/_validators.py b/jsonschema/_validators.py index 874e8796f..8542a879c 100644 --- a/jsonschema/_validators.py +++ b/jsonschema/_validators.py @@ -435,23 +435,32 @@ def unevaluatedItems(validator, unevaluatedItems, instance, schema): def unevaluatedProperties(validator, unevaluatedProperties, instance, schema): if not validator.is_type(instance, "object"): return - evaluated_property_keys = find_evaluated_property_keys_by_schema( + evaluated_keys = find_evaluated_property_keys_by_schema( validator, instance, schema, ) - unevaluated_property_keys = [] + unevaluated_keys = [] for property in instance: - if property not in evaluated_property_keys: + if property not in evaluated_keys: for _ in validator.descend( instance[property], unevaluatedProperties, path=property, schema_path=property, ): - unevaluated_property_keys.append(property) - - if unevaluated_property_keys: - error = "Unevaluated properties are not allowed (%s %s unexpected)" - yield ValidationError(error % extras_msg(unevaluated_property_keys)) + # FIXME: Include context for each unevaluated property + # indicating why it's invalid under the subschema. + unevaluated_keys.append(property) + + if unevaluated_keys: + if unevaluatedProperties is False: + error = "Unevaluated properties are not allowed (%s %s unexpected)" + yield ValidationError(error % extras_msg(unevaluated_keys)) + else: + error = ( + "Unevaluated properties are not valid under " + "the given schema (%s %s unevaluated and invalid)" + ) + yield ValidationError(error % extras_msg(unevaluated_keys)) def prefixItems(validator, prefixItems, instance, schema): diff --git a/jsonschema/tests/test_validators.py b/jsonschema/tests/test_validators.py index 12c9dc9db..8f8680a0f 100644 --- a/jsonschema/tests/test_validators.py +++ b/jsonschema/tests/test_validators.py @@ -634,7 +634,26 @@ def test_unevaluated_items_on_invalid_type(self): message = self.message_for(instance="foo", schema=schema) self.assertEqual(message, "'foo' is not of type 'array'") - def test_unevaluated_properties(self): + def test_unevaluated_properties_invalid_against_subschema(self): + schema = { + "properties": {"foo": {"type": "string"}}, + "unevaluatedProperties": {"const": 12}, + } + message = self.message_for( + instance={ + "foo": "foo", + "bar": "bar", + "baz": 12, + }, + schema=schema, + ) + self.assertEqual( + message, + "Unevaluated properties are not valid under the given schema " + "('bar' was unevaluated and invalid)", + ) + + def test_unevaluated_properties_disallowed(self): schema = {"type": "object", "unevaluatedProperties": False} message = self.message_for( instance={