Coverage for pydantic/types.py: 97.87%
622 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
1"""The types module contains custom types used by pydantic."""
3from __future__ import annotations as _annotations 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
5import base64 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
6import dataclasses as _dataclasses 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
7import re 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
8from datetime import date, datetime 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
9from decimal import Decimal 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
10from enum import Enum 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
11from pathlib import Path 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
12from types import ModuleType 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
13from typing import ( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
14 TYPE_CHECKING,
15 Any,
16 Callable,
17 ClassVar,
18 Dict,
19 FrozenSet,
20 Generic,
21 Hashable,
22 Iterator,
23 List,
24 Pattern,
25 Set,
26 TypeVar,
27 Union,
28 cast,
29 get_args,
30 get_origin,
31)
32from uuid import UUID 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
34import annotated_types 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
35from annotated_types import BaseMetadata, MaxLen, MinLen 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
36from pydantic_core import CoreSchema, PydanticCustomError, core_schema 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
37from typing_extensions import Annotated, Literal, Protocol, TypeAlias, TypeAliasType, deprecated 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
39from ._internal import ( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
40 _core_utils,
41 _fields,
42 _internal_dataclass,
43 _typing_extra,
44 _utils,
45 _validators,
46)
47from ._migration import getattr_migration 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
48from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
49from .errors import PydanticUserError 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
50from .json_schema import JsonSchemaValue 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
51from .warnings import PydanticDeprecatedSince20 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
53__all__ = ( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
54 'Strict',
55 'StrictStr',
56 'conbytes',
57 'conlist',
58 'conset',
59 'confrozenset',
60 'constr',
61 'ImportString',
62 'conint',
63 'PositiveInt',
64 'NegativeInt',
65 'NonNegativeInt',
66 'NonPositiveInt',
67 'confloat',
68 'PositiveFloat',
69 'NegativeFloat',
70 'NonNegativeFloat',
71 'NonPositiveFloat',
72 'FiniteFloat',
73 'condecimal',
74 'UUID1',
75 'UUID3',
76 'UUID4',
77 'UUID5',
78 'FilePath',
79 'DirectoryPath',
80 'NewPath',
81 'Json',
82 'Secret',
83 'SecretStr',
84 'SecretBytes',
85 'StrictBool',
86 'StrictBytes',
87 'StrictInt',
88 'StrictFloat',
89 'PaymentCardNumber',
90 'ByteSize',
91 'PastDate',
92 'FutureDate',
93 'PastDatetime',
94 'FutureDatetime',
95 'condate',
96 'AwareDatetime',
97 'NaiveDatetime',
98 'AllowInfNan',
99 'EncoderProtocol',
100 'EncodedBytes',
101 'EncodedStr',
102 'Base64Encoder',
103 'Base64Bytes',
104 'Base64Str',
105 'Base64UrlBytes',
106 'Base64UrlStr',
107 'GetPydanticSchema',
108 'StringConstraints',
109 'Tag',
110 'Discriminator',
111 'JsonValue',
112 'OnErrorOmit',
113 'FailFast',
114)
117T = TypeVar('T') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
120@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
121class Strict(_fields.PydanticMetadata, BaseMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
122 """Usage docs: https://docs.pydantic.dev/2.8/concepts/strict_mode/#strict-mode-with-annotated-strict
124 A field metadata class to indicate that a field should be validated in strict mode.
126 Attributes:
127 strict: Whether to validate the field in strict mode.
129 Example:
130 ```python
131 from typing_extensions import Annotated
133 from pydantic.types import Strict
135 StrictBool = Annotated[bool, Strict()]
136 ```
137 """
139 strict: bool = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
141 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
142 return hash(self.strict) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
145# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147StrictBool = Annotated[bool, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
148"""A boolean that must be either ``True`` or ``False``.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
150# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
153def conint( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
154 *,
155 strict: bool | None = None,
156 gt: int | None = None,
157 ge: int | None = None,
158 lt: int | None = None,
159 le: int | None = None,
160 multiple_of: int | None = None,
161) -> type[int]:
162 """
163 !!! warning "Discouraged"
164 This function is **discouraged** in favor of using
165 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
166 [`Field`][pydantic.fields.Field] instead.
168 This function will be **deprecated** in Pydantic 3.0.
170 The reason is that `conint` returns a type, which doesn't play well with static analysis tools.
172 === ":x: Don't do this"
173 ```py
174 from pydantic import BaseModel, conint
176 class Foo(BaseModel):
177 bar: conint(strict=True, gt=0)
178 ```
180 === ":white_check_mark: Do this"
181 ```py
182 from typing_extensions import Annotated
184 from pydantic import BaseModel, Field
186 class Foo(BaseModel):
187 bar: Annotated[int, Field(strict=True, gt=0)]
188 ```
190 A wrapper around `int` that allows for additional constraints.
192 Args:
193 strict: Whether to validate the integer in strict mode. Defaults to `None`.
194 gt: The value must be greater than this.
195 ge: The value must be greater than or equal to this.
196 lt: The value must be less than this.
197 le: The value must be less than or equal to this.
198 multiple_of: The value must be a multiple of this.
200 Returns:
201 The wrapped integer type.
203 ```py
204 from pydantic import BaseModel, ValidationError, conint
206 class ConstrainedExample(BaseModel):
207 constrained_int: conint(gt=1)
209 m = ConstrainedExample(constrained_int=2)
210 print(repr(m))
211 #> ConstrainedExample(constrained_int=2)
213 try:
214 ConstrainedExample(constrained_int=0)
215 except ValidationError as e:
216 print(e.errors())
217 '''
218 [
219 {
220 'type': 'greater_than',
221 'loc': ('constrained_int',),
222 'msg': 'Input should be greater than 1',
223 'input': 0,
224 'ctx': {'gt': 1},
225 'url': 'https://errors.pydantic.dev/2/v/greater_than',
226 }
227 ]
228 '''
229 ```
231 """ # noqa: D212
232 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
233 int,
234 Strict(strict) if strict is not None else None,
235 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
236 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
237 ]
240PositiveInt = Annotated[int, annotated_types.Gt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
241"""An integer that must be greater than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
243```py
244from pydantic import BaseModel, PositiveInt, ValidationError
246class Model(BaseModel):
247 positive_int: PositiveInt
249m = Model(positive_int=1)
250print(repr(m))
251#> Model(positive_int=1)
253try:
254 Model(positive_int=-1)
255except ValidationError as e:
256 print(e.errors())
257 '''
258 [
259 {
260 'type': 'greater_than',
261 'loc': ('positive_int',),
262 'msg': 'Input should be greater than 0',
263 'input': -1,
264 'ctx': {'gt': 0},
265 'url': 'https://errors.pydantic.dev/2/v/greater_than',
266 }
267 ]
268 '''
269```
270"""
271NegativeInt = Annotated[int, annotated_types.Lt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
272"""An integer that must be less than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
274```py
275from pydantic import BaseModel, NegativeInt, ValidationError
277class Model(BaseModel):
278 negative_int: NegativeInt
280m = Model(negative_int=-1)
281print(repr(m))
282#> Model(negative_int=-1)
284try:
285 Model(negative_int=1)
286except ValidationError as e:
287 print(e.errors())
288 '''
289 [
290 {
291 'type': 'less_than',
292 'loc': ('negative_int',),
293 'msg': 'Input should be less than 0',
294 'input': 1,
295 'ctx': {'lt': 0},
296 'url': 'https://errors.pydantic.dev/2/v/less_than',
297 }
298 ]
299 '''
300```
301"""
302NonPositiveInt = Annotated[int, annotated_types.Le(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
303"""An integer that must be less than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
305```py
306from pydantic import BaseModel, NonPositiveInt, ValidationError
308class Model(BaseModel):
309 non_positive_int: NonPositiveInt
311m = Model(non_positive_int=0)
312print(repr(m))
313#> Model(non_positive_int=0)
315try:
316 Model(non_positive_int=1)
317except ValidationError as e:
318 print(e.errors())
319 '''
320 [
321 {
322 'type': 'less_than_equal',
323 'loc': ('non_positive_int',),
324 'msg': 'Input should be less than or equal to 0',
325 'input': 1,
326 'ctx': {'le': 0},
327 'url': 'https://errors.pydantic.dev/2/v/less_than_equal',
328 }
329 ]
330 '''
331```
332"""
333NonNegativeInt = Annotated[int, annotated_types.Ge(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
334"""An integer that must be greater than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
336```py
337from pydantic import BaseModel, NonNegativeInt, ValidationError
339class Model(BaseModel):
340 non_negative_int: NonNegativeInt
342m = Model(non_negative_int=0)
343print(repr(m))
344#> Model(non_negative_int=0)
346try:
347 Model(non_negative_int=-1)
348except ValidationError as e:
349 print(e.errors())
350 '''
351 [
352 {
353 'type': 'greater_than_equal',
354 'loc': ('non_negative_int',),
355 'msg': 'Input should be greater than or equal to 0',
356 'input': -1,
357 'ctx': {'ge': 0},
358 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal',
359 }
360 ]
361 '''
362```
363"""
364StrictInt = Annotated[int, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
365"""An integer that must be validated in strict mode. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
367```py
368from pydantic import BaseModel, StrictInt, ValidationError
370class StrictIntModel(BaseModel):
371 strict_int: StrictInt
373try:
374 StrictIntModel(strict_int=3.14159)
375except ValidationError as e:
376 print(e)
377 '''
378 1 validation error for StrictIntModel
379 strict_int
380 Input should be a valid integer [type=int_type, input_value=3.14159, input_type=float]
381 '''
382```
383"""
385# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
388@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
389class AllowInfNan(_fields.PydanticMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
390 """A field metadata class to indicate that a field should allow ``-inf``, ``inf``, and ``nan``."""
392 allow_inf_nan: bool = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
394 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
395 return hash(self.allow_inf_nan) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
398def confloat( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
399 *,
400 strict: bool | None = None,
401 gt: float | None = None,
402 ge: float | None = None,
403 lt: float | None = None,
404 le: float | None = None,
405 multiple_of: float | None = None,
406 allow_inf_nan: bool | None = None,
407) -> type[float]:
408 """
409 !!! warning "Discouraged"
410 This function is **discouraged** in favor of using
411 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
412 [`Field`][pydantic.fields.Field] instead.
414 This function will be **deprecated** in Pydantic 3.0.
416 The reason is that `confloat` returns a type, which doesn't play well with static analysis tools.
418 === ":x: Don't do this"
419 ```py
420 from pydantic import BaseModel, confloat
422 class Foo(BaseModel):
423 bar: confloat(strict=True, gt=0)
424 ```
426 === ":white_check_mark: Do this"
427 ```py
428 from typing_extensions import Annotated
430 from pydantic import BaseModel, Field
432 class Foo(BaseModel):
433 bar: Annotated[float, Field(strict=True, gt=0)]
434 ```
436 A wrapper around `float` that allows for additional constraints.
438 Args:
439 strict: Whether to validate the float in strict mode.
440 gt: The value must be greater than this.
441 ge: The value must be greater than or equal to this.
442 lt: The value must be less than this.
443 le: The value must be less than or equal to this.
444 multiple_of: The value must be a multiple of this.
445 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`.
447 Returns:
448 The wrapped float type.
450 ```py
451 from pydantic import BaseModel, ValidationError, confloat
453 class ConstrainedExample(BaseModel):
454 constrained_float: confloat(gt=1.0)
456 m = ConstrainedExample(constrained_float=1.1)
457 print(repr(m))
458 #> ConstrainedExample(constrained_float=1.1)
460 try:
461 ConstrainedExample(constrained_float=0.9)
462 except ValidationError as e:
463 print(e.errors())
464 '''
465 [
466 {
467 'type': 'greater_than',
468 'loc': ('constrained_float',),
469 'msg': 'Input should be greater than 1',
470 'input': 0.9,
471 'ctx': {'gt': 1.0},
472 'url': 'https://errors.pydantic.dev/2/v/greater_than',
473 }
474 ]
475 '''
476 ```
477 """ # noqa: D212
478 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
479 float,
480 Strict(strict) if strict is not None else None,
481 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
482 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
483 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None,
484 ]
487PositiveFloat = Annotated[float, annotated_types.Gt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
488"""A float that must be greater than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
490```py
491from pydantic import BaseModel, PositiveFloat, ValidationError
493class Model(BaseModel):
494 positive_float: PositiveFloat
496m = Model(positive_float=1.0)
497print(repr(m))
498#> Model(positive_float=1.0)
500try:
501 Model(positive_float=-1.0)
502except ValidationError as e:
503 print(e.errors())
504 '''
505 [
506 {
507 'type': 'greater_than',
508 'loc': ('positive_float',),
509 'msg': 'Input should be greater than 0',
510 'input': -1.0,
511 'ctx': {'gt': 0.0},
512 'url': 'https://errors.pydantic.dev/2/v/greater_than',
513 }
514 ]
515 '''
516```
517"""
518NegativeFloat = Annotated[float, annotated_types.Lt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
519"""A float that must be less than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
521```py
522from pydantic import BaseModel, NegativeFloat, ValidationError
524class Model(BaseModel):
525 negative_float: NegativeFloat
527m = Model(negative_float=-1.0)
528print(repr(m))
529#> Model(negative_float=-1.0)
531try:
532 Model(negative_float=1.0)
533except ValidationError as e:
534 print(e.errors())
535 '''
536 [
537 {
538 'type': 'less_than',
539 'loc': ('negative_float',),
540 'msg': 'Input should be less than 0',
541 'input': 1.0,
542 'ctx': {'lt': 0.0},
543 'url': 'https://errors.pydantic.dev/2/v/less_than',
544 }
545 ]
546 '''
547```
548"""
549NonPositiveFloat = Annotated[float, annotated_types.Le(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
550"""A float that must be less than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
552```py
553from pydantic import BaseModel, NonPositiveFloat, ValidationError
555class Model(BaseModel):
556 non_positive_float: NonPositiveFloat
558m = Model(non_positive_float=0.0)
559print(repr(m))
560#> Model(non_positive_float=0.0)
562try:
563 Model(non_positive_float=1.0)
564except ValidationError as e:
565 print(e.errors())
566 '''
567 [
568 {
569 'type': 'less_than_equal',
570 'loc': ('non_positive_float',),
571 'msg': 'Input should be less than or equal to 0',
572 'input': 1.0,
573 'ctx': {'le': 0.0},
574 'url': 'https://errors.pydantic.dev/2/v/less_than_equal',
575 }
576 ]
577 '''
578```
579"""
580NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
581"""A float that must be greater than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
583```py
584from pydantic import BaseModel, NonNegativeFloat, ValidationError
586class Model(BaseModel):
587 non_negative_float: NonNegativeFloat
589m = Model(non_negative_float=0.0)
590print(repr(m))
591#> Model(non_negative_float=0.0)
593try:
594 Model(non_negative_float=-1.0)
595except ValidationError as e:
596 print(e.errors())
597 '''
598 [
599 {
600 'type': 'greater_than_equal',
601 'loc': ('non_negative_float',),
602 'msg': 'Input should be greater than or equal to 0',
603 'input': -1.0,
604 'ctx': {'ge': 0.0},
605 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal',
606 }
607 ]
608 '''
609```
610"""
611StrictFloat = Annotated[float, Strict(True)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
612"""A float that must be validated in strict mode. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
614```py
615from pydantic import BaseModel, StrictFloat, ValidationError
617class StrictFloatModel(BaseModel):
618 strict_float: StrictFloat
620try:
621 StrictFloatModel(strict_float='1.0')
622except ValidationError as e:
623 print(e)
624 '''
625 1 validation error for StrictFloatModel
626 strict_float
627 Input should be a valid number [type=float_type, input_value='1.0', input_type=str]
628 '''
629```
630"""
631FiniteFloat = Annotated[float, AllowInfNan(False)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
632"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
634```py
635from pydantic import BaseModel, FiniteFloat
637class Model(BaseModel):
638 finite: FiniteFloat
640m = Model(finite=1.0)
641print(m)
642#> finite=1.0
643```
644"""
647# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
650def conbytes( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
651 *,
652 min_length: int | None = None,
653 max_length: int | None = None,
654 strict: bool | None = None,
655) -> type[bytes]:
656 """A wrapper around `bytes` that allows for additional constraints.
658 Args:
659 min_length: The minimum length of the bytes.
660 max_length: The maximum length of the bytes.
661 strict: Whether to validate the bytes in strict mode.
663 Returns:
664 The wrapped bytes type.
665 """
666 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
667 bytes,
668 Strict(strict) if strict is not None else None,
669 annotated_types.Len(min_length or 0, max_length),
670 ]
673StrictBytes = Annotated[bytes, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
674"""A bytes that must be validated in strict mode.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
677# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
680@_dataclasses.dataclass(frozen=True) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
681class StringConstraints(annotated_types.GroupedMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
682 """Usage docs: https://docs.pydantic.dev/2.8/concepts/fields/#string-constraints
684 Apply constraints to `str` types.
686 Attributes:
687 strip_whitespace: Whether to remove leading and trailing whitespace.
688 to_upper: Whether to convert the string to uppercase.
689 to_lower: Whether to convert the string to lowercase.
690 strict: Whether to validate the string in strict mode.
691 min_length: The minimum length of the string.
692 max_length: The maximum length of the string.
693 pattern: A regex pattern that the string must match.
694 """
696 strip_whitespace: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
697 to_upper: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
698 to_lower: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
699 strict: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
700 min_length: int | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
701 max_length: int | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
702 pattern: str | Pattern[str] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
704 def __iter__(self) -> Iterator[BaseMetadata]: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
705 if self.min_length is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
706 yield MinLen(self.min_length) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
707 if self.max_length is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
708 yield MaxLen(self.max_length) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
709 if self.strict is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
710 yield Strict(self.strict) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
711 if ( 1zABCDaEFGH
712 self.strip_whitespace is not None
713 or self.pattern is not None
714 or self.to_lower is not None
715 or self.to_upper is not None
716 ):
717 yield _fields.pydantic_general_metadata( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
718 strip_whitespace=self.strip_whitespace,
719 to_upper=self.to_upper,
720 to_lower=self.to_lower,
721 pattern=self.pattern,
722 )
725def constr( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
726 *,
727 strip_whitespace: bool | None = None,
728 to_upper: bool | None = None,
729 to_lower: bool | None = None,
730 strict: bool | None = None,
731 min_length: int | None = None,
732 max_length: int | None = None,
733 pattern: str | Pattern[str] | None = None,
734) -> type[str]:
735 """
736 !!! warning "Discouraged"
737 This function is **discouraged** in favor of using
738 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
739 [`StringConstraints`][pydantic.types.StringConstraints] instead.
741 This function will be **deprecated** in Pydantic 3.0.
743 The reason is that `constr` returns a type, which doesn't play well with static analysis tools.
745 === ":x: Don't do this"
746 ```py
747 from pydantic import BaseModel, constr
749 class Foo(BaseModel):
750 bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$')
751 ```
753 === ":white_check_mark: Do this"
754 ```py
755 from typing_extensions import Annotated
757 from pydantic import BaseModel, StringConstraints
759 class Foo(BaseModel):
760 bar: Annotated[str, StringConstraints(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$')]
761 ```
763 A wrapper around `str` that allows for additional constraints.
765 ```py
766 from pydantic import BaseModel, constr
768 class Foo(BaseModel):
769 bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$')
772 foo = Foo(bar=' hello ')
773 print(foo)
774 #> bar='HELLO'
775 ```
777 Args:
778 strip_whitespace: Whether to remove leading and trailing whitespace.
779 to_upper: Whether to turn all characters to uppercase.
780 to_lower: Whether to turn all characters to lowercase.
781 strict: Whether to validate the string in strict mode.
782 min_length: The minimum length of the string.
783 max_length: The maximum length of the string.
784 pattern: A regex pattern to validate the string against.
786 Returns:
787 The wrapped string type.
788 """ # noqa: D212
789 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
790 str,
791 StringConstraints(
792 strip_whitespace=strip_whitespace,
793 to_upper=to_upper,
794 to_lower=to_lower,
795 strict=strict,
796 min_length=min_length,
797 max_length=max_length,
798 pattern=pattern,
799 ),
800 ]
803StrictStr = Annotated[str, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
804"""A string that must be validated in strict mode.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
807# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
808HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
811def conset( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
812 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None
813) -> type[set[HashableItemType]]:
814 """A wrapper around `typing.Set` that allows for additional constraints.
816 Args:
817 item_type: The type of the items in the set.
818 min_length: The minimum length of the set.
819 max_length: The maximum length of the set.
821 Returns:
822 The wrapped set type.
823 """
824 return Annotated[Set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
827def confrozenset( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
828 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None
829) -> type[frozenset[HashableItemType]]:
830 """A wrapper around `typing.FrozenSet` that allows for additional constraints.
832 Args:
833 item_type: The type of the items in the frozenset.
834 min_length: The minimum length of the frozenset.
835 max_length: The maximum length of the frozenset.
837 Returns:
838 The wrapped frozenset type.
839 """
840 return Annotated[FrozenSet[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
843AnyItemType = TypeVar('AnyItemType') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
846def conlist( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
847 item_type: type[AnyItemType],
848 *,
849 min_length: int | None = None,
850 max_length: int | None = None,
851 unique_items: bool | None = None,
852) -> type[list[AnyItemType]]:
853 """A wrapper around typing.List that adds validation.
855 Args:
856 item_type: The type of the items in the list.
857 min_length: The minimum length of the list. Defaults to None.
858 max_length: The maximum length of the list. Defaults to None.
859 unique_items: Whether the items in the list must be unique. Defaults to None.
860 !!! warning Deprecated
861 The `unique_items` parameter is deprecated, use `Set` instead.
862 See [this issue](https://github.com/pydantic/pydantic-core/issues/296) for more details.
864 Returns:
865 The wrapped list type.
866 """
867 if unique_items is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
868 raise PydanticUserError( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
869 (
870 '`unique_items` is removed, use `Set` instead'
871 '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)'
872 ),
873 code='removed-kwargs',
874 )
875 return Annotated[List[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
878# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
880AnyType = TypeVar('AnyType') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
881if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
882 ImportString = Annotated[AnyType, ...] 1a
883else:
885 class ImportString: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
886 """A type that can be used to import a type from a string.
888 `ImportString` expects a string and loads the Python object importable at that dotted path.
889 Attributes of modules may be separated from the module by `:` or `.`, e.g. if `'math:cos'` was provided,
890 the resulting field value would be the function`cos`. If a `.` is used and both an attribute and submodule
891 are present at the same path, the module will be preferred.
893 On model instantiation, pointers will be evaluated and imported. There is
894 some nuance to this behavior, demonstrated in the examples below.
896 **Good behavior:**
897 ```py
898 from math import cos
900 from pydantic import BaseModel, Field, ImportString, ValidationError
903 class ImportThings(BaseModel):
904 obj: ImportString
907 # A string value will cause an automatic import
908 my_cos = ImportThings(obj='math.cos')
910 # You can use the imported function as you would expect
911 cos_of_0 = my_cos.obj(0)
912 assert cos_of_0 == 1
915 # A string whose value cannot be imported will raise an error
916 try:
917 ImportThings(obj='foo.bar')
918 except ValidationError as e:
919 print(e)
920 '''
921 1 validation error for ImportThings
922 obj
923 Invalid python path: No module named 'foo.bar' [type=import_error, input_value='foo.bar', input_type=str]
924 '''
927 # Actual python objects can be assigned as well
928 my_cos = ImportThings(obj=cos)
929 my_cos_2 = ImportThings(obj='math.cos')
930 my_cos_3 = ImportThings(obj='math:cos')
931 assert my_cos == my_cos_2 == my_cos_3
934 # You can set default field value either as Python object:
935 class ImportThingsDefaultPyObj(BaseModel):
936 obj: ImportString = math.cos
939 # or as a string value (but only if used with `validate_default=True`)
940 class ImportThingsDefaultString(BaseModel):
941 obj: ImportString = Field(default='math.cos', validate_default=True)
944 my_cos_default1 = ImportThingsDefaultPyObj()
945 my_cos_default2 = ImportThingsDefaultString()
946 assert my_cos_default1.obj == my_cos_default2.obj == math.cos
949 # note: this will not work!
950 class ImportThingsMissingValidateDefault(BaseModel):
951 obj: ImportString = 'math.cos'
953 my_cos_default3 = ImportThingsMissingValidateDefault()
954 assert my_cos_default3.obj == 'math.cos' # just string, not evaluated
955 ```
957 Serializing an `ImportString` type to json is also possible.
959 ```py
960 from pydantic import BaseModel, ImportString
963 class ImportThings(BaseModel):
964 obj: ImportString
967 # Create an instance
968 m = ImportThings(obj='math.cos')
969 print(m)
970 #> obj=<built-in function cos>
971 print(m.model_dump_json())
972 #> {"obj":"math.cos"}
973 ```
974 """
976 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
977 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
978 return Annotated[item, cls()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
980 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
981 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
982 cls, source: type[Any], handler: GetCoreSchemaHandler
983 ) -> core_schema.CoreSchema:
984 serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
985 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
986 # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any]
987 return core_schema.no_info_plain_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
988 function=_validators.import_string, serialization=serializer
989 )
990 else:
991 return core_schema.no_info_before_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
992 function=_validators.import_string, schema=handler(source), serialization=serializer
993 )
995 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
996 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
997 return handler(core_schema.str_schema()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
999 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1000 def _serialize(v: Any) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1001 if isinstance(v, ModuleType): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1002 return v.__name__ 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1003 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1004 return f'{v.__module__}.{v.__name__}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1005 else:
1006 return v 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1008 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1009 return 'ImportString' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1012# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1015def condecimal( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1016 *,
1017 strict: bool | None = None,
1018 gt: int | Decimal | None = None,
1019 ge: int | Decimal | None = None,
1020 lt: int | Decimal | None = None,
1021 le: int | Decimal | None = None,
1022 multiple_of: int | Decimal | None = None,
1023 max_digits: int | None = None,
1024 decimal_places: int | None = None,
1025 allow_inf_nan: bool | None = None,
1026) -> type[Decimal]:
1027 """
1028 !!! warning "Discouraged"
1029 This function is **discouraged** in favor of using
1030 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
1031 [`Field`][pydantic.fields.Field] instead.
1033 This function will be **deprecated** in Pydantic 3.0.
1035 The reason is that `condecimal` returns a type, which doesn't play well with static analysis tools.
1037 === ":x: Don't do this"
1038 ```py
1039 from pydantic import BaseModel, condecimal
1041 class Foo(BaseModel):
1042 bar: condecimal(strict=True, allow_inf_nan=True)
1043 ```
1045 === ":white_check_mark: Do this"
1046 ```py
1047 from decimal import Decimal
1049 from typing_extensions import Annotated
1051 from pydantic import BaseModel, Field
1053 class Foo(BaseModel):
1054 bar: Annotated[Decimal, Field(strict=True, allow_inf_nan=True)]
1055 ```
1057 A wrapper around Decimal that adds validation.
1059 Args:
1060 strict: Whether to validate the value in strict mode. Defaults to `None`.
1061 gt: The value must be greater than this. Defaults to `None`.
1062 ge: The value must be greater than or equal to this. Defaults to `None`.
1063 lt: The value must be less than this. Defaults to `None`.
1064 le: The value must be less than or equal to this. Defaults to `None`.
1065 multiple_of: The value must be a multiple of this. Defaults to `None`.
1066 max_digits: The maximum number of digits. Defaults to `None`.
1067 decimal_places: The number of decimal places. Defaults to `None`.
1068 allow_inf_nan: Whether to allow infinity and NaN. Defaults to `None`.
1070 ```py
1071 from decimal import Decimal
1073 from pydantic import BaseModel, ValidationError, condecimal
1075 class ConstrainedExample(BaseModel):
1076 constrained_decimal: condecimal(gt=Decimal('1.0'))
1078 m = ConstrainedExample(constrained_decimal=Decimal('1.1'))
1079 print(repr(m))
1080 #> ConstrainedExample(constrained_decimal=Decimal('1.1'))
1082 try:
1083 ConstrainedExample(constrained_decimal=Decimal('0.9'))
1084 except ValidationError as e:
1085 print(e.errors())
1086 '''
1087 [
1088 {
1089 'type': 'greater_than',
1090 'loc': ('constrained_decimal',),
1091 'msg': 'Input should be greater than 1.0',
1092 'input': Decimal('0.9'),
1093 'ctx': {'gt': Decimal('1.0')},
1094 'url': 'https://errors.pydantic.dev/2/v/greater_than',
1095 }
1096 ]
1097 '''
1098 ```
1099 """ # noqa: D212
1100 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1101 Decimal,
1102 Strict(strict) if strict is not None else None,
1103 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
1104 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
1105 _fields.pydantic_general_metadata(max_digits=max_digits, decimal_places=decimal_places),
1106 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None,
1107 ]
1110# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1113@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1114class UuidVersion: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1115 """A field metadata class to indicate a [UUID](https://docs.python.org/3/library/uuid.html) version."""
1117 uuid_version: Literal[1, 3, 4, 5] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1119 def __get_pydantic_json_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1120 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1121 ) -> JsonSchemaValue:
1122 field_schema = handler(core_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1123 field_schema.pop('anyOf', None) # remove the bytes/str union 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1124 field_schema.update(type='string', format=f'uuid{self.uuid_version}') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1125 return field_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1127 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1128 if isinstance(self, source): 1128 ↛ 1130line 1128 didn't jump to line 1130 because the condition on line 1128 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1129 # used directly as a type
1130 return core_schema.uuid_schema(version=self.uuid_version)
1131 else:
1132 # update existing schema with self.uuid_version
1133 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1134 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1135 schema['version'] = self.uuid_version # type: ignore 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1136 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1138 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1139 return hash(type(self.uuid_version)) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1142UUID1 = Annotated[UUID, UuidVersion(1)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1143"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1145```py
1146import uuid
1148from pydantic import UUID1, BaseModel
1150class Model(BaseModel):
1151 uuid1: UUID1
1153Model(uuid1=uuid.uuid1())
1154```
1155"""
1156UUID3 = Annotated[UUID, UuidVersion(3)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1157"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1159```py
1160import uuid
1162from pydantic import UUID3, BaseModel
1164class Model(BaseModel):
1165 uuid3: UUID3
1167Model(uuid3=uuid.uuid3(uuid.NAMESPACE_DNS, 'pydantic.org'))
1168```
1169"""
1170UUID4 = Annotated[UUID, UuidVersion(4)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1171"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1173```py
1174import uuid
1176from pydantic import UUID4, BaseModel
1178class Model(BaseModel):
1179 uuid4: UUID4
1181Model(uuid4=uuid.uuid4())
1182```
1183"""
1184UUID5 = Annotated[UUID, UuidVersion(5)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1185"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1187```py
1188import uuid
1190from pydantic import UUID5, BaseModel
1192class Model(BaseModel):
1193 uuid5: UUID5
1195Model(uuid5=uuid.uuid5(uuid.NAMESPACE_DNS, 'pydantic.org'))
1196```
1197"""
1200# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1203@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1204class PathType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1205 path_type: Literal['file', 'dir', 'new'] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1207 def __get_pydantic_json_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1208 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1209 ) -> JsonSchemaValue:
1210 field_schema = handler(core_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1211 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1212 field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1213 return field_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1215 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1216 function_lookup = { 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1217 'file': cast(core_schema.WithInfoValidatorFunction, self.validate_file),
1218 'dir': cast(core_schema.WithInfoValidatorFunction, self.validate_directory),
1219 'new': cast(core_schema.WithInfoValidatorFunction, self.validate_new),
1220 }
1222 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1223 function_lookup[self.path_type],
1224 handler(source),
1225 )
1227 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1228 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1229 if path.is_file(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1230 return path 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1231 else:
1232 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1234 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1235 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1236 if path.is_dir(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1237 return path 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1238 else:
1239 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1241 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1242 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1243 if path.exists(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1244 raise PydanticCustomError('path_exists', 'Path already exists') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1245 elif not path.parent.exists(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1246 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1247 else:
1248 return path 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1250 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1251 return hash(type(self.path_type)) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1254FilePath = Annotated[Path, PathType('file')] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1255"""A path that must point to a file. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1257```py
1258from pathlib import Path
1260from pydantic import BaseModel, FilePath, ValidationError
1262class Model(BaseModel):
1263 f: FilePath
1265path = Path('text.txt')
1266path.touch()
1267m = Model(f='text.txt')
1268print(m.model_dump())
1269#> {'f': PosixPath('text.txt')}
1270path.unlink()
1272path = Path('directory')
1273path.mkdir(exist_ok=True)
1274try:
1275 Model(f='directory') # directory
1276except ValidationError as e:
1277 print(e)
1278 '''
1279 1 validation error for Model
1280 f
1281 Path does not point to a file [type=path_not_file, input_value='directory', input_type=str]
1282 '''
1283path.rmdir()
1285try:
1286 Model(f='not-exists-file')
1287except ValidationError as e:
1288 print(e)
1289 '''
1290 1 validation error for Model
1291 f
1292 Path does not point to a file [type=path_not_file, input_value='not-exists-file', input_type=str]
1293 '''
1294```
1295"""
1296DirectoryPath = Annotated[Path, PathType('dir')] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1297"""A path that must point to a directory. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1299```py
1300from pathlib import Path
1302from pydantic import BaseModel, DirectoryPath, ValidationError
1304class Model(BaseModel):
1305 f: DirectoryPath
1307path = Path('directory/')
1308path.mkdir()
1309m = Model(f='directory/')
1310print(m.model_dump())
1311#> {'f': PosixPath('directory')}
1312path.rmdir()
1314path = Path('file.txt')
1315path.touch()
1316try:
1317 Model(f='file.txt') # file
1318except ValidationError as e:
1319 print(e)
1320 '''
1321 1 validation error for Model
1322 f
1323 Path does not point to a directory [type=path_not_directory, input_value='file.txt', input_type=str]
1324 '''
1325path.unlink()
1327try:
1328 Model(f='not-exists-directory')
1329except ValidationError as e:
1330 print(e)
1331 '''
1332 1 validation error for Model
1333 f
1334 Path does not point to a directory [type=path_not_directory, input_value='not-exists-directory', input_type=str]
1335 '''
1336```
1337"""
1338NewPath = Annotated[Path, PathType('new')] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1339"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
1342# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1344if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1345 # Json[list[str]] will be recognized by type checkers as list[str]
1346 Json = Annotated[AnyType, ...]
1348else:
1350 class Json: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1351 """A special type wrapper which loads JSON before parsing.
1353 You can use the `Json` data type to make Pydantic first load a raw JSON string before
1354 validating the loaded data into the parametrized type:
1356 ```py
1357 from typing import Any, List
1359 from pydantic import BaseModel, Json, ValidationError
1362 class AnyJsonModel(BaseModel):
1363 json_obj: Json[Any]
1366 class ConstrainedJsonModel(BaseModel):
1367 json_obj: Json[List[int]]
1370 print(AnyJsonModel(json_obj='{"b": 1}'))
1371 #> json_obj={'b': 1}
1372 print(ConstrainedJsonModel(json_obj='[1, 2, 3]'))
1373 #> json_obj=[1, 2, 3]
1375 try:
1376 ConstrainedJsonModel(json_obj=12)
1377 except ValidationError as e:
1378 print(e)
1379 '''
1380 1 validation error for ConstrainedJsonModel
1381 json_obj
1382 JSON input should be string, bytes or bytearray [type=json_type, input_value=12, input_type=int]
1383 '''
1385 try:
1386 ConstrainedJsonModel(json_obj='[a, b]')
1387 except ValidationError as e:
1388 print(e)
1389 '''
1390 1 validation error for ConstrainedJsonModel
1391 json_obj
1392 Invalid JSON: expected value at line 1 column 2 [type=json_invalid, input_value='[a, b]', input_type=str]
1393 '''
1395 try:
1396 ConstrainedJsonModel(json_obj='["a", "b"]')
1397 except ValidationError as e:
1398 print(e)
1399 '''
1400 2 validation errors for ConstrainedJsonModel
1401 json_obj.0
1402 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
1403 json_obj.1
1404 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='b', input_type=str]
1405 '''
1406 ```
1408 When you dump the model using `model_dump` or `model_dump_json`, the dumped value will be the result of validation,
1409 not the original JSON string. However, you can use the argument `round_trip=True` to get the original JSON string back:
1411 ```py
1412 from typing import List
1414 from pydantic import BaseModel, Json
1417 class ConstrainedJsonModel(BaseModel):
1418 json_obj: Json[List[int]]
1421 print(ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json())
1422 #> {"json_obj":[1,2,3]}
1423 print(
1424 ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json(round_trip=True)
1425 )
1426 #> {"json_obj":"[1,2,3]"}
1427 ```
1428 """
1430 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1431 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1432 return Annotated[item, cls()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1434 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1435 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1436 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1437 return core_schema.json_schema(None) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1438 else:
1439 return core_schema.json_schema(handler(source)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1441 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1442 return 'Json' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1444 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1445 return hash(type(self)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1447 def __eq__(self, other: Any) -> bool: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1448 return type(other) == type(self) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1451# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1453SecretType = TypeVar('SecretType') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1456class _SecretBase(Generic[SecretType]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1457 def __init__(self, secret_value: SecretType) -> None: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1458 self._secret_value: SecretType = secret_value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1460 def get_secret_value(self) -> SecretType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1461 """Get the secret value.
1463 Returns:
1464 The secret value.
1465 """
1466 return self._secret_value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1468 def __eq__(self, other: Any) -> bool: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1469 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1471 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1472 return hash(self.get_secret_value()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1474 def __str__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1475 return str(self._display()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1477 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1478 return f'{self.__class__.__name__}({self._display()!r})' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1480 def _display(self) -> str | bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1481 raise NotImplementedError
1484class Secret(_SecretBase[SecretType]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1485 """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks.
1487 You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing
1488 is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both
1489 ways of using `Secret` to create a new secret type.
1491 1. Directly parametrizing `Secret` with a type:
1493 ```py
1494 from pydantic import BaseModel, Secret
1496 SecretBool = Secret[bool]
1498 class Model(BaseModel):
1499 secret_bool: SecretBool
1501 m = Model(secret_bool=True)
1502 print(m.model_dump())
1503 #> {'secret_bool': Secret('**********')}
1505 print(m.model_dump_json())
1506 #> {"secret_bool":"**********"}
1508 print(m.secret_bool.get_secret_value())
1509 #> True
1510 ```
1512 2. Subclassing from parametrized `Secret`:
1514 ```py
1515 from datetime import date
1517 from pydantic import BaseModel, Secret
1519 class SecretDate(Secret[date]):
1520 def _display(self) -> str:
1521 return '****/**/**'
1523 class Model(BaseModel):
1524 secret_date: SecretDate
1526 m = Model(secret_date=date(2022, 1, 1))
1527 print(m.model_dump())
1528 #> {'secret_date': SecretDate('****/**/**')}
1530 print(m.model_dump_json())
1531 #> {"secret_date":"****/**/**"}
1533 print(m.secret_date.get_secret_value())
1534 #> 2022-01-01
1535 ```
1537 The value returned by the `_display` method will be used for `repr()` and `str()`.
1538 """
1540 def _display(self) -> str | bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1541 return '**********' if self.get_secret_value() else '' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1543 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1544 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1545 inner_type = None 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1546 # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly
1547 origin_type = get_origin(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1548 if origin_type is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1549 inner_type = get_args(source)[0] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1550 # otherwise, we need to get the inner type from the base class
1551 else:
1552 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1553 for base in bases: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1554 if get_origin(base) is Secret: 1554 ↛ 1553line 1554 didn't jump to line 1553 because the condition on line 1554 was always true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1555 inner_type = get_args(base)[0] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1556 if bases == [] or inner_type is None: 1556 ↛ 1557line 1556 didn't jump to line 1557 because the condition on line 1556 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1557 raise TypeError(
1558 f"Can't get secret type from {cls.__name__}. "
1559 'Please use Secret[<type>], or subclass from Secret[<type>] instead.'
1560 )
1562 inner_schema = handler.generate_schema(inner_type) # type: ignore 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1564 def validate_secret_value(value, handler) -> Secret[SecretType]: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1565 if isinstance(value, Secret): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1566 value = value.get_secret_value() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1567 validated_inner = handler(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1568 return cls(validated_inner) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1570 def serialize(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1571 if info.mode == 'json': 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1572 return str(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1573 else:
1574 return value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1576 return core_schema.json_or_python_schema( 1576 ↛ exitline 1576 didn't jump to the function exit1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1577 python_schema=core_schema.no_info_wrap_validator_function(
1578 validate_secret_value,
1579 inner_schema,
1580 ),
1581 json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema),
1582 serialization=core_schema.plain_serializer_function_ser_schema(
1583 serialize,
1584 info_arg=True,
1585 when_used='always',
1586 ),
1587 )
1590def _secret_display(value: SecretType) -> str: # type: ignore 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1591 return '**********' if value else '' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1594class _SecretField(_SecretBase[SecretType]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1595 _inner_schema: ClassVar[CoreSchema] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1596 _error_kind: ClassVar[str] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1598 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1599 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1600 def serialize( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1601 value: _SecretField[SecretType], info: core_schema.SerializationInfo
1602 ) -> str | _SecretField[SecretType]:
1603 if info.mode == 'json': 1603 ↛ 1608line 1603 didn't jump to line 1608 because the condition on line 1603 was always true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1604 # we want the output to always be string without the `b'` prefix for bytes,
1605 # hence we just use `secret_display`
1606 return _secret_display(value.get_secret_value()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1607 else:
1608 return value
1610 def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1611 json_schema = handler(cls._inner_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1612 _utils.update_not_none( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1613 json_schema,
1614 type='string',
1615 writeOnly=True,
1616 format='password',
1617 )
1618 return json_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1620 json_schema = core_schema.no_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1621 source, # construct the type
1622 cls._inner_schema,
1623 )
1625 def get_secret_schema(strict: bool) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1626 return core_schema.json_or_python_schema( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1627 python_schema=core_schema.union_schema(
1628 [
1629 core_schema.is_instance_schema(source),
1630 json_schema,
1631 ],
1632 custom_error_type=cls._error_kind,
1633 strict=strict,
1634 ),
1635 json_schema=json_schema,
1636 serialization=core_schema.plain_serializer_function_ser_schema(
1637 serialize,
1638 info_arg=True,
1639 return_schema=core_schema.str_schema(),
1640 when_used='json',
1641 ),
1642 )
1644 return core_schema.lax_or_strict_schema( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1645 lax_schema=get_secret_schema(strict=False),
1646 strict_schema=get_secret_schema(strict=True),
1647 metadata={'pydantic_js_functions': [get_json_schema]},
1648 )
1651class SecretStr(_SecretField[str]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1652 """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1654 When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in
1655 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`.
1657 ```py
1658 from pydantic import BaseModel, SecretStr
1660 class User(BaseModel):
1661 username: str
1662 password: SecretStr
1664 user = User(username='scolvin', password='password1')
1666 print(user)
1667 #> username='scolvin' password=SecretStr('**********')
1668 print(user.password.get_secret_value())
1669 #> password1
1670 print((SecretStr('password'), SecretStr('')))
1671 #> (SecretStr('**********'), SecretStr(''))
1672 ```
1673 """
1675 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1676 _error_kind: ClassVar[str] = 'string_type' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1678 def __len__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1679 return len(self._secret_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1681 def _display(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1682 return _secret_display(self._secret_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1685class SecretBytes(_SecretField[bytes]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1686 """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1688 It displays `b'**********'` instead of the string value on `repr()` and `str()` calls.
1689 When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in
1690 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`.
1692 ```py
1693 from pydantic import BaseModel, SecretBytes
1695 class User(BaseModel):
1696 username: str
1697 password: SecretBytes
1699 user = User(username='scolvin', password=b'password1')
1700 #> username='scolvin' password=SecretBytes(b'**********')
1701 print(user.password.get_secret_value())
1702 #> b'password1'
1703 print((SecretBytes(b'password'), SecretBytes(b'')))
1704 #> (SecretBytes(b'**********'), SecretBytes(b''))
1705 ```
1706 """
1708 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1709 _error_kind: ClassVar[str] = 'bytes_type' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1711 def __len__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1712 return len(self._secret_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1714 def _display(self) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1715 return _secret_display(self._secret_value).encode() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1718# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1721class PaymentCardBrand(str, Enum): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1722 amex = 'American Express' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1723 mastercard = 'Mastercard' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1724 visa = 'Visa' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1725 other = 'other' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1727 def __str__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1728 return self.value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1731@deprecated( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1732 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. '
1733 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.',
1734 category=PydanticDeprecatedSince20,
1735)
1736class PaymentCardNumber(str): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1737 """Based on: https://en.wikipedia.org/wiki/Payment_card_number."""
1739 strip_whitespace: ClassVar[bool] = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1740 min_length: ClassVar[int] = 12 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1741 max_length: ClassVar[int] = 19 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1742 bin: str 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1743 last4: str 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1744 brand: PaymentCardBrand 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1746 def __init__(self, card_number: str): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1747 self.validate_digits(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1749 card_number = self.validate_luhn_check_digit(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1751 self.bin = card_number[:6] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1752 self.last4 = card_number[-4:] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1753 self.brand = self.validate_brand(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1755 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1756 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1757 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1758 cls.validate,
1759 core_schema.str_schema(
1760 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace
1761 ),
1762 )
1764 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1765 def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1766 """Validate the card number and return a `PaymentCardNumber` instance."""
1767 return cls(input_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1769 @property 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1770 def masked(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1771 """Mask all but the last 4 digits of the card number.
1773 Returns:
1774 A masked card number string.
1775 """
1776 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1777 return f'{self.bin}{"*" * num_masked}{self.last4}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1779 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1780 def validate_digits(cls, card_number: str) -> None: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1781 """Validate that the card number is all digits."""
1782 if not card_number.isdigit(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1783 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1785 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1786 def validate_luhn_check_digit(cls, card_number: str) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1787 """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm."""
1788 sum_ = int(card_number[-1]) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1789 length = len(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1790 parity = length % 2 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1791 for i in range(length - 1): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1792 digit = int(card_number[i]) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1793 if i % 2 == parity: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1794 digit *= 2 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1795 if digit > 9: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1796 digit -= 9 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1797 sum_ += digit 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1798 valid = sum_ % 10 == 0 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1799 if not valid: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1800 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1801 return card_number 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1803 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1804 def validate_brand(card_number: str) -> PaymentCardBrand: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1805 """Validate length based on BIN for major brands:
1806 https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN).
1807 """
1808 if card_number[0] == '4': 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1809 brand = PaymentCardBrand.visa 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1810 elif 51 <= int(card_number[:2]) <= 55: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1811 brand = PaymentCardBrand.mastercard 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1812 elif card_number[:2] in {'34', '37'}: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1813 brand = PaymentCardBrand.amex 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1814 else:
1815 brand = PaymentCardBrand.other 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1817 required_length: None | int | str = None 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1818 if brand in PaymentCardBrand.mastercard: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1819 required_length = 16 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1820 valid = len(card_number) == required_length 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1821 elif brand == PaymentCardBrand.visa: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1822 required_length = '13, 16 or 19' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1823 valid = len(card_number) in {13, 16, 19} 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1824 elif brand == PaymentCardBrand.amex: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1825 required_length = 15 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1826 valid = len(card_number) == required_length 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1827 else:
1828 valid = True 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1830 if not valid: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1831 raise PydanticCustomError( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1832 'payment_card_number_brand',
1833 'Length for a {brand} card must be {required_length}',
1834 {'brand': brand, 'required_length': required_length},
1835 )
1836 return brand 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1839# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1842class ByteSize(int): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1843 """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer.
1845 You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into
1846 an integer, and also to print out human-readable strings representing a number of bytes.
1848 In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes,
1849 and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2,
1850 rather than a power of 10 (so, for example, `'1 MB'` is treated as `1_000_000` bytes, whereas `'1 MiB'` is treated as `1_048_576` bytes).
1852 !!! info
1853 Note that `1b` will be parsed as "1 byte" and not "1 bit".
1855 ```py
1856 from pydantic import BaseModel, ByteSize
1858 class MyModel(BaseModel):
1859 size: ByteSize
1861 print(MyModel(size=52000).size)
1862 #> 52000
1863 print(MyModel(size='3000 KiB').size)
1864 #> 3072000
1866 m = MyModel(size='50 PB')
1867 print(m.size.human_readable())
1868 #> 44.4PiB
1869 print(m.size.human_readable(decimal=True))
1870 #> 50.0PB
1871 print(m.size.human_readable(separator=' '))
1872 #> 44.4 PiB
1874 print(m.size.to('TiB'))
1875 #> 45474.73508864641
1876 ```
1877 """
1879 byte_sizes = { 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1880 'b': 1,
1881 'kb': 10**3,
1882 'mb': 10**6,
1883 'gb': 10**9,
1884 'tb': 10**12,
1885 'pb': 10**15,
1886 'eb': 10**18,
1887 'kib': 2**10,
1888 'mib': 2**20,
1889 'gib': 2**30,
1890 'tib': 2**40,
1891 'pib': 2**50,
1892 'eib': 2**60,
1893 'bit': 1 / 8,
1894 'kbit': 10**3 / 8,
1895 'mbit': 10**6 / 8,
1896 'gbit': 10**9 / 8,
1897 'tbit': 10**12 / 8,
1898 'pbit': 10**15 / 8,
1899 'ebit': 10**18 / 8,
1900 'kibit': 2**10 / 8,
1901 'mibit': 2**20 / 8,
1902 'gibit': 2**30 / 8,
1903 'tibit': 2**40 / 8,
1904 'pibit': 2**50 / 8,
1905 'eibit': 2**60 / 8,
1906 }
1907 byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1909 byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1910 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1912 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1913 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1914 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1915 function=cls._validate,
1916 schema=core_schema.union_schema(
1917 [
1918 core_schema.str_schema(pattern=cls.byte_string_pattern),
1919 core_schema.int_schema(ge=0),
1920 ],
1921 custom_error_type='byte_size',
1922 custom_error_message='could not parse value and unit from byte string',
1923 ),
1924 serialization=core_schema.plain_serializer_function_ser_schema(
1925 int, return_schema=core_schema.int_schema(ge=0)
1926 ),
1927 )
1929 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1930 def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1931 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1932 return cls(int(input_value)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1933 except ValueError: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1934 pass 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1936 str_match = cls.byte_string_re.match(str(input_value)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1937 if str_match is None: 1937 ↛ 1938line 1937 didn't jump to line 1938 because the condition on line 1937 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1938 raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string')
1940 scalar, unit = str_match.groups() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1941 if unit is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1942 unit = 'b' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1944 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1945 unit_mult = cls.byte_sizes[unit.lower()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1946 except KeyError: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1947 raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1949 return cls(int(float(scalar) * unit_mult)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1951 def human_readable(self, decimal: bool = False, separator: str = '') -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1952 """Converts a byte size to a human readable string.
1954 Args:
1955 decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units
1956 (e.g. 1024 bytes per KiB).
1957 separator: A string used to split the value and unit. Defaults to an empty string ('').
1959 Returns:
1960 A human readable string representation of the byte size.
1961 """
1962 if decimal: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1963 divisor = 1000 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1964 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1965 final_unit = 'EB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1966 else:
1967 divisor = 1024 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1968 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1969 final_unit = 'EiB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1971 num = float(self) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1972 for unit in units: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1973 if abs(num) < divisor: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1974 if unit == 'B': 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1975 return f'{num:0.0f}{separator}{unit}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1976 else:
1977 return f'{num:0.1f}{separator}{unit}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1978 num /= divisor 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1980 return f'{num:0.1f}{separator}{final_unit}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1982 def to(self, unit: str) -> float: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
1983 """Converts a byte size to another unit, including both byte and bit units.
1985 Args:
1986 unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB,
1987 KiB, MiB, GiB, TiB, PiB, EiB (byte units) and
1988 bit, kbit, mbit, gbit, tbit, pbit, ebit,
1989 kibit, mibit, gibit, tibit, pibit, eibit (bit units).
1991 Returns:
1992 The byte size in the new unit.
1993 """
1994 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1995 unit_div = self.byte_sizes[unit.lower()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1996 except KeyError: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1997 raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
1999 return self / unit_div 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2002# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2005def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2006 if annotated_type != expected_type: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2007 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid_annotated_type') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2010if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2011 PastDate = Annotated[date, ...]
2012 FutureDate = Annotated[date, ...]
2013else:
2015 class PastDate: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2016 """A date in the past."""
2018 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2019 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2020 cls, source: type[Any], handler: GetCoreSchemaHandler
2021 ) -> core_schema.CoreSchema:
2022 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2023 # used directly as a type
2024 return core_schema.date_schema(now_op='past') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2025 else:
2026 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2027 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2028 schema['now_op'] = 'past' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2029 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2031 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2032 return 'PastDate' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2034 class FutureDate: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2035 """A date in the future."""
2037 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2038 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2039 cls, source: type[Any], handler: GetCoreSchemaHandler
2040 ) -> core_schema.CoreSchema:
2041 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2042 # used directly as a type
2043 return core_schema.date_schema(now_op='future') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2044 else:
2045 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2046 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2047 schema['now_op'] = 'future' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2048 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2050 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2051 return 'FutureDate' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2054def condate( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2055 *,
2056 strict: bool | None = None,
2057 gt: date | None = None,
2058 ge: date | None = None,
2059 lt: date | None = None,
2060 le: date | None = None,
2061) -> type[date]:
2062 """A wrapper for date that adds constraints.
2064 Args:
2065 strict: Whether to validate the date value in strict mode. Defaults to `None`.
2066 gt: The value must be greater than this. Defaults to `None`.
2067 ge: The value must be greater than or equal to this. Defaults to `None`.
2068 lt: The value must be less than this. Defaults to `None`.
2069 le: The value must be less than or equal to this. Defaults to `None`.
2071 Returns:
2072 A date type with the specified constraints.
2073 """
2074 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2075 date,
2076 Strict(strict) if strict is not None else None,
2077 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
2078 ]
2081# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2083if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2084 AwareDatetime = Annotated[datetime, ...]
2085 NaiveDatetime = Annotated[datetime, ...]
2086 PastDatetime = Annotated[datetime, ...]
2087 FutureDatetime = Annotated[datetime, ...]
2089else:
2091 class AwareDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2092 """A datetime that requires timezone info."""
2094 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2095 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2096 cls, source: type[Any], handler: GetCoreSchemaHandler
2097 ) -> core_schema.CoreSchema:
2098 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2099 # used directly as a type
2100 return core_schema.datetime_schema(tz_constraint='aware') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2101 else:
2102 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2103 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2104 schema['tz_constraint'] = 'aware' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2105 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2107 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2108 return 'AwareDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2110 class NaiveDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2111 """A datetime that doesn't require timezone info."""
2113 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2114 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2115 cls, source: type[Any], handler: GetCoreSchemaHandler
2116 ) -> core_schema.CoreSchema:
2117 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2118 # used directly as a type
2119 return core_schema.datetime_schema(tz_constraint='naive') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2120 else:
2121 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2122 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2123 schema['tz_constraint'] = 'naive' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2124 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2126 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2127 return 'NaiveDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2129 class PastDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2130 """A datetime that must be in the past."""
2132 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2133 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2134 cls, source: type[Any], handler: GetCoreSchemaHandler
2135 ) -> core_schema.CoreSchema:
2136 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2137 # used directly as a type
2138 return core_schema.datetime_schema(now_op='past') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2139 else:
2140 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2141 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2142 schema['now_op'] = 'past' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2143 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2145 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2146 return 'PastDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2148 class FutureDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2149 """A datetime that must be in the future."""
2151 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2152 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2153 cls, source: type[Any], handler: GetCoreSchemaHandler
2154 ) -> core_schema.CoreSchema:
2155 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2156 # used directly as a type
2157 return core_schema.datetime_schema(now_op='future') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2158 else:
2159 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2160 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2161 schema['now_op'] = 'future' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2162 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2164 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2165 return 'FutureDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2168# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2171class EncoderProtocol(Protocol): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2172 """Protocol for encoding and decoding data to and from bytes.""" 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2174 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2175 def decode(cls, data: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2176 """Decode the data using the encoder.
2178 Args:
2179 data: The data to decode.
2181 Returns:
2182 The decoded data.
2183 """
2184 ...
2186 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2187 def encode(cls, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2188 """Encode the data using the encoder.
2190 Args:
2191 value: The data to encode.
2193 Returns:
2194 The encoded data.
2195 """
2196 ...
2198 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2199 def get_json_format(cls) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2200 """Get the JSON format for the encoded data.
2202 Returns:
2203 The JSON format for the encoded data.
2204 """
2205 ...
2208class Base64Encoder(EncoderProtocol): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2209 """Standard (non-URL-safe) Base64 encoder."""
2211 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2212 def decode(cls, data: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2213 """Decode the data from base64 encoded bytes to original bytes data.
2215 Args:
2216 data: The data to decode.
2218 Returns:
2219 The decoded data.
2220 """
2221 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2222 return base64.decodebytes(data) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2223 except ValueError as e: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2224 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2226 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2227 def encode(cls, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2228 """Encode the data from bytes to a base64 encoded bytes.
2230 Args:
2231 value: The data to encode.
2233 Returns:
2234 The encoded data.
2235 """
2236 return base64.encodebytes(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2238 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2239 def get_json_format(cls) -> Literal['base64']: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2240 """Get the JSON format for the encoded data.
2242 Returns:
2243 The JSON format for the encoded data.
2244 """
2245 return 'base64' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2248class Base64UrlEncoder(EncoderProtocol): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2249 """URL-safe Base64 encoder."""
2251 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2252 def decode(cls, data: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2253 """Decode the data from base64 encoded bytes to original bytes data.
2255 Args:
2256 data: The data to decode.
2258 Returns:
2259 The decoded data.
2260 """
2261 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2262 return base64.urlsafe_b64decode(data) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2263 except ValueError as e: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2264 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2266 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2267 def encode(cls, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2268 """Encode the data from bytes to a base64 encoded bytes.
2270 Args:
2271 value: The data to encode.
2273 Returns:
2274 The encoded data.
2275 """
2276 return base64.urlsafe_b64encode(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2278 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2279 def get_json_format(cls) -> Literal['base64url']: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2280 """Get the JSON format for the encoded data.
2282 Returns:
2283 The JSON format for the encoded data.
2284 """
2285 return 'base64url' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2288@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2289class EncodedBytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2290 """A bytes type that is encoded and decoded using the specified encoder.
2292 `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate.
2294 ```py
2295 from typing_extensions import Annotated
2297 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError
2299 class MyEncoder(EncoderProtocol):
2300 @classmethod
2301 def decode(cls, data: bytes) -> bytes:
2302 if data == b'**undecodable**':
2303 raise ValueError('Cannot decode data')
2304 return data[13:]
2306 @classmethod
2307 def encode(cls, value: bytes) -> bytes:
2308 return b'**encoded**: ' + value
2310 @classmethod
2311 def get_json_format(cls) -> str:
2312 return 'my-encoder'
2314 MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)]
2316 class Model(BaseModel):
2317 my_encoded_bytes: MyEncodedBytes
2319 # Initialize the model with encoded data
2320 m = Model(my_encoded_bytes=b'**encoded**: some bytes')
2322 # Access decoded value
2323 print(m.my_encoded_bytes)
2324 #> b'some bytes'
2326 # Serialize into the encoded form
2327 print(m.model_dump())
2328 #> {'my_encoded_bytes': b'**encoded**: some bytes'}
2330 # Validate encoded data
2331 try:
2332 Model(my_encoded_bytes=b'**undecodable**')
2333 except ValidationError as e:
2334 print(e)
2335 '''
2336 1 validation error for Model
2337 my_encoded_bytes
2338 Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes]
2339 '''
2340 ```
2341 """
2343 encoder: type[EncoderProtocol] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2345 def __get_pydantic_json_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2346 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2347 ) -> JsonSchemaValue:
2348 field_schema = handler(core_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2349 field_schema.update(type='string', format=self.encoder.get_json_format()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2350 return field_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2352 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2353 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2354 function=self.decode,
2355 schema=core_schema.bytes_schema(),
2356 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode),
2357 )
2359 def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2360 """Decode the data using the specified encoder.
2362 Args:
2363 data: The data to decode.
2365 Returns:
2366 The decoded data.
2367 """
2368 return self.encoder.decode(data) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2370 def encode(self, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2371 """Encode the data using the specified encoder.
2373 Args:
2374 value: The data to encode.
2376 Returns:
2377 The encoded data.
2378 """
2379 return self.encoder.encode(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2381 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2382 return hash(self.encoder) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2385@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2386class EncodedStr(EncodedBytes): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2387 """A str type that is encoded and decoded using the specified encoder.
2389 `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate.
2391 ```py
2392 from typing_extensions import Annotated
2394 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError
2396 class MyEncoder(EncoderProtocol):
2397 @classmethod
2398 def decode(cls, data: bytes) -> bytes:
2399 if data == b'**undecodable**':
2400 raise ValueError('Cannot decode data')
2401 return data[13:]
2403 @classmethod
2404 def encode(cls, value: bytes) -> bytes:
2405 return b'**encoded**: ' + value
2407 @classmethod
2408 def get_json_format(cls) -> str:
2409 return 'my-encoder'
2411 MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)]
2413 class Model(BaseModel):
2414 my_encoded_str: MyEncodedStr
2416 # Initialize the model with encoded data
2417 m = Model(my_encoded_str='**encoded**: some str')
2419 # Access decoded value
2420 print(m.my_encoded_str)
2421 #> some str
2423 # Serialize into the encoded form
2424 print(m.model_dump())
2425 #> {'my_encoded_str': '**encoded**: some str'}
2427 # Validate encoded data
2428 try:
2429 Model(my_encoded_str='**undecodable**')
2430 except ValidationError as e:
2431 print(e)
2432 '''
2433 1 validation error for Model
2434 my_encoded_str
2435 Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str]
2436 '''
2437 ```
2438 """
2440 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2441 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2442 function=self.decode_str,
2443 schema=super(EncodedStr, self).__get_pydantic_core_schema__(source=source, handler=handler), # noqa: UP008
2444 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str),
2445 )
2447 def decode_str(self, data: bytes, _: core_schema.ValidationInfo) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2448 """Decode the data using the specified encoder.
2450 Args:
2451 data: The data to decode.
2453 Returns:
2454 The decoded data.
2455 """
2456 return data.decode() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2458 def encode_str(self, value: str) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2459 """Encode the data using the specified encoder.
2461 Args:
2462 value: The data to encode.
2464 Returns:
2465 The encoded data.
2466 """
2467 return super(EncodedStr, self).encode(value=value.encode()).decode() # noqa: UP008 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2469 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2470 return hash(self.encoder) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2473Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2474"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2476Note:
2477 Under the hood, `Base64Bytes` use standard library `base64.encodebytes` and `base64.decodebytes` functions.
2479 As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect
2480 decoding.
2482```py
2483from pydantic import Base64Bytes, BaseModel, ValidationError
2485class Model(BaseModel):
2486 base64_bytes: Base64Bytes
2488# Initialize the model with base64 data
2489m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5')
2491# Access decoded value
2492print(m.base64_bytes)
2493#> b'This is the way'
2495# Serialize into the base64 form
2496print(m.model_dump())
2497#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5\n'}
2499# Validate base64 data
2500try:
2501 print(Model(base64_bytes=b'undecodable').base64_bytes)
2502except ValidationError as e:
2503 print(e)
2504 '''
2505 1 validation error for Model
2506 base64_bytes
2507 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes]
2508 '''
2509```
2510"""
2511Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2512"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2514Note:
2515 Under the hood, `Base64Bytes` use standard library `base64.encodebytes` and `base64.decodebytes` functions.
2517 As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect
2518 decoding.
2520```py
2521from pydantic import Base64Str, BaseModel, ValidationError
2523class Model(BaseModel):
2524 base64_str: Base64Str
2526# Initialize the model with base64 data
2527m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y')
2529# Access decoded value
2530print(m.base64_str)
2531#> These aren't the droids you're looking for
2533# Serialize into the base64 form
2534print(m.model_dump())
2535#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y\n'}
2537# Validate base64 data
2538try:
2539 print(Model(base64_str='undecodable').base64_str)
2540except ValidationError as e:
2541 print(e)
2542 '''
2543 1 validation error for Model
2544 base64_str
2545 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str]
2546 '''
2547```
2548"""
2549Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2550"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2552Note:
2553 Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2554 functions.
2556 As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data
2557 (using `'+'` and `'/'`).
2559```py
2560from pydantic import Base64UrlBytes, BaseModel
2562class Model(BaseModel):
2563 base64url_bytes: Base64UrlBytes
2565# Initialize the model with base64 data
2566m = Model(base64url_bytes=b'SHc_dHc-TXc==')
2567print(m)
2568#> base64url_bytes=b'Hw?tw>Mw'
2569```
2570"""
2571Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2572"""A str type that is encoded and decoded using the URL-safe base64 encoder. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2574Note:
2575 Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2576 functions.
2578 As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`).
2580```py
2581from pydantic import Base64UrlStr, BaseModel
2583class Model(BaseModel):
2584 base64url_str: Base64UrlStr
2586# Initialize the model with base64 data
2587m = Model(base64url_str='SHc_dHc-TXc==')
2588print(m)
2589#> base64url_str='Hw?tw>Mw'
2590```
2591"""
2594__getattr__ = getattr_migration(__name__) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2597@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2598class GetPydanticSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2599 """Usage docs: https://docs.pydantic.dev/2.8/concepts/types/#using-getpydanticschema-to-reduce-boilerplate
2601 A convenience class for creating an annotation that provides pydantic custom type hooks.
2603 This class is intended to eliminate the need to create a custom "marker" which defines the
2604 `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods.
2606 For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do:
2607 ```python
2608 from typing import Any
2610 from typing_extensions import Annotated
2612 from pydantic import BaseModel, GetPydanticSchema
2614 HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any))
2616 class Model(BaseModel):
2617 x: Annotated[int, HandleAsAny] # pydantic sees `x: Any`
2619 print(repr(Model(x='abc').x))
2620 #> 'abc'
2621 ```
2622 """
2624 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2625 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2627 # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:`
2628 # which returns `GetPydanticSchema(lambda _s, h: h(type_))`
2630 if not TYPE_CHECKING: 2630 ↛ 2642line 2630 didn't jump to line 2642 because the condition on line 2630 was always true1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2631 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
2633 def __getattr__(self, item: str) -> Any: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2634 """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls."""
2635 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2636 return self.get_pydantic_core_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2637 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2637 ↛ 2638line 2637 didn't jump to line 2638 because the condition on line 2637 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2638 return self.get_pydantic_json_schema
2639 else:
2640 return object.__getattribute__(self, item) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2642 __hash__ = object.__hash__ 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2645@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2646class Tag: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2647 """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union.
2649 Also provides a way to label a union case in error messages.
2651 When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that
2652 should be used to identify that case. For example, in the below example, the `Tag` is used to specify that
2653 if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it
2654 returns `'pumpkin'`, the input should be validated as a `PumpkinPie`.
2656 The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to
2657 the appropriate member of the `Union` in question.
2659 ```py
2660 from typing import Any, Union
2662 from typing_extensions import Annotated, Literal
2664 from pydantic import BaseModel, Discriminator, Tag
2666 class Pie(BaseModel):
2667 time_to_cook: int
2668 num_ingredients: int
2670 class ApplePie(Pie):
2671 fruit: Literal['apple'] = 'apple'
2673 class PumpkinPie(Pie):
2674 filling: Literal['pumpkin'] = 'pumpkin'
2676 def get_discriminator_value(v: Any) -> str:
2677 if isinstance(v, dict):
2678 return v.get('fruit', v.get('filling'))
2679 return getattr(v, 'fruit', getattr(v, 'filling', None))
2681 class ThanksgivingDinner(BaseModel):
2682 dessert: Annotated[
2683 Union[
2684 Annotated[ApplePie, Tag('apple')],
2685 Annotated[PumpkinPie, Tag('pumpkin')],
2686 ],
2687 Discriminator(get_discriminator_value),
2688 ]
2690 apple_variation = ThanksgivingDinner.model_validate(
2691 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
2692 )
2693 print(repr(apple_variation))
2694 '''
2695 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
2696 '''
2698 pumpkin_variation = ThanksgivingDinner.model_validate(
2699 {
2700 'dessert': {
2701 'filling': 'pumpkin',
2702 'time_to_cook': 40,
2703 'num_ingredients': 6,
2704 }
2705 }
2706 )
2707 print(repr(pumpkin_variation))
2708 '''
2709 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
2710 '''
2711 ```
2713 !!! note
2714 You must specify a `Tag` for every case in a `Tag` that is associated with a
2715 callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code
2716 [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag).
2718 See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s.
2720 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
2721 """
2723 tag: str 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2725 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2726 schema = handler(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2727 metadata = schema.setdefault('metadata', {}) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2728 assert isinstance(metadata, dict) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2729 metadata[_core_utils.TAGGED_UNION_TAG_KEY] = self.tag 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2730 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2733@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2734class Discriminator: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2735 """Usage docs: https://docs.pydantic.dev/2.8/concepts/unions/#discriminated-unions-with-callable-discriminator
2737 Provides a way to use a custom callable as the way to extract the value of a union discriminator.
2739 This allows you to get validation behavior like you'd get from `Field(discriminator=<field_name>)`,
2740 but without needing to have a single shared field across all the union choices. This also makes it
2741 possible to handle unions of models and primitive types with discriminated-union-style validation errors.
2742 Finally, this allows you to use a custom callable as the way to identify which member of a union a value
2743 belongs to, while still seeing all the performance benefits of a discriminated union.
2745 Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion`
2746 than it would be as a normal `Union`.
2748 ```py
2749 from typing import Any, Union
2751 from typing_extensions import Annotated, Literal
2753 from pydantic import BaseModel, Discriminator, Tag
2755 class Pie(BaseModel):
2756 time_to_cook: int
2757 num_ingredients: int
2759 class ApplePie(Pie):
2760 fruit: Literal['apple'] = 'apple'
2762 class PumpkinPie(Pie):
2763 filling: Literal['pumpkin'] = 'pumpkin'
2765 def get_discriminator_value(v: Any) -> str:
2766 if isinstance(v, dict):
2767 return v.get('fruit', v.get('filling'))
2768 return getattr(v, 'fruit', getattr(v, 'filling', None))
2770 class ThanksgivingDinner(BaseModel):
2771 dessert: Annotated[
2772 Union[
2773 Annotated[ApplePie, Tag('apple')],
2774 Annotated[PumpkinPie, Tag('pumpkin')],
2775 ],
2776 Discriminator(get_discriminator_value),
2777 ]
2779 apple_variation = ThanksgivingDinner.model_validate(
2780 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
2781 )
2782 print(repr(apple_variation))
2783 '''
2784 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
2785 '''
2787 pumpkin_variation = ThanksgivingDinner.model_validate(
2788 {
2789 'dessert': {
2790 'filling': 'pumpkin',
2791 'time_to_cook': 40,
2792 'num_ingredients': 6,
2793 }
2794 }
2795 )
2796 print(repr(pumpkin_variation))
2797 '''
2798 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
2799 '''
2800 ```
2802 See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s.
2804 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
2805 """
2807 discriminator: str | Callable[[Any], Hashable] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2808 """The callable or field name for discriminating the type in a tagged union. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2810 A `Callable` discriminator must extract the value of the discriminator from the input.
2811 A `str` discriminator must be the name of a field to discriminate against.
2812 """
2813 custom_error_type: str | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2814 """Type to use in [custom errors](../errors/errors.md#custom-errors) replacing the standard discriminated union 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2815 validation errors.
2816 """
2817 custom_error_message: str | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2818 """Message to use in custom errors.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2819 custom_error_context: dict[str, int | str | float] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2820 """Context to use in custom errors.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
2822 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2823 origin = _typing_extra.get_origin(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2824 if not origin or not _typing_extra.origin_is_union(origin): 2824 ↛ 2825line 2824 didn't jump to line 2825 because the condition on line 2824 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2825 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}')
2827 if isinstance(self.discriminator, str): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2828 from pydantic import Field 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2830 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2831 else:
2832 original_schema = handler(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2833 return self._convert_schema(original_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2835 def _convert_schema(self, original_schema: core_schema.CoreSchema) -> core_schema.TaggedUnionSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2836 if original_schema['type'] != 'union': 2836 ↛ 2841line 2836 didn't jump to line 2841 because the condition on line 2836 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2837 # This likely indicates that the schema was a single-item union that was simplified.
2838 # In this case, we do the same thing we do in
2839 # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely,
2840 # package the generated schema back into a single-item union.
2841 original_schema = core_schema.union_schema([original_schema])
2843 tagged_union_choices = {} 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2844 for i, choice in enumerate(original_schema['choices']): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2845 tag = None 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2846 if isinstance(choice, tuple): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2847 choice, tag = choice 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2848 metadata = choice.get('metadata') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2849 if metadata is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2850 metadata_tag = metadata.get(_core_utils.TAGGED_UNION_TAG_KEY) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2851 if metadata_tag is not None: 2851 ↛ 2853line 2851 didn't jump to line 2853 because the condition on line 2851 was always true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2852 tag = metadata_tag 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2853 if tag is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2854 raise PydanticUserError( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2855 f'`Tag` not provided for choice {choice} used with `Discriminator`',
2856 code='callable-discriminator-no-tag',
2857 )
2858 tagged_union_choices[tag] = choice 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2860 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored
2861 custom_error_type = self.custom_error_type 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2862 if custom_error_type is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2863 custom_error_type = original_schema.get('custom_error_type') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2865 custom_error_message = self.custom_error_message 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2866 if custom_error_message is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2867 custom_error_message = original_schema.get('custom_error_message') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2869 custom_error_context = self.custom_error_context 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2870 if custom_error_context is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2871 custom_error_context = original_schema.get('custom_error_context') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2873 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2874 return core_schema.tagged_union_schema( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2875 tagged_union_choices,
2876 self.discriminator,
2877 custom_error_type=custom_error_type,
2878 custom_error_message=custom_error_message,
2879 custom_error_context=custom_error_context,
2880 strict=original_schema.get('strict'),
2881 ref=original_schema.get('ref'),
2882 metadata=original_schema.get('metadata'),
2883 serialization=original_schema.get('serialization'),
2884 )
2887_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2890def _get_type_name(x: Any) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2891 type_ = type(x) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2892 if type_ in _JSON_TYPES: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2893 return type_.__name__ 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2895 # Handle proper subclasses; note we don't need to handle None or bool here
2896 if isinstance(x, int): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2897 return 'int' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2898 if isinstance(x, float): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2899 return 'float' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2900 if isinstance(x, str): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2901 return 'str' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2902 if isinstance(x, list): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2903 return 'list' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2904 if isinstance(x, dict): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2905 return 'dict' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2907 # Fail by returning the type's actual name
2908 return getattr(type_, '__name__', '<no type name>') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2911class _AllowAnyJson: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2912 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2913 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2914 python_schema = handler(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2915 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
2918if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2919 # This seems to only be necessary for mypy
2920 JsonValue: TypeAlias = Union[
2921 List['JsonValue'],
2922 Dict[str, 'JsonValue'],
2923 str,
2924 bool,
2925 int,
2926 float,
2927 None,
2928 ]
2929 """A `JsonValue` is used to represent a value that can be serialized to JSON.
2931 It may be one of:
2933 * `List['JsonValue']`
2934 * `Dict[str, 'JsonValue']`
2935 * `str`
2936 * `bool`
2937 * `int`
2938 * `float`
2939 * `None`
2941 The following example demonstrates how to use `JsonValue` to validate JSON data,
2942 and what kind of errors to expect when input data is not json serializable.
2944 ```py
2945 import json
2947 from pydantic import BaseModel, JsonValue, ValidationError
2949 class Model(BaseModel):
2950 j: JsonValue
2952 valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}}
2953 invalid_json_data = {'j': {'a': {'b': ...}}}
2955 print(repr(Model.model_validate(valid_json_data)))
2956 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
2957 print(repr(Model.model_validate_json(json.dumps(valid_json_data))))
2958 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
2960 try:
2961 Model.model_validate(invalid_json_data)
2962 except ValidationError as e:
2963 print(e)
2964 '''
2965 1 validation error for Model
2966 j.dict.a.dict.b
2967 input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis]
2968 '''
2969 ```
2970 """
2972else:
2973 JsonValue = TypeAliasType( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2974 'JsonValue',
2975 Annotated[
2976 Union[
2977 Annotated[List['JsonValue'], Tag('list')],
2978 Annotated[Dict[str, 'JsonValue'], Tag('dict')],
2979 Annotated[str, Tag('str')],
2980 Annotated[bool, Tag('bool')],
2981 Annotated[int, Tag('int')],
2982 Annotated[float, Tag('float')],
2983 Annotated[None, Tag('NoneType')],
2984 ],
2985 Discriminator(
2986 _get_type_name,
2987 custom_error_type='invalid-json-value',
2988 custom_error_message='input was not a valid JSON value',
2989 ),
2990 _AllowAnyJson,
2991 ],
2992 )
2995class _OnErrorOmit: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2996 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2997 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
2998 # there is no actual default value here but we use with_default_schema since it already has the on_error
2999 # behavior implemented and it would be no more efficient to implement it on every other validator
3000 # or as a standalone validator
3001 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy
3004OnErrorOmit = Annotated[T, _OnErrorOmit] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
3005""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy
3006When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc.
3007this annotation omits the item from the iteration if there is any error validating it.
3008That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded
3009any invalid items are discarded and the valid ones are returned.
3010"""
3013@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
3014class FailFast(_fields.PydanticMetadata, BaseMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy
3015 """A `FailFast` annotation can be used to specify that validation should stop at the first error.
3017 This can be useful when you want to validate a large amount of data and you only need to know if it's valid or not.
3019 You might want to enable this setting if you want to validate your data faster (basically, if you use this,
3020 validation will be more performant with the caveat that you get less information).
3022 ```py
3023 from typing import List
3024 from typing_extensions import Annotated
3025 from pydantic import BaseModel, FailFast, ValidationError
3027 class Model(BaseModel):
3028 x: Annotated[List[int], FailFast()]
3030 # This will raise a single error for the first invalid value and stop validation
3031 try:
3032 obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c'])
3033 except ValidationError as e:
3034 print(e)
3035 '''
3036 1 validation error for Model
3037 x.2
3038 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
3039 '''
3040 ```
3041 """
3043 fail_fast: bool = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy