Skip to content

Commit 6615916

Browse files
committed
Fix additionalProperties with patternProperties present.
Closes #24.
1 parent 69dc5c1 commit 6615916

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

jsonschema.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,7 @@ def validate_additionalProperties(self, aP, instance, schema):
391391
if not self.is_type(instance, "object"):
392392
return
393393

394-
# no viewkeys in <2.7, and pypy seems to fail on vk - vk anyhow, so...
395-
extras = set(instance) - set(schema.get("properties", {}))
394+
extras = set(_find_additional_properties(instance, schema))
396395

397396
if self.is_type(aP, "object"):
398397
for extra in extras:
@@ -596,6 +595,26 @@ def __repr__(self):
596595
return "<%s (%s errors)>" % (self.__class__.__name__, len(self))
597596

598597

598+
def _find_additional_properties(instance, schema):
599+
"""
600+
Return the set of additional properties for the given ``instance``.
601+
602+
Weeds out properties that should have been validated by ``properties`` and
603+
/ or ``patternProperties``.
604+
605+
Assumes ``instance`` is dict-like already.
606+
607+
"""
608+
609+
properties = schema.get("properties", {})
610+
patterns = "|".join(schema.get("patternProperties", {}))
611+
for property in instance:
612+
if property not in properties:
613+
if patterns and re.search(patterns, property):
614+
continue
615+
yield property
616+
617+
599618
def _extras_msg(extras):
600619
"""
601620
Create an error message for extra items or properties.

tests.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,26 @@ def additionalProperties(self, aP):
282282
with self.assertRaises(ValidationError):
283283
validate({"foo" : 1, "bar" : "baz", "quux" : "boom"}, schema)
284284

285+
# A horrible name and horrible test. I will repent.
286+
# See https://groups.google.com/d/msg/json-schema/Q5F30CZtMb4/yk_niLnsdQ0J
287+
p_pP_aP = parametrized(
288+
("property_validates_property", "valid", {"foo" : [1, 2]}),
289+
("property_invalidates_property", "invalid", {"foo" : [1, 2, 3, 4]}),
290+
("patternProperty_invalidates_property", "invalid", {"foo" : []}),
291+
("patternProperty_validates_nonproperty", "valid", {"fxo" : [1, 2]}),
292+
("patternProperty_invalidates_nonproperty", "invalid", {"fxo" : []}),
293+
("additionalProperty_ignores_property", "valid", {"bar" : []}),
294+
("additionalProperty_validates_others", "valid", {"quux" : 3}),
295+
("additionalProperty_invalidates_others", "invalid", {"quux" : "foo"}),
296+
)(validation_test(
297+
properties={
298+
"foo" : {"type" : "array", "maxItems" : 3},
299+
"bar" : {"type" : "array"}
300+
},
301+
patternProperties={"f.o" : {"minItems" : 2}},
302+
additionalProperties={"type" : "integer"},
303+
))
304+
285305
items = parametrized(
286306
("", "valid", [1, 2, 3]),
287307
("wrong_type", "invalid", [1, "x"]),

0 commit comments

Comments
 (0)