Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions jsonschema/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,13 @@ def find_additional_properties(instance, schema):
Assumes ``instance`` is dict-like already.
"""
properties = schema.get("properties", {})
patterns = "|".join(schema.get("patternProperties", {}))
patterns = schema.get("patternProperties", {})
for property in instance:
if property not in properties:
if patterns and re.search(patterns, property):
continue
yield property
if property in properties:
continue
if any(re.search(pattern, property) for pattern in patterns):
continue
yield property


def extras_msg(extras):
Expand Down
20 changes: 19 additions & 1 deletion jsonschema/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from math import nan
from unittest import TestCase

from jsonschema._utils import equal, uniq
from jsonschema._utils import equal, find_additional_properties, uniq


class Unhashable:
Expand Down Expand Up @@ -223,3 +223,21 @@ def test_unhashable_inside_mapping_falls_back(self):
self.assertTrue(
uniq([{"k": Unhashable(1)}, {"k": Unhashable(2)}]),
)


class TestFindAdditionalProperties(TestCase):
def test_empty_pattern_matches_all_properties(self):
# An empty-string pattern is a valid regex that matches every property,
# so patternProperties covers everything and nothing is additional.
schema = {"patternProperties": {"": {"type": "integer"}}}
instance = {"foo": 1, "bar": 2}
self.assertEqual(
list(find_additional_properties(instance, schema)), [],
)

def test_no_pattern_properties_leaves_all_additional(self):
schema = {"properties": {"foo": {}}}
instance = {"foo": 1, "bar": 2}
self.assertEqual(
list(find_additional_properties(instance, schema)), ["bar"],
)
Loading