Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jsonschema/_types.py: 64%
59 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 __future__ import annotations
3from typing import Any, Callable, Mapping
4import numbers
6from attrs import evolve, field, frozen
7from rpds import HashTrieMap
9from jsonschema.exceptions import UndefinedTypeCheck
12# unfortunately, the type of HashTrieMap is generic, and if used as an attrs
13# converter, the generic type is presented to mypy, which then fails to match
14# the concrete type of a type checker mapping
15# this "do nothing" wrapper presents the correct information to mypy
16def _typed_map_converter(
17 init_val: Mapping[str, Callable[[TypeChecker, Any], bool]],
18) -> HashTrieMap[str, Callable[[TypeChecker, Any], bool]]:
19 return HashTrieMap.convert(init_val)
22def is_array(checker, instance):
23 return isinstance(instance, list)
26def is_bool(checker, instance):
27 return isinstance(instance, bool)
30def is_integer(checker, instance):
31 # bool inherits from int, so ensure bools aren't reported as ints
32 if isinstance(instance, bool):
33 return False
34 return isinstance(instance, int)
37def is_null(checker, instance):
38 return instance is None
41def is_number(checker, instance):
42 # bool inherits from int, so ensure bools aren't reported as ints
43 if isinstance(instance, bool):
44 return False
45 return isinstance(instance, numbers.Number)
48def is_object(checker, instance):
49 return isinstance(instance, dict)
52def is_string(checker, instance):
53 return isinstance(instance, str)
56def is_any(checker, instance):
57 return True
60@frozen(repr=False)
61class TypeChecker:
62 """
63 A :kw:`type` property checker.
65 A `TypeChecker` performs type checking for a `Validator`, converting
66 between the defined JSON Schema types and some associated Python types or
67 objects.
69 Modifying the behavior just mentioned by redefining which Python objects
70 are considered to be of which JSON Schema types can be done using
71 `TypeChecker.redefine` or `TypeChecker.redefine_many`, and types can be
72 removed via `TypeChecker.remove`. Each of these return a new `TypeChecker`.
74 Arguments:
76 type_checkers:
78 The initial mapping of types to their checking functions.
79 """
81 _type_checkers: HashTrieMap[
82 str, Callable[[TypeChecker, Any], bool],
83 ] = field(default=HashTrieMap(), converter=_typed_map_converter)
85 def __repr__(self):
86 types = ", ".join(repr(k) for k in sorted(self._type_checkers))
87 return f"<{self.__class__.__name__} types={{{types}}}>"
89 def is_type(self, instance, type: str) -> bool:
90 """
91 Check if the instance is of the appropriate type.
93 Arguments:
95 instance:
97 The instance to check
99 type:
101 The name of the type that is expected.
103 Raises:
105 `jsonschema.exceptions.UndefinedTypeCheck`:
107 if ``type`` is unknown to this object.
108 """
109 try:
110 fn = self._type_checkers[type]
111 except KeyError:
112 raise UndefinedTypeCheck(type) from None
114 return fn(self, instance)
116 def redefine(self, type: str, fn) -> TypeChecker:
117 """
118 Produce a new checker with the given type redefined.
120 Arguments:
122 type:
124 The name of the type to check.
126 fn (collections.abc.Callable):
128 A callable taking exactly two parameters - the type
129 checker calling the function and the instance to check.
130 The function should return true if instance is of this
131 type and false otherwise.
132 """
133 return self.redefine_many({type: fn})
135 def redefine_many(self, definitions=()) -> TypeChecker:
136 """
137 Produce a new checker with the given types redefined.
139 Arguments:
141 definitions (dict):
143 A dictionary mapping types to their checking functions.
144 """
145 type_checkers = self._type_checkers.update(definitions)
146 return evolve(self, type_checkers=type_checkers)
148 def remove(self, *types) -> TypeChecker:
149 """
150 Produce a new checker with the given types forgotten.
152 Arguments:
154 types:
156 the names of the types to remove.
158 Raises:
160 `jsonschema.exceptions.UndefinedTypeCheck`:
162 if any given type is unknown to this object
163 """
164 type_checkers = self._type_checkers
165 for each in types:
166 try:
167 type_checkers = type_checkers.remove(each)
168 except KeyError:
169 raise UndefinedTypeCheck(each)
170 return evolve(self, type_checkers=type_checkers)
173draft3_type_checker = TypeChecker(
174 {
175 "any": is_any,
176 "array": is_array,
177 "boolean": is_bool,
178 "integer": is_integer,
179 "object": is_object,
180 "null": is_null,
181 "number": is_number,
182 "string": is_string,
183 },
184)
185draft4_type_checker = draft3_type_checker.remove("any")
186draft6_type_checker = draft4_type_checker.redefine(
187 "integer",
188 lambda checker, instance: (
189 is_integer(checker, instance)
190 or isinstance(instance, float) and instance.is_integer()
191 ),
192)
193draft7_type_checker = draft6_type_checker
194draft201909_type_checker = draft7_type_checker
195draft202012_type_checker = draft201909_type_checker