Coverage for pydantic/types.py: 100.00%
597 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
1import abc 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
2import math 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
3import re 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
4import warnings 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
5from datetime import date 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
6from decimal import Decimal, InvalidOperation 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
7from enum import Enum 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
8from pathlib import Path 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
9from types import new_class 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
10from typing import ( 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
11 TYPE_CHECKING,
12 Any,
13 Callable,
14 ClassVar,
15 Dict,
16 FrozenSet,
17 List,
18 Optional,
19 Pattern,
20 Set,
21 Tuple,
22 Type,
23 TypeVar,
24 Union,
25 cast,
26 overload,
27)
28from uuid import UUID 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
29from weakref import WeakSet 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
31from pydantic import errors 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
32from pydantic.datetime_parse import parse_date 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
33from pydantic.utils import import_string, update_not_none 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
34from pydantic.validators import ( 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
35 bytes_validator,
36 constr_length_validator,
37 constr_lower,
38 constr_strip_whitespace,
39 constr_upper,
40 decimal_validator,
41 float_finite_validator,
42 float_validator,
43 frozenset_validator,
44 int_validator,
45 list_validator,
46 number_multiple_validator,
47 number_size_validator,
48 path_exists_validator,
49 path_validator,
50 set_validator,
51 str_validator,
52 strict_bytes_validator,
53 strict_float_validator,
54 strict_int_validator,
55 strict_str_validator,
56)
58__all__ = [ 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
59 'NoneStr',
60 'NoneBytes',
61 'StrBytes',
62 'NoneStrBytes',
63 'StrictStr',
64 'ConstrainedBytes',
65 'conbytes',
66 'ConstrainedList',
67 'conlist',
68 'ConstrainedSet',
69 'conset',
70 'ConstrainedFrozenSet',
71 'confrozenset',
72 'ConstrainedStr',
73 'constr',
74 'PyObject',
75 'ConstrainedInt',
76 'conint',
77 'PositiveInt',
78 'NegativeInt',
79 'NonNegativeInt',
80 'NonPositiveInt',
81 'ConstrainedFloat',
82 'confloat',
83 'PositiveFloat',
84 'NegativeFloat',
85 'NonNegativeFloat',
86 'NonPositiveFloat',
87 'FiniteFloat',
88 'ConstrainedDecimal',
89 'condecimal',
90 'UUID1',
91 'UUID3',
92 'UUID4',
93 'UUID5',
94 'FilePath',
95 'DirectoryPath',
96 'Json',
97 'JsonWrapper',
98 'SecretField',
99 'SecretStr',
100 'SecretBytes',
101 'StrictBool',
102 'StrictBytes',
103 'StrictInt',
104 'StrictFloat',
105 'PaymentCardNumber',
106 'ByteSize',
107 'PastDate',
108 'FutureDate',
109 'ConstrainedDate',
110 'condate',
111]
113NoneStr = Optional[str] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
114NoneBytes = Optional[bytes] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
115StrBytes = Union[str, bytes] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
116NoneStrBytes = Optional[StrBytes] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
117OptionalInt = Optional[int] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
118OptionalIntFloat = Union[OptionalInt, float] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
119OptionalIntFloatDecimal = Union[OptionalIntFloat, Decimal] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
120OptionalDate = Optional[date] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
121StrIntFloat = Union[str, int, float] 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
123if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
124 from typing_extensions import Annotated
126 from pydantic.dataclasses import Dataclass
127 from pydantic.main import BaseModel
128 from pydantic.typing import CallableGenerator
130 ModelOrDc = Type[Union[BaseModel, Dataclass]]
132T = TypeVar('T') 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
133_DEFINED_TYPES: 'WeakSet[type]' = WeakSet() 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
136@overload 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
137def _registered(typ: Type[T]) -> Type[T]: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
138 pass
141@overload 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
142def _registered(typ: 'ConstrainedNumberMeta') -> 'ConstrainedNumberMeta': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
143 pass
146def _registered(typ: Union[Type[T], 'ConstrainedNumberMeta']) -> Union[Type[T], 'ConstrainedNumberMeta']: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
147 # In order to generate valid examples of constrained types, Hypothesis needs
148 # to inspect the type object - so we keep a weakref to each contype object
149 # until it can be registered. When (or if) our Hypothesis plugin is loaded,
150 # it monkeypatches this function.
151 # If Hypothesis is never used, the total effect is to keep a weak reference
152 # which has minimal memory usage and doesn't even affect garbage collection.
153 _DEFINED_TYPES.add(typ) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
154 return typ 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
157class ConstrainedNumberMeta(type): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
158 def __new__(cls, name: str, bases: Any, dct: Dict[str, Any]) -> 'ConstrainedInt': # type: ignore 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
159 new_cls = cast('ConstrainedInt', type.__new__(cls, name, bases, dct)) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
161 if new_cls.gt is not None and new_cls.ge is not None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
162 raise errors.ConfigError('bounds gt and ge cannot be specified at the same time') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
163 if new_cls.lt is not None and new_cls.le is not None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
164 raise errors.ConfigError('bounds lt and le cannot be specified at the same time') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
166 return _registered(new_cls) # type: ignore 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
169# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
172 StrictBool = bool
173else:
175 class StrictBool(int): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
176 """
177 StrictBool to allow for bools which are not type-coerced.
178 """
180 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
181 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
182 field_schema.update(type='boolean') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
184 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
185 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
186 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
188 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
189 def validate(cls, value: Any) -> bool: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
190 """
191 Ensure that we only allow bools.
192 """
193 if isinstance(value, bool): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
194 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
196 raise errors.StrictBoolError() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
199# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
202class ConstrainedInt(int, metaclass=ConstrainedNumberMeta): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
203 strict: bool = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
204 gt: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
205 ge: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
206 lt: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
207 le: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
208 multiple_of: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
210 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
211 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
212 update_not_none( 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
213 field_schema,
214 exclusiveMinimum=cls.gt,
215 exclusiveMaximum=cls.lt,
216 minimum=cls.ge,
217 maximum=cls.le,
218 multipleOf=cls.multiple_of,
219 )
221 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
222 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
223 yield strict_int_validator if cls.strict else int_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
224 yield number_size_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
225 yield number_multiple_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
228def conint( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
229 *,
230 strict: bool = False,
231 gt: Optional[int] = None,
232 ge: Optional[int] = None,
233 lt: Optional[int] = None,
234 le: Optional[int] = None,
235 multiple_of: Optional[int] = None,
236) -> Type[int]:
237 # use kwargs then define conf in a dict to aid with IDE type hinting
238 namespace = dict(strict=strict, gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
239 return type('ConstrainedIntValue', (ConstrainedInt,), namespace) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
242if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
243 PositiveInt = int
244 NegativeInt = int
245 NonPositiveInt = int
246 NonNegativeInt = int
247 StrictInt = int
248else:
250 class PositiveInt(ConstrainedInt): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
251 gt = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
253 class NegativeInt(ConstrainedInt): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
254 lt = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
256 class NonPositiveInt(ConstrainedInt): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
257 le = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
259 class NonNegativeInt(ConstrainedInt): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
260 ge = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
262 class StrictInt(ConstrainedInt): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
263 strict = True 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
266# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
269class ConstrainedFloat(float, metaclass=ConstrainedNumberMeta): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
270 strict: bool = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
271 gt: OptionalIntFloat = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
272 ge: OptionalIntFloat = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
273 lt: OptionalIntFloat = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
274 le: OptionalIntFloat = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
275 multiple_of: OptionalIntFloat = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
276 allow_inf_nan: Optional[bool] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
278 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
279 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
280 update_not_none( 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
281 field_schema,
282 exclusiveMinimum=cls.gt,
283 exclusiveMaximum=cls.lt,
284 minimum=cls.ge,
285 maximum=cls.le,
286 multipleOf=cls.multiple_of,
287 )
288 # Modify constraints to account for differences between IEEE floats and JSON
289 if field_schema.get('exclusiveMinimum') == -math.inf: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
290 del field_schema['exclusiveMinimum'] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
291 if field_schema.get('minimum') == -math.inf: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
292 del field_schema['minimum'] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
293 if field_schema.get('exclusiveMaximum') == math.inf: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
294 del field_schema['exclusiveMaximum'] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
295 if field_schema.get('maximum') == math.inf: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
296 del field_schema['maximum'] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
298 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
299 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
300 yield strict_float_validator if cls.strict else float_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
301 yield number_size_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
302 yield number_multiple_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
303 yield float_finite_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
306def confloat( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
307 *,
308 strict: bool = False,
309 gt: float = None,
310 ge: float = None,
311 lt: float = None,
312 le: float = None,
313 multiple_of: float = None,
314 allow_inf_nan: Optional[bool] = None,
315) -> Type[float]:
316 # use kwargs then define conf in a dict to aid with IDE type hinting
317 namespace = dict(strict=strict, gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of, allow_inf_nan=allow_inf_nan) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
318 return type('ConstrainedFloatValue', (ConstrainedFloat,), namespace) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
321if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
322 PositiveFloat = float
323 NegativeFloat = float
324 NonPositiveFloat = float
325 NonNegativeFloat = float
326 StrictFloat = float
327 FiniteFloat = float
328else:
330 class PositiveFloat(ConstrainedFloat): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
331 gt = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
333 class NegativeFloat(ConstrainedFloat): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
334 lt = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
336 class NonPositiveFloat(ConstrainedFloat): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
337 le = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
339 class NonNegativeFloat(ConstrainedFloat): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
340 ge = 0 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
342 class StrictFloat(ConstrainedFloat): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
343 strict = True 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
345 class FiniteFloat(ConstrainedFloat): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
346 allow_inf_nan = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
349# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352class ConstrainedBytes(bytes): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
353 strip_whitespace = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
354 to_upper = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
355 to_lower = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
356 min_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
357 max_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
358 strict: bool = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
360 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
361 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
362 update_not_none(field_schema, minLength=cls.min_length, maxLength=cls.max_length) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
364 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
365 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
366 yield strict_bytes_validator if cls.strict else bytes_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
367 yield constr_strip_whitespace 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
368 yield constr_upper 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
369 yield constr_lower 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
370 yield constr_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
373def conbytes( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
374 *,
375 strip_whitespace: bool = False,
376 to_upper: bool = False,
377 to_lower: bool = False,
378 min_length: Optional[int] = None,
379 max_length: Optional[int] = None,
380 strict: bool = False,
381) -> Type[bytes]:
382 # use kwargs then define conf in a dict to aid with IDE type hinting
383 namespace = dict( 1EGakblcmdneoHJpzqArBsCtDFIfugvhwixjy
384 strip_whitespace=strip_whitespace,
385 to_upper=to_upper,
386 to_lower=to_lower,
387 min_length=min_length,
388 max_length=max_length,
389 strict=strict,
390 )
391 return _registered(type('ConstrainedBytesValue', (ConstrainedBytes,), namespace)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
394if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
395 StrictBytes = bytes
396else:
398 class StrictBytes(ConstrainedBytes): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
399 strict = True 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
402# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
405class ConstrainedStr(str): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
406 strip_whitespace = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
407 to_upper = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
408 to_lower = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
409 min_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
410 max_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
411 curtail_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
412 regex: Optional[Union[str, Pattern[str]]] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
413 strict = False 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
415 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
416 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
417 update_not_none( 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
418 field_schema,
419 minLength=cls.min_length,
420 maxLength=cls.max_length,
421 pattern=cls.regex and cls._get_pattern(cls.regex),
422 )
424 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
425 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
426 yield strict_str_validator if cls.strict else str_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
427 yield constr_strip_whitespace 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
428 yield constr_upper 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
429 yield constr_lower 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
430 yield constr_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
431 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
433 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
434 def validate(cls, value: Union[str]) -> Union[str]: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
435 if cls.curtail_length and len(value) > cls.curtail_length: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
436 value = value[: cls.curtail_length] 1EabcdeHpqrstKLMNOFfghij
438 if cls.regex: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
439 if not re.match(cls.regex, value): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
440 raise errors.StrRegexError(pattern=cls._get_pattern(cls.regex)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
442 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
444 @staticmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
445 def _get_pattern(regex: Union[str, Pattern[str]]) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
446 return regex if isinstance(regex, str) else regex.pattern 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
449def constr( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
450 *,
451 strip_whitespace: bool = False,
452 to_upper: bool = False,
453 to_lower: bool = False,
454 strict: bool = False,
455 min_length: Optional[int] = None,
456 max_length: Optional[int] = None,
457 curtail_length: Optional[int] = None,
458 regex: Optional[str] = None,
459) -> Type[str]:
460 # use kwargs then define conf in a dict to aid with IDE type hinting
461 namespace = dict( 1EGakblcmdneoHJpzqArBsCtDFIfugvhwixjy
462 strip_whitespace=strip_whitespace,
463 to_upper=to_upper,
464 to_lower=to_lower,
465 strict=strict,
466 min_length=min_length,
467 max_length=max_length,
468 curtail_length=curtail_length,
469 regex=regex and re.compile(regex),
470 )
471 return _registered(type('ConstrainedStrValue', (ConstrainedStr,), namespace)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
474if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
475 StrictStr = str
476else:
478 class StrictStr(ConstrainedStr): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
479 strict = True 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
482# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
485# This types superclass should be Set[T], but cython chokes on that...
486class ConstrainedSet(set): # type: ignore 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
487 # Needed for pydantic to detect that this is a set
488 __origin__ = set 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
489 __args__: Set[Type[T]] # type: ignore 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
491 min_items: Optional[int] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
492 max_items: Optional[int] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
493 item_type: Type[T] # type: ignore 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
495 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
496 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
497 yield cls.set_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
499 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
500 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
501 update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
503 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
504 def set_length_validator(cls, v: 'Optional[Set[T]]') -> 'Optional[Set[T]]': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
505 if v is None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
506 return None 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
508 v = set_validator(v) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
509 v_len = len(v) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
511 if cls.min_items is not None and v_len < cls.min_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
512 raise errors.SetMinLengthError(limit_value=cls.min_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
514 if cls.max_items is not None and v_len > cls.max_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
515 raise errors.SetMaxLengthError(limit_value=cls.max_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
517 return v 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
520def conset(item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None) -> Type[Set[T]]: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
521 # __args__ is needed to conform to typing generics api
522 namespace = {'min_items': min_items, 'max_items': max_items, 'item_type': item_type, '__args__': [item_type]} 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
523 # We use new_class to be able to deal with Generic types
524 return new_class('ConstrainedSetValue', (ConstrainedSet,), {}, lambda ns: ns.update(namespace)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
527# This types superclass should be FrozenSet[T], but cython chokes on that...
528class ConstrainedFrozenSet(frozenset): # type: ignore 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
529 # Needed for pydantic to detect that this is a set
530 __origin__ = frozenset 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
531 __args__: FrozenSet[Type[T]] # type: ignore 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
533 min_items: Optional[int] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
534 max_items: Optional[int] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
535 item_type: Type[T] # type: ignore 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
537 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
538 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
539 yield cls.frozenset_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
541 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
542 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
543 update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
545 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
546 def frozenset_length_validator(cls, v: 'Optional[FrozenSet[T]]') -> 'Optional[FrozenSet[T]]': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
547 if v is None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
548 return None 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
550 v = frozenset_validator(v) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
551 v_len = len(v) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
553 if cls.min_items is not None and v_len < cls.min_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
554 raise errors.FrozenSetMinLengthError(limit_value=cls.min_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
556 if cls.max_items is not None and v_len > cls.max_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
557 raise errors.FrozenSetMaxLengthError(limit_value=cls.max_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
559 return v 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
562def confrozenset( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
563 item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None
564) -> Type[FrozenSet[T]]:
565 # __args__ is needed to conform to typing generics api
566 namespace = {'min_items': min_items, 'max_items': max_items, 'item_type': item_type, '__args__': [item_type]} 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
567 # We use new_class to be able to deal with Generic types
568 return new_class('ConstrainedFrozenSetValue', (ConstrainedFrozenSet,), {}, lambda ns: ns.update(namespace)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
571# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LIST TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
574# This types superclass should be List[T], but cython chokes on that...
575class ConstrainedList(list): # type: ignore 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
576 # Needed for pydantic to detect that this is a list
577 __origin__ = list 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
578 __args__: Tuple[Type[T], ...] # type: ignore 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
580 min_items: Optional[int] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
581 max_items: Optional[int] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
582 unique_items: Optional[bool] = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
583 item_type: Type[T] # type: ignore 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
585 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
586 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
587 yield cls.list_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
588 if cls.unique_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
589 yield cls.unique_items_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
591 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
592 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
593 update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items, uniqueItems=cls.unique_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
595 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
596 def list_length_validator(cls, v: 'Optional[List[T]]') -> 'Optional[List[T]]': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
597 if v is None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
598 return None 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
600 v = list_validator(v) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
601 v_len = len(v) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
603 if cls.min_items is not None and v_len < cls.min_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
604 raise errors.ListMinLengthError(limit_value=cls.min_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
606 if cls.max_items is not None and v_len > cls.max_items: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
607 raise errors.ListMaxLengthError(limit_value=cls.max_items) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
609 return v 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
611 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
612 def unique_items_validator(cls, v: 'Optional[List[T]]') -> 'Optional[List[T]]': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
613 if v is None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
614 return None 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
616 for i, value in enumerate(v, start=1): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
617 if value in v[i:]: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
618 raise errors.ListUniqueItemsError() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
620 return v 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
623def conlist( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
624 item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None, unique_items: bool = None
625) -> Type[List[T]]:
626 # __args__ is needed to conform to typing generics api
627 namespace = dict( 1EGakblcmdneoHJpzqArBsCtDFIfugvhwixjy
628 min_items=min_items, max_items=max_items, unique_items=unique_items, item_type=item_type, __args__=(item_type,)
629 )
630 # We use new_class to be able to deal with Generic types
631 return new_class('ConstrainedListValue', (ConstrainedList,), {}, lambda ns: ns.update(namespace)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
634# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PYOBJECT TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
637if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
638 PyObject = Callable[..., Any]
639else:
641 class PyObject: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
642 validate_always = True 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
644 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
645 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
646 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
648 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
649 def validate(cls, value: Any) -> Any: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
650 if isinstance(value, Callable): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
651 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
653 try: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
654 value = str_validator(value) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
655 except errors.StrError: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
656 raise errors.PyObjectError(error_message='value is neither a valid import path not a valid callable') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
658 try: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
659 return import_string(value) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
660 except ImportError as e: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
661 raise errors.PyObjectError(error_message=str(e)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
664# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
667class ConstrainedDecimal(Decimal, metaclass=ConstrainedNumberMeta): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
668 gt: OptionalIntFloatDecimal = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
669 ge: OptionalIntFloatDecimal = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
670 lt: OptionalIntFloatDecimal = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
671 le: OptionalIntFloatDecimal = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
672 max_digits: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
673 decimal_places: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
674 multiple_of: OptionalIntFloatDecimal = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
676 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
677 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
678 update_not_none( 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
679 field_schema,
680 exclusiveMinimum=cls.gt,
681 exclusiveMaximum=cls.lt,
682 minimum=cls.ge,
683 maximum=cls.le,
684 multipleOf=cls.multiple_of,
685 )
687 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
688 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
689 yield decimal_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
690 yield number_size_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
691 yield number_multiple_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
692 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
694 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
695 def validate(cls, value: Decimal) -> Decimal: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
696 try: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
697 normalized_value = value.normalize() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
698 except InvalidOperation: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
699 normalized_value = value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
700 digit_tuple, exponent = normalized_value.as_tuple()[1:] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
701 if exponent in {'F', 'n', 'N'}: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
702 raise errors.DecimalIsNotFiniteError() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
704 if exponent >= 0: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
705 # A positive exponent adds that many trailing zeros.
706 digits = len(digit_tuple) + exponent 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
707 decimals = 0 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
708 else:
709 # If the absolute value of the negative exponent is larger than the
710 # number of digits, then it's the same as the number of digits,
711 # because it'll consume all of the digits in digit_tuple and then
712 # add abs(exponent) - len(digit_tuple) leading zeros after the
713 # decimal point.
714 if abs(exponent) > len(digit_tuple): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
715 digits = decimals = abs(exponent) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
716 else:
717 digits = len(digit_tuple) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
718 decimals = abs(exponent) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
719 whole_digits = digits - decimals 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
721 if cls.max_digits is not None and digits > cls.max_digits: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
722 raise errors.DecimalMaxDigitsError(max_digits=cls.max_digits) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
724 if cls.decimal_places is not None and decimals > cls.decimal_places: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
725 raise errors.DecimalMaxPlacesError(decimal_places=cls.decimal_places) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
727 if cls.max_digits is not None and cls.decimal_places is not None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
728 expected = cls.max_digits - cls.decimal_places 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
729 if whole_digits > expected: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
730 raise errors.DecimalWholeDigitsError(whole_digits=expected) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
732 return value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
735def condecimal( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
736 *,
737 gt: Decimal = None,
738 ge: Decimal = None,
739 lt: Decimal = None,
740 le: Decimal = None,
741 max_digits: Optional[int] = None,
742 decimal_places: Optional[int] = None,
743 multiple_of: Decimal = None,
744) -> Type[Decimal]:
745 # use kwargs then define conf in a dict to aid with IDE type hinting
746 namespace = dict( 1EGakblcmdneoHJpzqArBsCtDFIfugvhwixjy
747 gt=gt, ge=ge, lt=lt, le=le, max_digits=max_digits, decimal_places=decimal_places, multiple_of=multiple_of
748 )
749 return type('ConstrainedDecimalValue', (ConstrainedDecimal,), namespace) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
752# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
754if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
755 UUID1 = UUID
756 UUID3 = UUID
757 UUID4 = UUID
758 UUID5 = UUID
759else:
761 class UUID1(UUID): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
762 _required_version = 1 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
764 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
765 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
766 field_schema.update(type='string', format=f'uuid{cls._required_version}') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
768 class UUID3(UUID1): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
769 _required_version = 3 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
771 class UUID4(UUID1): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
772 _required_version = 4 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
774 class UUID5(UUID1): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
775 _required_version = 5 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
778# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
780if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
781 FilePath = Path
782 DirectoryPath = Path
783else:
785 class FilePath(Path): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
786 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
787 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
788 field_schema.update(format='file-path') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
790 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
791 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
792 yield path_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
793 yield path_exists_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
794 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
796 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
797 def validate(cls, value: Path) -> Path: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
798 if not value.is_file(): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
799 raise errors.PathNotAFileError(path=value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
801 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
803 class DirectoryPath(Path): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
804 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
805 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
806 field_schema.update(format='directory-path') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
808 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
809 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
810 yield path_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
811 yield path_exists_validator 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
812 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
814 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
815 def validate(cls, value: Path) -> Path: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
816 if not value.is_dir(): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
817 raise errors.PathNotADirectoryError(path=value) 1EGakblcmdneoKLMNOFIfugvhwixjy
819 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
822# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
825class JsonWrapper: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
826 pass 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
829class JsonMeta(type): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
830 def __getitem__(self, t: Type[Any]) -> Type[JsonWrapper]: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
831 if t is Any: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
832 return Json # allow Json[Any] to replecate plain Json 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
833 return _registered(type('JsonWrapperValue', (JsonWrapper,), {'inner_type': t})) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
836if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
837 Json = Annotated[T, ...] # Json[list[str]] will be recognized by type checkers as list[str]
839else:
841 class Json(metaclass=JsonMeta): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
842 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
843 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
844 field_schema.update(type='string', format='json-string') 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
847# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
850class SecretField(abc.ABC): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
851 """
852 Note: this should be implemented as a generic like `SecretField(ABC, Generic[T])`,
853 the `__init__()` should be part of the abstract class and the
854 `get_secret_value()` method should use the generic `T` type.
856 However Cython doesn't support very well generics at the moment and
857 the generated code fails to be imported (see
858 https://github.com/cython/cython/issues/2753).
859 """
861 def __eq__(self, other: Any) -> bool: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
862 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
864 def __str__(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
865 return '**********' if self.get_secret_value() else '' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
867 def __hash__(self) -> int: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
868 return hash(self.get_secret_value()) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
870 @abc.abstractmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
871 def get_secret_value(self) -> Any: # pragma: no cover 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
872 ...
875class SecretStr(SecretField): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
876 min_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
877 max_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
879 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
880 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
881 update_not_none( 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
882 field_schema,
883 type='string',
884 writeOnly=True,
885 format='password',
886 minLength=cls.min_length,
887 maxLength=cls.max_length,
888 )
890 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
891 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
892 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
893 yield constr_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
895 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
896 def validate(cls, value: Any) -> 'SecretStr': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
897 if isinstance(value, cls): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
898 return value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
899 value = str_validator(value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
900 return cls(value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
902 def __init__(self, value: str): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
903 self._secret_value = value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
905 def __repr__(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
906 return f"SecretStr('{self}')" 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
908 def __len__(self) -> int: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
909 return len(self._secret_value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
911 def display(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
912 warnings.warn('`secret_str.display()` is deprecated, use `str(secret_str)` instead', DeprecationWarning) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
913 return str(self) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
915 def get_secret_value(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
916 return self._secret_value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
919class SecretBytes(SecretField): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
920 min_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
921 max_length: OptionalInt = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
923 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
924 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
925 update_not_none( 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
926 field_schema,
927 type='string',
928 writeOnly=True,
929 format='password',
930 minLength=cls.min_length,
931 maxLength=cls.max_length,
932 )
934 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
935 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
936 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
937 yield constr_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
939 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
940 def validate(cls, value: Any) -> 'SecretBytes': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
941 if isinstance(value, cls): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
942 return value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
943 value = bytes_validator(value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
944 return cls(value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
946 def __init__(self, value: bytes): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
947 self._secret_value = value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
949 def __repr__(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
950 return f"SecretBytes(b'{self}')" 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
952 def __len__(self) -> int: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
953 return len(self._secret_value) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
955 def display(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
956 warnings.warn('`secret_bytes.display()` is deprecated, use `str(secret_bytes)` instead', DeprecationWarning) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
957 return str(self) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
959 def get_secret_value(self) -> bytes: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
960 return self._secret_value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
963# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
966class PaymentCardBrand(str, Enum): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
967 # If you add another card type, please also add it to the
968 # Hypothesis strategy in `pydantic._hypothesis_plugin`.
969 amex = 'American Express' 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
970 mastercard = 'Mastercard' 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
971 visa = 'Visa' 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
972 other = 'other' 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
974 def __str__(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
975 return self.value 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
978class PaymentCardNumber(str): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
979 """
980 Based on: https://en.wikipedia.org/wiki/Payment_card_number
981 """
983 strip_whitespace: ClassVar[bool] = True 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
984 min_length: ClassVar[int] = 12 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
985 max_length: ClassVar[int] = 19 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
986 bin: str 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
987 last4: str 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
988 brand: PaymentCardBrand 1EGakblcmdneoHJpzqArBsCtDPQRSTUFIfugvhwixjy
990 def __init__(self, card_number: str): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
991 self.bin = card_number[:6] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
992 self.last4 = card_number[-4:] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
993 self.brand = self._get_brand(card_number) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
995 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
996 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
997 yield str_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
998 yield constr_strip_whitespace 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
999 yield constr_length_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1000 yield cls.validate_digits 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1001 yield cls.validate_luhn_check_digit 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1002 yield cls 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1003 yield cls.validate_length_for_brand 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1005 @property 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1006 def masked(self) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1007 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1008 return f'{self.bin}{"*" * num_masked}{self.last4}' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1010 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1011 def validate_digits(cls, card_number: str) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1012 if not card_number.isdigit(): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1013 raise errors.NotDigitError 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1014 return card_number 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1016 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1017 def validate_luhn_check_digit(cls, card_number: str) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1018 """
1019 Based on: https://en.wikipedia.org/wiki/Luhn_algorithm
1020 """
1021 sum_ = int(card_number[-1]) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1022 length = len(card_number) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1023 parity = length % 2 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1024 for i in range(length - 1): 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1025 digit = int(card_number[i]) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1026 if i % 2 == parity: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1027 digit *= 2 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1028 if digit > 9: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1029 digit -= 9 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1030 sum_ += digit 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1031 valid = sum_ % 10 == 0 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1032 if not valid: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1033 raise errors.LuhnValidationError 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1034 return card_number 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1036 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1037 def validate_length_for_brand(cls, card_number: 'PaymentCardNumber') -> 'PaymentCardNumber': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1038 """
1039 Validate length based on BIN for major brands:
1040 https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN)
1041 """
1042 required_length: Union[None, int, str] = None 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1043 if card_number.brand in PaymentCardBrand.mastercard: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1044 required_length = 16 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1045 valid = len(card_number) == required_length 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1046 elif card_number.brand == PaymentCardBrand.visa: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1047 required_length = '13, 16 or 19' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1048 valid = len(card_number) in {13, 16, 19} 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1049 elif card_number.brand == PaymentCardBrand.amex: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1050 required_length = 15 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1051 valid = len(card_number) == required_length 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1052 else:
1053 valid = True 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1054 if not valid: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1055 raise errors.InvalidLengthForBrand(brand=card_number.brand, required_length=required_length) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1056 return card_number 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1058 @staticmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1059 def _get_brand(card_number: str) -> PaymentCardBrand: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1060 if card_number[0] == '4': 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1061 brand = PaymentCardBrand.visa 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1062 elif 51 <= int(card_number[:2]) <= 55: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1063 brand = PaymentCardBrand.mastercard 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1064 elif card_number[:2] in {'34', '37'}: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1065 brand = PaymentCardBrand.amex 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1066 else:
1067 brand = PaymentCardBrand.other 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1068 return brand 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1071# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1073BYTE_SIZES = { 1akblcmdneopzqArBsCtDPQRSTUfugvhwixjy
1074 'b': 1,
1075 'kb': 10**3,
1076 'mb': 10**6,
1077 'gb': 10**9,
1078 'tb': 10**12,
1079 'pb': 10**15,
1080 'eb': 10**18,
1081 'kib': 2**10,
1082 'mib': 2**20,
1083 'gib': 2**30,
1084 'tib': 2**40,
1085 'pib': 2**50,
1086 'eib': 2**60,
1087}
1088BYTE_SIZES.update({k.lower()[0]: v for k, v in BYTE_SIZES.items() if 'i' not in k}) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1089byte_string_re = re.compile(r'^\s*(\d*\.?\d+)\s*(\w+)?', re.IGNORECASE) 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1092class ByteSize(int): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1093 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1094 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1095 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1097 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1098 def validate(cls, v: StrIntFloat) -> 'ByteSize': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1099 try: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1100 return cls(int(v)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1101 except ValueError: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1102 pass 1EGakblcmdneoHJpzqArBsCtDFIfugvhwixjy
1104 str_match = byte_string_re.match(str(v)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1105 if str_match is None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1106 raise errors.InvalidByteSize() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1108 scalar, unit = str_match.groups() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1109 if unit is None: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1110 unit = 'b' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1112 try: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1113 unit_mult = BYTE_SIZES[unit.lower()] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1114 except KeyError: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1115 raise errors.InvalidByteSizeUnit(unit=unit) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1117 return cls(int(float(scalar) * unit_mult)) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1119 def human_readable(self, decimal: bool = False) -> str: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1120 if decimal: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1121 divisor = 1000 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1122 units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1123 final_unit = 'EB' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1124 else:
1125 divisor = 1024 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1126 units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1127 final_unit = 'EiB' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1129 num = float(self) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1130 for unit in units: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1131 if abs(num) < divisor: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1132 return f'{num:0.1f}{unit}' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1133 num /= divisor 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1135 return f'{num:0.1f}{final_unit}' 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1137 def to(self, unit: str) -> float: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1138 try: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1139 unit_div = BYTE_SIZES[unit.lower()] 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1140 except KeyError: 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1141 raise errors.InvalidByteSizeUnit(unit=unit) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1143 return self / unit_div 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1146# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1148if TYPE_CHECKING: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1149 PastDate = date
1150 FutureDate = date
1151else:
1153 class PastDate(date): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1154 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1155 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1156 yield parse_date 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1157 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1159 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1160 def validate(cls, value: date) -> date: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1161 if value >= date.today(): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1162 raise errors.DateNotInThePastError() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1164 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1166 class FutureDate(date): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1167 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1168 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1169 yield parse_date 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1170 yield cls.validate 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1172 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1173 def validate(cls, value: date) -> date: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1174 if value <= date.today(): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1175 raise errors.DateNotInTheFutureError() 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1177 return value 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1180class ConstrainedDate(date, metaclass=ConstrainedNumberMeta): 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1181 gt: OptionalDate = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1182 ge: OptionalDate = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1183 lt: OptionalDate = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1184 le: OptionalDate = None 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1186 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1187 def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1188 update_not_none(field_schema, exclusiveMinimum=cls.gt, exclusiveMaximum=cls.lt, minimum=cls.ge, maximum=cls.le) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1190 @classmethod 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1191 def __get_validators__(cls) -> 'CallableGenerator': 1EGakblcmdneoHJpzqArBsCtDKLMNPQRSTUOFIfugvhwixjy
1192 yield parse_date 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1193 yield number_size_validator 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1196def condate( 1akblcmdneopzqArBsCtDKLMNPQRSTUOfugvhwixjy
1197 *,
1198 gt: date = None,
1199 ge: date = None,
1200 lt: date = None,
1201 le: date = None,
1202) -> Type[date]:
1203 # use kwargs then define conf in a dict to aid with IDE type hinting
1204 namespace = dict(gt=gt, ge=ge, lt=lt, le=le) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy
1205 return type('ConstrainedDateValue', (ConstrainedDate,), namespace) 1EGakblcmdneoHJpzqArBsCtDKLMNOFIfugvhwixjy