Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jsonschema/_keywords.py: 16%
243 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:51 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:51 +0000
1from fractions import Fraction
2import re
4from jsonschema._utils import (
5 ensure_list,
6 equal,
7 extras_msg,
8 find_additional_properties,
9 find_evaluated_item_indexes_by_schema,
10 find_evaluated_property_keys_by_schema,
11 unbool,
12 uniq,
13)
14from jsonschema.exceptions import FormatError, ValidationError
17def patternProperties(validator, patternProperties, instance, schema):
18 if not validator.is_type(instance, "object"):
19 return
21 for pattern, subschema in patternProperties.items():
22 for k, v in instance.items():
23 if re.search(pattern, k):
24 yield from validator.descend(
25 v, subschema, path=k, schema_path=pattern,
26 )
29def propertyNames(validator, propertyNames, instance, schema):
30 if not validator.is_type(instance, "object"):
31 return
33 for property in instance:
34 yield from validator.descend(instance=property, schema=propertyNames)
37def additionalProperties(validator, aP, instance, schema):
38 if not validator.is_type(instance, "object"):
39 return
41 extras = set(find_additional_properties(instance, schema))
43 if validator.is_type(aP, "object"):
44 for extra in extras:
45 yield from validator.descend(instance[extra], aP, path=extra)
46 elif not aP and extras:
47 if "patternProperties" in schema:
48 verb = "does" if len(extras) == 1 else "do"
49 joined = ", ".join(repr(each) for each in sorted(extras))
50 patterns = ", ".join(
51 repr(each) for each in sorted(schema["patternProperties"])
52 )
53 error = f"{joined} {verb} not match any of the regexes: {patterns}"
54 yield ValidationError(error)
55 else:
56 error = "Additional properties are not allowed (%s %s unexpected)"
57 yield ValidationError(error % extras_msg(sorted(extras, key=str)))
60def items(validator, items, instance, schema):
61 if not validator.is_type(instance, "array"):
62 return
64 prefix = len(schema.get("prefixItems", []))
65 total = len(instance)
66 extra = total - prefix
67 if extra <= 0:
68 return
70 if items is False:
71 rest = instance[prefix:] if extra != 1 else instance[prefix]
72 item = "items" if prefix != 1 else "item"
73 yield ValidationError(
74 f"Expected at most {prefix} {item} but found {extra} "
75 f"extra: {rest!r}",
76 )
77 else:
78 for index in range(prefix, total):
79 yield from validator.descend(
80 instance=instance[index],
81 schema=items,
82 path=index,
83 )
86def const(validator, const, instance, schema):
87 if not equal(instance, const):
88 yield ValidationError(f"{const!r} was expected")
91def contains(validator, contains, instance, schema):
92 if not validator.is_type(instance, "array"):
93 return
95 matches = 0
96 min_contains = schema.get("minContains", 1)
97 max_contains = schema.get("maxContains", len(instance))
99 for each in instance:
100 if validator.evolve(schema=contains).is_valid(each):
101 matches += 1
102 if matches > max_contains:
103 yield ValidationError(
104 "Too many items match the given schema "
105 f"(expected at most {max_contains})",
106 validator="maxContains",
107 validator_value=max_contains,
108 )
109 return
111 if matches < min_contains:
112 if not matches:
113 yield ValidationError(
114 f"{instance!r} does not contain items "
115 "matching the given schema",
116 )
117 else:
118 yield ValidationError(
119 "Too few items match the given schema (expected at least "
120 f"{min_contains} but only {matches} matched)",
121 validator="minContains",
122 validator_value=min_contains,
123 )
126def exclusiveMinimum(validator, minimum, instance, schema):
127 if not validator.is_type(instance, "number"):
128 return
130 if instance <= minimum:
131 yield ValidationError(
132 f"{instance!r} is less than or equal to "
133 f"the minimum of {minimum!r}",
134 )
137def exclusiveMaximum(validator, maximum, instance, schema):
138 if not validator.is_type(instance, "number"):
139 return
141 if instance >= maximum:
142 yield ValidationError(
143 f"{instance!r} is greater than or equal "
144 f"to the maximum of {maximum!r}",
145 )
148def minimum(validator, minimum, instance, schema):
149 if not validator.is_type(instance, "number"):
150 return
152 if instance < minimum:
153 message = f"{instance!r} is less than the minimum of {minimum!r}"
154 yield ValidationError(message)
157def maximum(validator, maximum, instance, schema):
158 if not validator.is_type(instance, "number"):
159 return
161 if instance > maximum:
162 message = f"{instance!r} is greater than the maximum of {maximum!r}"
163 yield ValidationError(message)
166def multipleOf(validator, dB, instance, schema):
167 if not validator.is_type(instance, "number"):
168 return
170 if isinstance(dB, float):
171 quotient = instance / dB
172 try:
173 failed = int(quotient) != quotient
174 except OverflowError:
175 # When `instance` is large and `dB` is less than one,
176 # quotient can overflow to infinity; and then casting to int
177 # raises an error.
178 #
179 # In this case we fall back to Fraction logic, which is
180 # exact and cannot overflow. The performance is also
181 # acceptable: we try the fast all-float option first, and
182 # we know that fraction(dB) can have at most a few hundred
183 # digits in each part. The worst-case slowdown is therefore
184 # for already-slow enormous integers or Decimals.
185 failed = (Fraction(instance) / Fraction(dB)).denominator != 1
186 else:
187 failed = instance % dB
189 if failed:
190 yield ValidationError(f"{instance!r} is not a multiple of {dB}")
193def minItems(validator, mI, instance, schema):
194 if validator.is_type(instance, "array") and len(instance) < mI:
195 yield ValidationError(f"{instance!r} is too short")
198def maxItems(validator, mI, instance, schema):
199 if validator.is_type(instance, "array") and len(instance) > mI:
200 yield ValidationError(f"{instance!r} is too long")
203def uniqueItems(validator, uI, instance, schema):
204 if (
205 uI
206 and validator.is_type(instance, "array")
207 and not uniq(instance)
208 ):
209 yield ValidationError(f"{instance!r} has non-unique elements")
212def pattern(validator, patrn, instance, schema):
213 if (
214 validator.is_type(instance, "string")
215 and not re.search(patrn, instance)
216 ):
217 yield ValidationError(f"{instance!r} does not match {patrn!r}")
220def format(validator, format, instance, schema):
221 if validator.format_checker is not None:
222 try:
223 validator.format_checker.check(instance, format)
224 except FormatError as error:
225 yield ValidationError(error.message, cause=error.cause)
228def minLength(validator, mL, instance, schema):
229 if validator.is_type(instance, "string") and len(instance) < mL:
230 yield ValidationError(f"{instance!r} is too short")
233def maxLength(validator, mL, instance, schema):
234 if validator.is_type(instance, "string") and len(instance) > mL:
235 yield ValidationError(f"{instance!r} is too long")
238def dependentRequired(validator, dependentRequired, instance, schema):
239 if not validator.is_type(instance, "object"):
240 return
242 for property, dependency in dependentRequired.items():
243 if property not in instance:
244 continue
246 for each in dependency:
247 if each not in instance:
248 message = f"{each!r} is a dependency of {property!r}"
249 yield ValidationError(message)
252def dependentSchemas(validator, dependentSchemas, instance, schema):
253 if not validator.is_type(instance, "object"):
254 return
256 for property, dependency in dependentSchemas.items():
257 if property not in instance:
258 continue
259 yield from validator.descend(
260 instance, dependency, schema_path=property,
261 )
264def enum(validator, enums, instance, schema):
265 if instance == 0 or instance == 1:
266 unbooled = unbool(instance)
267 if all(unbooled != unbool(each) for each in enums):
268 yield ValidationError(f"{instance!r} is not one of {enums!r}")
269 elif instance not in enums:
270 yield ValidationError(f"{instance!r} is not one of {enums!r}")
273def ref(validator, ref, instance, schema):
274 yield from validator._validate_reference(ref=ref, instance=instance)
277def dynamicRef(validator, dynamicRef, instance, schema):
278 yield from validator._validate_reference(ref=dynamicRef, instance=instance)
281def type(validator, types, instance, schema):
282 types = ensure_list(types)
284 if not any(validator.is_type(instance, type) for type in types):
285 reprs = ", ".join(repr(type) for type in types)
286 yield ValidationError(f"{instance!r} is not of type {reprs}")
289def properties(validator, properties, instance, schema):
290 if not validator.is_type(instance, "object"):
291 return
293 for property, subschema in properties.items():
294 if property in instance:
295 yield from validator.descend(
296 instance[property],
297 subschema,
298 path=property,
299 schema_path=property,
300 )
303def required(validator, required, instance, schema):
304 if not validator.is_type(instance, "object"):
305 return
306 for property in required:
307 if property not in instance:
308 yield ValidationError(f"{property!r} is a required property")
311def minProperties(validator, mP, instance, schema):
312 if validator.is_type(instance, "object") and len(instance) < mP:
313 yield ValidationError(f"{instance!r} does not have enough properties")
316def maxProperties(validator, mP, instance, schema):
317 if not validator.is_type(instance, "object"):
318 return
319 if validator.is_type(instance, "object") and len(instance) > mP:
320 yield ValidationError(f"{instance!r} has too many properties")
323def allOf(validator, allOf, instance, schema):
324 for index, subschema in enumerate(allOf):
325 yield from validator.descend(instance, subschema, schema_path=index)
328def anyOf(validator, anyOf, instance, schema):
329 all_errors = []
330 for index, subschema in enumerate(anyOf):
331 errs = list(validator.descend(instance, subschema, schema_path=index))
332 if not errs:
333 break
334 all_errors.extend(errs)
335 else:
336 yield ValidationError(
337 f"{instance!r} is not valid under any of the given schemas",
338 context=all_errors,
339 )
342def oneOf(validator, oneOf, instance, schema):
343 subschemas = enumerate(oneOf)
344 all_errors = []
345 for index, subschema in subschemas:
346 errs = list(validator.descend(instance, subschema, schema_path=index))
347 if not errs:
348 first_valid = subschema
349 break
350 all_errors.extend(errs)
351 else:
352 yield ValidationError(
353 f"{instance!r} is not valid under any of the given schemas",
354 context=all_errors,
355 )
357 more_valid = [
358 each for _, each in subschemas
359 if validator.evolve(schema=each).is_valid(instance)
360 ]
361 if more_valid:
362 more_valid.append(first_valid)
363 reprs = ", ".join(repr(schema) for schema in more_valid)
364 yield ValidationError(f"{instance!r} is valid under each of {reprs}")
367def not_(validator, not_schema, instance, schema):
368 if validator.evolve(schema=not_schema).is_valid(instance):
369 message = f"{instance!r} should not be valid under {not_schema!r}"
370 yield ValidationError(message)
373def if_(validator, if_schema, instance, schema):
374 if validator.evolve(schema=if_schema).is_valid(instance):
375 if "then" in schema:
376 then = schema["then"]
377 yield from validator.descend(instance, then, schema_path="then")
378 elif "else" in schema:
379 else_ = schema["else"]
380 yield from validator.descend(instance, else_, schema_path="else")
383def unevaluatedItems(validator, unevaluatedItems, instance, schema):
384 if not validator.is_type(instance, "array"):
385 return
386 evaluated_item_indexes = find_evaluated_item_indexes_by_schema(
387 validator, instance, schema,
388 )
389 unevaluated_items = [
390 item for index, item in enumerate(instance)
391 if index not in evaluated_item_indexes
392 ]
393 if unevaluated_items:
394 error = "Unevaluated items are not allowed (%s %s unexpected)"
395 yield ValidationError(error % extras_msg(unevaluated_items))
398def unevaluatedProperties(validator, unevaluatedProperties, instance, schema):
399 if not validator.is_type(instance, "object"):
400 return
401 evaluated_keys = find_evaluated_property_keys_by_schema(
402 validator, instance, schema,
403 )
404 unevaluated_keys = []
405 for property in instance:
406 if property not in evaluated_keys:
407 for _ in validator.descend(
408 instance[property],
409 unevaluatedProperties,
410 path=property,
411 schema_path=property,
412 ):
413 # FIXME: Include context for each unevaluated property
414 # indicating why it's invalid under the subschema.
415 unevaluated_keys.append(property)
417 if unevaluated_keys:
418 if unevaluatedProperties is False:
419 error = "Unevaluated properties are not allowed (%s %s unexpected)"
420 extras = sorted(unevaluated_keys, key=str)
421 yield ValidationError(error % extras_msg(extras))
422 else:
423 error = (
424 "Unevaluated properties are not valid under "
425 "the given schema (%s %s unevaluated and invalid)"
426 )
427 yield ValidationError(error % extras_msg(unevaluated_keys))
430def prefixItems(validator, prefixItems, instance, schema):
431 if not validator.is_type(instance, "array"):
432 return
434 for (index, item), subschema in zip(enumerate(instance), prefixItems):
435 yield from validator.descend(
436 instance=item,
437 schema=subschema,
438 schema_path=index,
439 path=index,
440 )