Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jsonschema/_keywords.py: 23%
248 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:30 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:30 +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(extras))
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 if items is False and total > prefix:
67 message = f"Expected at most {prefix} items, but found {total}"
68 yield ValidationError(message)
69 else:
70 for index in range(prefix, total):
71 yield from validator.descend(
72 instance=instance[index],
73 schema=items,
74 path=index,
75 )
78def additionalItems(validator, aI, instance, schema):
79 if (
80 not validator.is_type(instance, "array")
81 or validator.is_type(schema.get("items", {}), "object")
82 ):
83 return
85 len_items = len(schema.get("items", []))
86 if validator.is_type(aI, "object"):
87 for index, item in enumerate(instance[len_items:], start=len_items):
88 yield from validator.descend(item, aI, path=index)
89 elif not aI and len(instance) > len(schema.get("items", [])):
90 error = "Additional items are not allowed (%s %s unexpected)"
91 yield ValidationError(
92 error % extras_msg(instance[len(schema.get("items", [])):]),
93 )
96def const(validator, const, instance, schema):
97 if not equal(instance, const):
98 yield ValidationError(f"{const!r} was expected")
101def contains(validator, contains, instance, schema):
102 if not validator.is_type(instance, "array"):
103 return
105 matches = 0
106 min_contains = schema.get("minContains", 1)
107 max_contains = schema.get("maxContains", len(instance))
109 for each in instance:
110 if validator.evolve(schema=contains).is_valid(each):
111 matches += 1
112 if matches > max_contains:
113 yield ValidationError(
114 "Too many items match the given schema "
115 f"(expected at most {max_contains})",
116 validator="maxContains",
117 validator_value=max_contains,
118 )
119 return
121 if matches < min_contains:
122 if not matches:
123 yield ValidationError(
124 f"{instance!r} does not contain items "
125 "matching the given schema",
126 )
127 else:
128 yield ValidationError(
129 "Too few items match the given schema (expected at least "
130 f"{min_contains} but only {matches} matched)",
131 validator="minContains",
132 validator_value=min_contains,
133 )
136def exclusiveMinimum(validator, minimum, instance, schema):
137 if not validator.is_type(instance, "number"):
138 return
140 if instance <= minimum:
141 yield ValidationError(
142 f"{instance!r} is less than or equal to "
143 f"the minimum of {minimum!r}",
144 )
147def exclusiveMaximum(validator, maximum, instance, schema):
148 if not validator.is_type(instance, "number"):
149 return
151 if instance >= maximum:
152 yield ValidationError(
153 f"{instance!r} is greater than or equal "
154 f"to the maximum of {maximum!r}",
155 )
158def minimum(validator, minimum, instance, schema):
159 if not validator.is_type(instance, "number"):
160 return
162 if instance < minimum:
163 message = f"{instance!r} is less than the minimum of {minimum!r}"
164 yield ValidationError(message)
167def maximum(validator, maximum, instance, schema):
168 if not validator.is_type(instance, "number"):
169 return
171 if instance > maximum:
172 message = f"{instance!r} is greater than the maximum of {maximum!r}"
173 yield ValidationError(message)
176def multipleOf(validator, dB, instance, schema):
177 if not validator.is_type(instance, "number"):
178 return
180 if isinstance(dB, float):
181 quotient = instance / dB
182 try:
183 failed = int(quotient) != quotient
184 except OverflowError:
185 # When `instance` is large and `dB` is less than one,
186 # quotient can overflow to infinity; and then casting to int
187 # raises an error.
188 #
189 # In this case we fall back to Fraction logic, which is
190 # exact and cannot overflow. The performance is also
191 # acceptable: we try the fast all-float option first, and
192 # we know that fraction(dB) can have at most a few hundred
193 # digits in each part. The worst-case slowdown is therefore
194 # for already-slow enormous integers or Decimals.
195 failed = (Fraction(instance) / Fraction(dB)).denominator != 1
196 else:
197 failed = instance % dB
199 if failed:
200 yield ValidationError(f"{instance!r} is not a multiple of {dB}")
203def minItems(validator, mI, instance, schema):
204 if validator.is_type(instance, "array") and len(instance) < mI:
205 yield ValidationError(f"{instance!r} is too short")
208def maxItems(validator, mI, instance, schema):
209 if validator.is_type(instance, "array") and len(instance) > mI:
210 yield ValidationError(f"{instance!r} is too long")
213def uniqueItems(validator, uI, instance, schema):
214 if (
215 uI
216 and validator.is_type(instance, "array")
217 and not uniq(instance)
218 ):
219 yield ValidationError(f"{instance!r} has non-unique elements")
222def pattern(validator, patrn, instance, schema):
223 if (
224 validator.is_type(instance, "string")
225 and not re.search(patrn, instance)
226 ):
227 yield ValidationError(f"{instance!r} does not match {patrn!r}")
230def format(validator, format, instance, schema):
231 if validator.format_checker is not None:
232 try:
233 validator.format_checker.check(instance, format)
234 except FormatError as error:
235 yield ValidationError(error.message, cause=error.cause)
238def minLength(validator, mL, instance, schema):
239 if validator.is_type(instance, "string") and len(instance) < mL:
240 yield ValidationError(f"{instance!r} is too short")
243def maxLength(validator, mL, instance, schema):
244 if validator.is_type(instance, "string") and len(instance) > mL:
245 yield ValidationError(f"{instance!r} is too long")
248def dependentRequired(validator, dependentRequired, instance, schema):
249 if not validator.is_type(instance, "object"):
250 return
252 for property, dependency in dependentRequired.items():
253 if property not in instance:
254 continue
256 for each in dependency:
257 if each not in instance:
258 message = f"{each!r} is a dependency of {property!r}"
259 yield ValidationError(message)
262def dependentSchemas(validator, dependentSchemas, instance, schema):
263 if not validator.is_type(instance, "object"):
264 return
266 for property, dependency in dependentSchemas.items():
267 if property not in instance:
268 continue
269 yield from validator.descend(
270 instance, dependency, schema_path=property,
271 )
274def enum(validator, enums, instance, schema):
275 if instance == 0 or instance == 1:
276 unbooled = unbool(instance)
277 if all(unbooled != unbool(each) for each in enums):
278 yield ValidationError(f"{instance!r} is not one of {enums!r}")
279 elif instance not in enums:
280 yield ValidationError(f"{instance!r} is not one of {enums!r}")
283def ref(validator, ref, instance, schema):
284 yield from validator._validate_reference(ref=ref, instance=instance)
287def dynamicRef(validator, dynamicRef, instance, schema):
288 yield from validator._validate_reference(ref=dynamicRef, instance=instance)
291def type(validator, types, instance, schema):
292 types = ensure_list(types)
294 if not any(validator.is_type(instance, type) for type in types):
295 reprs = ", ".join(repr(type) for type in types)
296 yield ValidationError(f"{instance!r} is not of type {reprs}")
299def properties(validator, properties, instance, schema):
300 if not validator.is_type(instance, "object"):
301 return
303 for property, subschema in properties.items():
304 if property in instance:
305 yield from validator.descend(
306 instance[property],
307 subschema,
308 path=property,
309 schema_path=property,
310 )
313def required(validator, required, instance, schema):
314 if not validator.is_type(instance, "object"):
315 return
316 for property in required:
317 if property not in instance:
318 yield ValidationError(f"{property!r} is a required property")
321def minProperties(validator, mP, instance, schema):
322 if validator.is_type(instance, "object") and len(instance) < mP:
323 yield ValidationError(f"{instance!r} does not have enough properties")
326def maxProperties(validator, mP, instance, schema):
327 if not validator.is_type(instance, "object"):
328 return
329 if validator.is_type(instance, "object") and len(instance) > mP:
330 yield ValidationError(f"{instance!r} has too many properties")
333def allOf(validator, allOf, instance, schema):
334 for index, subschema in enumerate(allOf):
335 yield from validator.descend(instance, subschema, schema_path=index)
338def anyOf(validator, anyOf, instance, schema):
339 all_errors = []
340 for index, subschema in enumerate(anyOf):
341 errs = list(validator.descend(instance, subschema, schema_path=index))
342 if not errs:
343 break
344 all_errors.extend(errs)
345 else:
346 yield ValidationError(
347 f"{instance!r} is not valid under any of the given schemas",
348 context=all_errors,
349 )
352def oneOf(validator, oneOf, instance, schema):
353 subschemas = enumerate(oneOf)
354 all_errors = []
355 for index, subschema in subschemas:
356 errs = list(validator.descend(instance, subschema, schema_path=index))
357 if not errs:
358 first_valid = subschema
359 break
360 all_errors.extend(errs)
361 else:
362 yield ValidationError(
363 f"{instance!r} is not valid under any of the given schemas",
364 context=all_errors,
365 )
367 more_valid = [
368 each for _, each in subschemas
369 if validator.evolve(schema=each).is_valid(instance)
370 ]
371 if more_valid:
372 more_valid.append(first_valid)
373 reprs = ", ".join(repr(schema) for schema in more_valid)
374 yield ValidationError(f"{instance!r} is valid under each of {reprs}")
377def not_(validator, not_schema, instance, schema):
378 if validator.evolve(schema=not_schema).is_valid(instance):
379 message = f"{instance!r} should not be valid under {not_schema!r}"
380 yield ValidationError(message)
383def if_(validator, if_schema, instance, schema):
384 if validator.evolve(schema=if_schema).is_valid(instance):
385 if "then" in schema:
386 then = schema["then"]
387 yield from validator.descend(instance, then, schema_path="then")
388 elif "else" in schema:
389 else_ = schema["else"]
390 yield from validator.descend(instance, else_, schema_path="else")
393def unevaluatedItems(validator, unevaluatedItems, instance, schema):
394 if not validator.is_type(instance, "array"):
395 return
396 evaluated_item_indexes = find_evaluated_item_indexes_by_schema(
397 validator, instance, schema,
398 )
399 unevaluated_items = [
400 item for index, item in enumerate(instance)
401 if index not in evaluated_item_indexes
402 ]
403 if unevaluated_items:
404 error = "Unevaluated items are not allowed (%s %s unexpected)"
405 yield ValidationError(error % extras_msg(unevaluated_items))
408def unevaluatedProperties(validator, unevaluatedProperties, instance, schema):
409 if not validator.is_type(instance, "object"):
410 return
411 evaluated_keys = find_evaluated_property_keys_by_schema(
412 validator, instance, schema,
413 )
414 unevaluated_keys = []
415 for property in instance:
416 if property not in evaluated_keys:
417 for _ in validator.descend(
418 instance[property],
419 unevaluatedProperties,
420 path=property,
421 schema_path=property,
422 ):
423 # FIXME: Include context for each unevaluated property
424 # indicating why it's invalid under the subschema.
425 unevaluated_keys.append(property)
427 if unevaluated_keys:
428 if unevaluatedProperties is False:
429 error = "Unevaluated properties are not allowed (%s %s unexpected)"
430 yield ValidationError(error % extras_msg(unevaluated_keys))
431 else:
432 error = (
433 "Unevaluated properties are not valid under "
434 "the given schema (%s %s unevaluated and invalid)"
435 )
436 yield ValidationError(error % extras_msg(unevaluated_keys))
439def prefixItems(validator, prefixItems, instance, schema):
440 if not validator.is_type(instance, "array"):
441 return
443 for (index, item), subschema in zip(enumerate(instance), prefixItems):
444 yield from validator.descend(
445 instance=item,
446 schema=subschema,
447 schema_path=index,
448 path=index,
449 )