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