summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Berman <Julian@GrayVines.com>2021-08-18 19:12:27 +0100
committerJulian Berman <Julian@GrayVines.com>2021-08-18 19:34:32 +0100
commitee775891043d428c084748dbf435b80401ab64ae (patch)
tree5514e38c9c201c742df76cf1fa0fde3c9b085754
parent00031cb043763842266877923552e40f0c8f36b5 (diff)
downloadjsonschema-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.py64
-rw-r--r--jsonschema/tests/test_validators.py12
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):