Skip to content

Commit ebebf52

Browse files
committed
Properly set the failing validator for min/maxContains.
Also check that only one error is raised for maxContains, which is the case right now due to short circuiting as soon as we see too many matches.
1 parent 3992d99 commit ebebf52

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

jsonschema/_validators.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ def contains(validator, contains, instance, schema):
118118
yield ValidationError(
119119
"Too many items match the given schema "
120120
f"(expected at most {max_contains})",
121+
validator="maxContains",
122+
validator_value=max_contains,
121123
)
122124
return
123125

@@ -131,6 +133,8 @@ def contains(validator, contains, instance, schema):
131133
yield ValidationError(
132134
"Too few items match the given schema (expected at least "
133135
f"{min_contains} but only {matches} matched)",
136+
validator="minContains",
137+
validator_value=min_contains,
134138
)
135139

136140

jsonschema/tests/test_validators.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,94 @@ def test_prefixItems_with_items(self):
12211221
),
12221222
)
12231223

1224+
def test_contains_too_many(self):
1225+
"""
1226+
`contains` + `maxContains` produces only one error, even if there are
1227+
many more incorrectly matching elements.
1228+
"""
1229+
schema = {"contains": {"type": "string"}, "maxContains": 2}
1230+
validator = validators.Draft202012Validator(schema)
1231+
error, = validator.iter_errors(["foo", 2, "bar", 4, "baz", "quux"])
1232+
self.assertEqual(
1233+
(
1234+
error.message,
1235+
error.validator,
1236+
error.validator_value,
1237+
error.instance,
1238+
error.absolute_path,
1239+
error.schema,
1240+
error.schema_path,
1241+
error.json_path,
1242+
),
1243+
(
1244+
"Too many items match the given schema (expected at most 2)",
1245+
"maxContains",
1246+
2,
1247+
["foo", 2, "bar", 4, "baz", "quux"],
1248+
deque([]),
1249+
{"contains": {"type": "string"}, "maxContains": 2},
1250+
deque(["contains"]),
1251+
"$",
1252+
),
1253+
)
1254+
1255+
def test_contains_too_few(self):
1256+
schema = {"contains": {"type": "string"}, "minContains": 2}
1257+
validator = validators.Draft202012Validator(schema)
1258+
error, = validator.iter_errors(["foo", 2, 4])
1259+
self.assertEqual(
1260+
(
1261+
error.message,
1262+
error.validator,
1263+
error.validator_value,
1264+
error.instance,
1265+
error.absolute_path,
1266+
error.schema,
1267+
error.schema_path,
1268+
error.json_path,
1269+
),
1270+
(
1271+
(
1272+
"Too few items match the given schema "
1273+
"(expected at least 2 but only 1 matched)"
1274+
),
1275+
"minContains",
1276+
2,
1277+
["foo", 2, 4],
1278+
deque([]),
1279+
{"contains": {"type": "string"}, "minContains": 2},
1280+
deque(["contains"]),
1281+
"$",
1282+
),
1283+
)
1284+
1285+
def test_contains_none(self):
1286+
schema = {"contains": {"type": "string"}, "minContains": 2}
1287+
validator = validators.Draft202012Validator(schema)
1288+
error, = validator.iter_errors([2, 4])
1289+
self.assertEqual(
1290+
(
1291+
error.message,
1292+
error.validator,
1293+
error.validator_value,
1294+
error.instance,
1295+
error.absolute_path,
1296+
error.schema,
1297+
error.schema_path,
1298+
error.json_path,
1299+
),
1300+
(
1301+
"[2, 4] does not contain items matching the given schema",
1302+
"contains",
1303+
{"type": "string"},
1304+
[2, 4],
1305+
deque([]),
1306+
{"contains": {"type": "string"}, "minContains": 2},
1307+
deque(["contains"]),
1308+
"$",
1309+
),
1310+
)
1311+
12241312

12251313
class MetaSchemaTestsMixin(object):
12261314
# TODO: These all belong upstream

0 commit comments

Comments
 (0)