_validators.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. import re
  2. from jsonschema._utils import (
  3. ensure_list,
  4. equal,
  5. extras_msg,
  6. find_additional_properties,
  7. types_msg,
  8. unbool,
  9. uniq,
  10. )
  11. from jsonschema.exceptions import FormatError, ValidationError
  12. from jsonschema.compat import iteritems
  13. def patternProperties(validator, patternProperties, instance, schema):
  14. if not validator.is_type(instance, "object"):
  15. return
  16. for pattern, subschema in iteritems(patternProperties):
  17. for k, v in iteritems(instance):
  18. if re.search(pattern, k):
  19. for error in validator.descend(
  20. v, subschema, path=k, schema_path=pattern,
  21. ):
  22. yield error
  23. def propertyNames(validator, propertyNames, instance, schema):
  24. if not validator.is_type(instance, "object"):
  25. return
  26. for property in instance:
  27. for error in validator.descend(
  28. instance=property,
  29. schema=propertyNames,
  30. ):
  31. yield error
  32. def additionalProperties(validator, aP, instance, schema):
  33. if not validator.is_type(instance, "object"):
  34. return
  35. extras = set(find_additional_properties(instance, schema))
  36. if validator.is_type(aP, "object"):
  37. for extra in extras:
  38. for error in validator.descend(instance[extra], aP, path=extra):
  39. yield error
  40. elif not aP and extras:
  41. if "patternProperties" in schema:
  42. patterns = sorted(schema["patternProperties"])
  43. if len(extras) == 1:
  44. verb = "does"
  45. else:
  46. verb = "do"
  47. error = "%s %s not match any of the regexes: %s" % (
  48. ", ".join(map(repr, sorted(extras))),
  49. verb,
  50. ", ".join(map(repr, patterns)),
  51. )
  52. yield ValidationError(error)
  53. else:
  54. error = "Additional properties are not allowed (%s %s unexpected)"
  55. yield ValidationError(error % extras_msg(extras))
  56. def items(validator, items, instance, schema):
  57. if not validator.is_type(instance, "array"):
  58. return
  59. if validator.is_type(items, "array"):
  60. for (index, item), subschema in zip(enumerate(instance), items):
  61. for error in validator.descend(
  62. item, subschema, path=index, schema_path=index,
  63. ):
  64. yield error
  65. else:
  66. for index, item in enumerate(instance):
  67. for error in validator.descend(item, items, path=index):
  68. yield error
  69. def additionalItems(validator, aI, instance, schema):
  70. if (
  71. not validator.is_type(instance, "array") or
  72. validator.is_type(schema.get("items", {}), "object")
  73. ):
  74. return
  75. len_items = len(schema.get("items", []))
  76. if validator.is_type(aI, "object"):
  77. for index, item in enumerate(instance[len_items:], start=len_items):
  78. for error in validator.descend(item, aI, path=index):
  79. yield error
  80. elif not aI and len(instance) > len(schema.get("items", [])):
  81. error = "Additional items are not allowed (%s %s unexpected)"
  82. yield ValidationError(
  83. error %
  84. extras_msg(instance[len(schema.get("items", [])):])
  85. )
  86. def const(validator, const, instance, schema):
  87. if not equal(instance, const):
  88. yield ValidationError("%r was expected" % (const,))
  89. def contains(validator, contains, instance, schema):
  90. if not validator.is_type(instance, "array"):
  91. return
  92. if not any(validator.is_valid(element, contains) for element in instance):
  93. yield ValidationError(
  94. "None of %r are valid under the given schema" % (instance,)
  95. )
  96. def exclusiveMinimum(validator, minimum, instance, schema):
  97. if not validator.is_type(instance, "number"):
  98. return
  99. if instance <= minimum:
  100. yield ValidationError(
  101. "%r is less than or equal to the minimum of %r" % (
  102. instance, minimum,
  103. ),
  104. )
  105. def exclusiveMaximum(validator, maximum, instance, schema):
  106. if not validator.is_type(instance, "number"):
  107. return
  108. if instance >= maximum:
  109. yield ValidationError(
  110. "%r is greater than or equal to the maximum of %r" % (
  111. instance, maximum,
  112. ),
  113. )
  114. def minimum(validator, minimum, instance, schema):
  115. if not validator.is_type(instance, "number"):
  116. return
  117. if instance < minimum:
  118. yield ValidationError(
  119. "%r is less than the minimum of %r" % (instance, minimum)
  120. )
  121. def maximum(validator, maximum, instance, schema):
  122. if not validator.is_type(instance, "number"):
  123. return
  124. if instance > maximum:
  125. yield ValidationError(
  126. "%r is greater than the maximum of %r" % (instance, maximum)
  127. )
  128. def multipleOf(validator, dB, instance, schema):
  129. if not validator.is_type(instance, "number"):
  130. return
  131. if isinstance(dB, float):
  132. quotient = instance / dB
  133. failed = int(quotient) != quotient
  134. else:
  135. failed = instance % dB
  136. if failed:
  137. yield ValidationError("%r is not a multiple of %r" % (instance, dB))
  138. def minItems(validator, mI, instance, schema):
  139. if validator.is_type(instance, "array") and len(instance) < mI:
  140. yield ValidationError("%r is too short" % (instance,))
  141. def maxItems(validator, mI, instance, schema):
  142. if validator.is_type(instance, "array") and len(instance) > mI:
  143. yield ValidationError("%r is too long" % (instance,))
  144. def uniqueItems(validator, uI, instance, schema):
  145. if (
  146. uI and
  147. validator.is_type(instance, "array") and
  148. not uniq(instance)
  149. ):
  150. yield ValidationError("%r has non-unique elements" % (instance,))
  151. def pattern(validator, patrn, instance, schema):
  152. if (
  153. validator.is_type(instance, "string") and
  154. not re.search(patrn, instance)
  155. ):
  156. yield ValidationError("%r does not match %r" % (instance, patrn))
  157. def format(validator, format, instance, schema):
  158. if validator.format_checker is not None:
  159. try:
  160. validator.format_checker.check(instance, format)
  161. except FormatError as error:
  162. yield ValidationError(error.message, cause=error.cause)
  163. def minLength(validator, mL, instance, schema):
  164. if validator.is_type(instance, "string") and len(instance) < mL:
  165. yield ValidationError("%r is too short" % (instance,))
  166. def maxLength(validator, mL, instance, schema):
  167. if validator.is_type(instance, "string") and len(instance) > mL:
  168. yield ValidationError("%r is too long" % (instance,))
  169. def dependencies(validator, dependencies, instance, schema):
  170. if not validator.is_type(instance, "object"):
  171. return
  172. for property, dependency in iteritems(dependencies):
  173. if property not in instance:
  174. continue
  175. if validator.is_type(dependency, "array"):
  176. for each in dependency:
  177. if each not in instance:
  178. message = "%r is a dependency of %r"
  179. yield ValidationError(message % (each, property))
  180. else:
  181. for error in validator.descend(
  182. instance, dependency, schema_path=property,
  183. ):
  184. yield error
  185. def enum(validator, enums, instance, schema):
  186. if instance == 0 or instance == 1:
  187. unbooled = unbool(instance)
  188. if all(unbooled != unbool(each) for each in enums):
  189. yield ValidationError("%r is not one of %r" % (instance, enums))
  190. elif instance not in enums:
  191. yield ValidationError("%r is not one of %r" % (instance, enums))
  192. def ref(validator, ref, instance, schema):
  193. resolve = getattr(validator.resolver, "resolve", None)
  194. if resolve is None:
  195. with validator.resolver.resolving(ref) as resolved:
  196. for error in validator.descend(instance, resolved):
  197. yield error
  198. else:
  199. scope, resolved = validator.resolver.resolve(ref)
  200. validator.resolver.push_scope(scope)
  201. try:
  202. for error in validator.descend(instance, resolved):
  203. yield error
  204. finally:
  205. validator.resolver.pop_scope()
  206. def type(validator, types, instance, schema):
  207. types = ensure_list(types)
  208. if not any(validator.is_type(instance, type) for type in types):
  209. yield ValidationError(types_msg(instance, types))
  210. def properties(validator, properties, instance, schema):
  211. if not validator.is_type(instance, "object"):
  212. return
  213. for property, subschema in iteritems(properties):
  214. if property in instance:
  215. for error in validator.descend(
  216. instance[property],
  217. subschema,
  218. path=property,
  219. schema_path=property,
  220. ):
  221. yield error
  222. def required(validator, required, instance, schema):
  223. if not validator.is_type(instance, "object"):
  224. return
  225. for property in required:
  226. if property not in instance:
  227. yield ValidationError("%r is a required property" % property)
  228. def minProperties(validator, mP, instance, schema):
  229. if validator.is_type(instance, "object") and len(instance) < mP:
  230. yield ValidationError(
  231. "%r does not have enough properties" % (instance,)
  232. )
  233. def maxProperties(validator, mP, instance, schema):
  234. if not validator.is_type(instance, "object"):
  235. return
  236. if validator.is_type(instance, "object") and len(instance) > mP:
  237. yield ValidationError("%r has too many properties" % (instance,))
  238. def allOf(validator, allOf, instance, schema):
  239. for index, subschema in enumerate(allOf):
  240. for error in validator.descend(instance, subschema, schema_path=index):
  241. yield error
  242. def anyOf(validator, anyOf, instance, schema):
  243. all_errors = []
  244. for index, subschema in enumerate(anyOf):
  245. errs = list(validator.descend(instance, subschema, schema_path=index))
  246. if not errs:
  247. break
  248. all_errors.extend(errs)
  249. else:
  250. yield ValidationError(
  251. "%r is not valid under any of the given schemas" % (instance,),
  252. context=all_errors,
  253. )
  254. def oneOf(validator, oneOf, instance, schema):
  255. subschemas = enumerate(oneOf)
  256. all_errors = []
  257. for index, subschema in subschemas:
  258. errs = list(validator.descend(instance, subschema, schema_path=index))
  259. if not errs:
  260. first_valid = subschema
  261. break
  262. all_errors.extend(errs)
  263. else:
  264. yield ValidationError(
  265. "%r is not valid under any of the given schemas" % (instance,),
  266. context=all_errors,
  267. )
  268. more_valid = [s for i, s in subschemas if validator.is_valid(instance, s)]
  269. if more_valid:
  270. more_valid.append(first_valid)
  271. reprs = ", ".join(repr(schema) for schema in more_valid)
  272. yield ValidationError(
  273. "%r is valid under each of %s" % (instance, reprs)
  274. )
  275. def not_(validator, not_schema, instance, schema):
  276. if validator.is_valid(instance, not_schema):
  277. yield ValidationError(
  278. "%r is not allowed for %r" % (not_schema, instance)
  279. )
  280. def if_(validator, if_schema, instance, schema):
  281. if validator.is_valid(instance, if_schema):
  282. if u"then" in schema:
  283. then = schema[u"then"]
  284. for error in validator.descend(instance, then, schema_path="then"):
  285. yield error
  286. elif u"else" in schema:
  287. else_ = schema[u"else"]
  288. for error in validator.descend(instance, else_, schema_path="else"):
  289. yield error