diff options
author | Julian Berman <Julian@GrayVines.com> | 2021-08-18 19:12:27 +0100 |
---|---|---|
committer | Julian Berman <Julian@GrayVines.com> | 2021-08-18 19:34:32 +0100 |
commit | ee775891043d428c084748dbf435b80401ab64ae (patch) | |
tree | 5514e38c9c201c742df76cf1fa0fde3c9b085754 | |
parent | 00031cb043763842266877923552e40f0c8f36b5 (diff) | |
download | jsonschema-ee775891043d428c084748dbf435b80401ab64ae.tar.gz |
Reimplement contains.
Fixes a bug where maxContains was being ignored if minContains was set to 0.
Also now short circuits as soon as more than maxContains is reached rather
than continuing to validate.
-rw-r--r-- | jsonschema/_validators.py | 64 | ||||
-rw-r--r-- | jsonschema/tests/test_validators.py | 12 |
2 files changed, 25 insertions, 51 deletions
diff --git a/jsonschema/_validators.py b/jsonschema/_validators.py index 2c0df8f..2784c09 100644 --- a/jsonschema/_validators.py +++ b/jsonschema/_validators.py @@ -119,55 +119,31 @@ def contains(validator, contains, instance, schema): if not validator.is_type(instance, "array"): return - min_contains = max_contains = None - - if "minContains" in schema: - min_contains = schema["minContains"] - - if "maxContains" in schema: - max_contains = schema["maxContains"] - - # minContains set to 0 will ignore contains - if min_contains == 0: - return - - matches = sum(1 for each in instance if validator.is_valid(each, contains)) - - if not matches: - yield ValidationError( - f"{instance!r} does not contain items matching the given schema", - ) - return - - if min_contains and max_contains is None: - if matches < min_contains: - yield ValidationError( - "Too few items match the given schema " - f"(expected {min_contains} but only {matches} matched)", - ) - return - - if min_contains is None and max_contains: - if matches > max_contains: + matches = 0 + min_contains = schema.get("minContains", 1) + max_contains = schema.get("maxContains", len(instance)) + + for each in instance: + if validator.is_valid(each, contains): + matches += 1 + if matches > max_contains: + yield ValidationError( + "Too many items match the given schema " + f"(expected at most {max_contains})", + ) + return + + if matches < min_contains: + if not matches: yield ValidationError( - "Too many items match the given schema " - f"(expected at most {max_contains} but {matches} matched)", + f"{instance!r} does not contain items " + "matching the given schema", ) - return - - if min_contains and max_contains: - if matches < min_contains: - only = "only " - elif matches > max_contains: - only = "" else: - only = None - if only is not None: yield ValidationError( - f"Expected between {min_contains} and {max_contains} items " - f"to match the given schema but {only}{matches} matched", + "Too few items match the given schema (expected at least " + f"{min_contains} but only {matches} matched)", ) - return def exclusiveMinimum(validator, minimum, instance, schema): diff --git a/jsonschema/tests/test_validators.py b/jsonschema/tests/test_validators.py index 449ba93..85f6b4f 100644 --- a/jsonschema/tests/test_validators.py +++ b/jsonschema/tests/test_validators.py @@ -464,7 +464,7 @@ class TestValidationErrorMessages(TestCase): self.assertEqual( message, "Too few items match the given schema " - "(expected 2 but only 1 matched)", + "(expected at least 2 but only 1 matched)", ) def test_contains_too_few_both_constrained(self): @@ -478,8 +478,8 @@ class TestValidationErrorMessages(TestCase): ) self.assertEqual( message, - "Expected between 2 and 4 items to match the given schema but " - "only 1 matched", + "Too few items match the given schema (expected at least 2 but " + "only 1 matched)", ) def test_contains_too_many(self): @@ -489,8 +489,7 @@ class TestValidationErrorMessages(TestCase): ) self.assertEqual( message, - "Too many items match the given schema " - "(expected at most 2 but 4 matched)", + "Too many items match the given schema (expected at most 2)", ) def test_contains_too_many_both_constrained(self): @@ -504,8 +503,7 @@ class TestValidationErrorMessages(TestCase): ) self.assertEqual( message, - "Expected between 2 and 4 items to match the given schema but " - "7 matched", + "Too many items match the given schema (expected at most 4)", ) def test_exclusiveMinimum(self): |