Coverage for pydantic/types.py: 97.64%
660 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-16 14:56 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-16 14:56 +0000
1"""The types module contains custom types used by pydantic."""
3from __future__ import annotations as _annotations 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
5import base64 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
6import dataclasses as _dataclasses 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
7import re 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
8from collections.abc import Hashable, Iterator 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
9from datetime import date, datetime 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
10from decimal import Decimal 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
11from enum import Enum 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
12from pathlib import Path 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
13from re import Pattern 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
14from types import ModuleType 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
15from typing import ( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
16 TYPE_CHECKING,
17 Annotated,
18 Any,
19 Callable,
20 ClassVar,
21 Generic,
22 Literal,
23 TypeVar,
24 Union,
25 cast,
26)
27from uuid import UUID 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
29import annotated_types 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
30from annotated_types import BaseMetadata, MaxLen, MinLen 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
31from pydantic_core import CoreSchema, PydanticCustomError, SchemaSerializer, core_schema 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
32from typing_extensions import Protocol, TypeAlias, TypeAliasType, deprecated, get_args, get_origin 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
33from typing_inspection.introspection import is_union_origin 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
35from ._internal import _fields, _internal_dataclass, _utils, _validators 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
36from ._migration import getattr_migration 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
37from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
38from .errors import PydanticUserError 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
39from .json_schema import JsonSchemaValue 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
40from .warnings import PydanticDeprecatedSince20 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
42if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
43 from ._internal._core_metadata import CoreMetadata
45__all__ = ( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
46 'Strict',
47 'StrictStr',
48 'SocketPath',
49 'conbytes',
50 'conlist',
51 'conset',
52 'confrozenset',
53 'constr',
54 'ImportString',
55 'conint',
56 'PositiveInt',
57 'NegativeInt',
58 'NonNegativeInt',
59 'NonPositiveInt',
60 'confloat',
61 'PositiveFloat',
62 'NegativeFloat',
63 'NonNegativeFloat',
64 'NonPositiveFloat',
65 'FiniteFloat',
66 'condecimal',
67 'UUID1',
68 'UUID3',
69 'UUID4',
70 'UUID5',
71 'UUID6',
72 'UUID7',
73 'UUID8',
74 'FilePath',
75 'DirectoryPath',
76 'NewPath',
77 'Json',
78 'Secret',
79 'SecretStr',
80 'SecretBytes',
81 'StrictBool',
82 'StrictBytes',
83 'StrictInt',
84 'StrictFloat',
85 'PaymentCardNumber',
86 'ByteSize',
87 'PastDate',
88 'FutureDate',
89 'PastDatetime',
90 'FutureDatetime',
91 'condate',
92 'AwareDatetime',
93 'NaiveDatetime',
94 'AllowInfNan',
95 'EncoderProtocol',
96 'EncodedBytes',
97 'EncodedStr',
98 'Base64Encoder',
99 'Base64Bytes',
100 'Base64Str',
101 'Base64UrlBytes',
102 'Base64UrlStr',
103 'GetPydanticSchema',
104 'StringConstraints',
105 'Tag',
106 'Discriminator',
107 'JsonValue',
108 'OnErrorOmit',
109 'FailFast',
110)
113T = TypeVar('T') 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
116@_dataclasses.dataclass 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
117class Strict(_fields.PydanticMetadata, BaseMetadata): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
118 """!!! abstract "Usage Documentation"
119 [Strict Mode with `Annotated` `Strict`](../concepts/strict_mode.md#strict-mode-with-annotated-strict)
121 A field metadata class to indicate that a field should be validated in strict mode.
122 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
124 Attributes:
125 strict: Whether to validate the field in strict mode.
127 Example:
128 ```python
129 from typing import Annotated
131 from pydantic.types import Strict
133 StrictBool = Annotated[bool, Strict()]
134 ```
135 """
137 strict: bool = True 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
139 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
140 return hash(self.strict) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
143# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145StrictBool = Annotated[bool, Strict()] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
146"""A boolean that must be either ``True`` or ``False``.""" 1abcdefghijklmnopqrsJtuvwxyzAB
148# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151def conint( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
152 *,
153 strict: bool | None = None,
154 gt: int | None = None,
155 ge: int | None = None,
156 lt: int | None = None,
157 le: int | None = None,
158 multiple_of: int | None = None,
159) -> type[int]:
160 """
161 !!! warning "Discouraged"
162 This function is **discouraged** in favor of using
163 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
164 [`Field`][pydantic.fields.Field] instead.
166 This function will be **deprecated** in Pydantic 3.0.
168 The reason is that `conint` returns a type, which doesn't play well with static analysis tools.
170 === ":x: Don't do this"
171 ```python
172 from pydantic import BaseModel, conint
174 class Foo(BaseModel):
175 bar: conint(strict=True, gt=0)
176 ```
178 === ":white_check_mark: Do this"
179 ```python
180 from typing import Annotated
182 from pydantic import BaseModel, Field
184 class Foo(BaseModel):
185 bar: Annotated[int, Field(strict=True, gt=0)]
186 ```
188 A wrapper around `int` that allows for additional constraints.
190 Args:
191 strict: Whether to validate the integer in strict mode. Defaults to `None`.
192 gt: The value must be greater than this.
193 ge: The value must be greater than or equal to this.
194 lt: The value must be less than this.
195 le: The value must be less than or equal to this.
196 multiple_of: The value must be a multiple of this.
198 Returns:
199 The wrapped integer type.
201 ```python
202 from pydantic import BaseModel, ValidationError, conint
204 class ConstrainedExample(BaseModel):
205 constrained_int: conint(gt=1)
207 m = ConstrainedExample(constrained_int=2)
208 print(repr(m))
209 #> ConstrainedExample(constrained_int=2)
211 try:
212 ConstrainedExample(constrained_int=0)
213 except ValidationError as e:
214 print(e.errors())
215 '''
216 [
217 {
218 'type': 'greater_than',
219 'loc': ('constrained_int',),
220 'msg': 'Input should be greater than 1',
221 'input': 0,
222 'ctx': {'gt': 1},
223 'url': 'https://errors.pydantic.dev/2/v/greater_than',
224 }
225 ]
226 '''
227 ```
229 """ # noqa: D212
230 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
231 int,
232 Strict(strict) if strict is not None else None,
233 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
234 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
235 ]
238PositiveInt = Annotated[int, annotated_types.Gt(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
239"""An integer that must be greater than zero. 1abcdefghijklmnopqrsJtuvwxyzAB
241```python
242from pydantic import BaseModel, PositiveInt, ValidationError
244class Model(BaseModel):
245 positive_int: PositiveInt
247m = Model(positive_int=1)
248print(repr(m))
249#> Model(positive_int=1)
251try:
252 Model(positive_int=-1)
253except ValidationError as e:
254 print(e.errors())
255 '''
256 [
257 {
258 'type': 'greater_than',
259 'loc': ('positive_int',),
260 'msg': 'Input should be greater than 0',
261 'input': -1,
262 'ctx': {'gt': 0},
263 'url': 'https://errors.pydantic.dev/2/v/greater_than',
264 }
265 ]
266 '''
267```
268"""
269NegativeInt = Annotated[int, annotated_types.Lt(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
270"""An integer that must be less than zero. 1abcdefghijklmnopqrsJtuvwxyzAB
272```python
273from pydantic import BaseModel, NegativeInt, ValidationError
275class Model(BaseModel):
276 negative_int: NegativeInt
278m = Model(negative_int=-1)
279print(repr(m))
280#> Model(negative_int=-1)
282try:
283 Model(negative_int=1)
284except ValidationError as e:
285 print(e.errors())
286 '''
287 [
288 {
289 'type': 'less_than',
290 'loc': ('negative_int',),
291 'msg': 'Input should be less than 0',
292 'input': 1,
293 'ctx': {'lt': 0},
294 'url': 'https://errors.pydantic.dev/2/v/less_than',
295 }
296 ]
297 '''
298```
299"""
300NonPositiveInt = Annotated[int, annotated_types.Le(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
301"""An integer that must be less than or equal to zero. 1abcdefghijklmnopqrsJtuvwxyzAB
303```python
304from pydantic import BaseModel, NonPositiveInt, ValidationError
306class Model(BaseModel):
307 non_positive_int: NonPositiveInt
309m = Model(non_positive_int=0)
310print(repr(m))
311#> Model(non_positive_int=0)
313try:
314 Model(non_positive_int=1)
315except ValidationError as e:
316 print(e.errors())
317 '''
318 [
319 {
320 'type': 'less_than_equal',
321 'loc': ('non_positive_int',),
322 'msg': 'Input should be less than or equal to 0',
323 'input': 1,
324 'ctx': {'le': 0},
325 'url': 'https://errors.pydantic.dev/2/v/less_than_equal',
326 }
327 ]
328 '''
329```
330"""
331NonNegativeInt = Annotated[int, annotated_types.Ge(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
332"""An integer that must be greater than or equal to zero. 1abcdefghijklmnopqrsJtuvwxyzAB
334```python
335from pydantic import BaseModel, NonNegativeInt, ValidationError
337class Model(BaseModel):
338 non_negative_int: NonNegativeInt
340m = Model(non_negative_int=0)
341print(repr(m))
342#> Model(non_negative_int=0)
344try:
345 Model(non_negative_int=-1)
346except ValidationError as e:
347 print(e.errors())
348 '''
349 [
350 {
351 'type': 'greater_than_equal',
352 'loc': ('non_negative_int',),
353 'msg': 'Input should be greater than or equal to 0',
354 'input': -1,
355 'ctx': {'ge': 0},
356 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal',
357 }
358 ]
359 '''
360```
361"""
362StrictInt = Annotated[int, Strict()] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
363"""An integer that must be validated in strict mode. 1abcdefghijklmnopqrsJtuvwxyzAB
365```python
366from pydantic import BaseModel, StrictInt, ValidationError
368class StrictIntModel(BaseModel):
369 strict_int: StrictInt
371try:
372 StrictIntModel(strict_int=3.14159)
373except ValidationError as e:
374 print(e)
375 '''
376 1 validation error for StrictIntModel
377 strict_int
378 Input should be a valid integer [type=int_type, input_value=3.14159, input_type=float]
379 '''
380```
381"""
383# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
386@_dataclasses.dataclass 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
387class AllowInfNan(_fields.PydanticMetadata): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
388 """A field metadata class to indicate that a field should allow `-inf`, `inf`, and `nan`.
390 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
392 Attributes:
393 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. Defaults to `True`.
395 Example:
396 ```python
397 from typing import Annotated
399 from pydantic.types import AllowInfNan
401 LaxFloat = Annotated[float, AllowInfNan()]
402 ```
403 """
405 allow_inf_nan: bool = True 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
407 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
408 return hash(self.allow_inf_nan) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
411def confloat( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
412 *,
413 strict: bool | None = None,
414 gt: float | None = None,
415 ge: float | None = None,
416 lt: float | None = None,
417 le: float | None = None,
418 multiple_of: float | None = None,
419 allow_inf_nan: bool | None = None,
420) -> type[float]:
421 """
422 !!! warning "Discouraged"
423 This function is **discouraged** in favor of using
424 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
425 [`Field`][pydantic.fields.Field] instead.
427 This function will be **deprecated** in Pydantic 3.0.
429 The reason is that `confloat` returns a type, which doesn't play well with static analysis tools.
431 === ":x: Don't do this"
432 ```python
433 from pydantic import BaseModel, confloat
435 class Foo(BaseModel):
436 bar: confloat(strict=True, gt=0)
437 ```
439 === ":white_check_mark: Do this"
440 ```python
441 from typing import Annotated
443 from pydantic import BaseModel, Field
445 class Foo(BaseModel):
446 bar: Annotated[float, Field(strict=True, gt=0)]
447 ```
449 A wrapper around `float` that allows for additional constraints.
451 Args:
452 strict: Whether to validate the float in strict mode.
453 gt: The value must be greater than this.
454 ge: The value must be greater than or equal to this.
455 lt: The value must be less than this.
456 le: The value must be less than or equal to this.
457 multiple_of: The value must be a multiple of this.
458 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`.
460 Returns:
461 The wrapped float type.
463 ```python
464 from pydantic import BaseModel, ValidationError, confloat
466 class ConstrainedExample(BaseModel):
467 constrained_float: confloat(gt=1.0)
469 m = ConstrainedExample(constrained_float=1.1)
470 print(repr(m))
471 #> ConstrainedExample(constrained_float=1.1)
473 try:
474 ConstrainedExample(constrained_float=0.9)
475 except ValidationError as e:
476 print(e.errors())
477 '''
478 [
479 {
480 'type': 'greater_than',
481 'loc': ('constrained_float',),
482 'msg': 'Input should be greater than 1',
483 'input': 0.9,
484 'ctx': {'gt': 1.0},
485 'url': 'https://errors.pydantic.dev/2/v/greater_than',
486 }
487 ]
488 '''
489 ```
490 """ # noqa: D212
491 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
492 float,
493 Strict(strict) if strict is not None else None,
494 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
495 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
496 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None,
497 ]
500PositiveFloat = Annotated[float, annotated_types.Gt(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
501"""A float that must be greater than zero. 1abcdefghijklmnopqrsJtuvwxyzAB
503```python
504from pydantic import BaseModel, PositiveFloat, ValidationError
506class Model(BaseModel):
507 positive_float: PositiveFloat
509m = Model(positive_float=1.0)
510print(repr(m))
511#> Model(positive_float=1.0)
513try:
514 Model(positive_float=-1.0)
515except ValidationError as e:
516 print(e.errors())
517 '''
518 [
519 {
520 'type': 'greater_than',
521 'loc': ('positive_float',),
522 'msg': 'Input should be greater than 0',
523 'input': -1.0,
524 'ctx': {'gt': 0.0},
525 'url': 'https://errors.pydantic.dev/2/v/greater_than',
526 }
527 ]
528 '''
529```
530"""
531NegativeFloat = Annotated[float, annotated_types.Lt(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
532"""A float that must be less than zero. 1abcdefghijklmnopqrsJtuvwxyzAB
534```python
535from pydantic import BaseModel, NegativeFloat, ValidationError
537class Model(BaseModel):
538 negative_float: NegativeFloat
540m = Model(negative_float=-1.0)
541print(repr(m))
542#> Model(negative_float=-1.0)
544try:
545 Model(negative_float=1.0)
546except ValidationError as e:
547 print(e.errors())
548 '''
549 [
550 {
551 'type': 'less_than',
552 'loc': ('negative_float',),
553 'msg': 'Input should be less than 0',
554 'input': 1.0,
555 'ctx': {'lt': 0.0},
556 'url': 'https://errors.pydantic.dev/2/v/less_than',
557 }
558 ]
559 '''
560```
561"""
562NonPositiveFloat = Annotated[float, annotated_types.Le(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
563"""A float that must be less than or equal to zero. 1abcdefghijklmnopqrsJtuvwxyzAB
565```python
566from pydantic import BaseModel, NonPositiveFloat, ValidationError
568class Model(BaseModel):
569 non_positive_float: NonPositiveFloat
571m = Model(non_positive_float=0.0)
572print(repr(m))
573#> Model(non_positive_float=0.0)
575try:
576 Model(non_positive_float=1.0)
577except ValidationError as e:
578 print(e.errors())
579 '''
580 [
581 {
582 'type': 'less_than_equal',
583 'loc': ('non_positive_float',),
584 'msg': 'Input should be less than or equal to 0',
585 'input': 1.0,
586 'ctx': {'le': 0.0},
587 'url': 'https://errors.pydantic.dev/2/v/less_than_equal',
588 }
589 ]
590 '''
591```
592"""
593NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
594"""A float that must be greater than or equal to zero. 1abcdefghijklmnopqrsJtuvwxyzAB
596```python
597from pydantic import BaseModel, NonNegativeFloat, ValidationError
599class Model(BaseModel):
600 non_negative_float: NonNegativeFloat
602m = Model(non_negative_float=0.0)
603print(repr(m))
604#> Model(non_negative_float=0.0)
606try:
607 Model(non_negative_float=-1.0)
608except ValidationError as e:
609 print(e.errors())
610 '''
611 [
612 {
613 'type': 'greater_than_equal',
614 'loc': ('non_negative_float',),
615 'msg': 'Input should be greater than or equal to 0',
616 'input': -1.0,
617 'ctx': {'ge': 0.0},
618 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal',
619 }
620 ]
621 '''
622```
623"""
624StrictFloat = Annotated[float, Strict(True)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
625"""A float that must be validated in strict mode. 1abcdefghijklmnopqrsJtuvwxyzAB
627```python
628from pydantic import BaseModel, StrictFloat, ValidationError
630class StrictFloatModel(BaseModel):
631 strict_float: StrictFloat
633try:
634 StrictFloatModel(strict_float='1.0')
635except ValidationError as e:
636 print(e)
637 '''
638 1 validation error for StrictFloatModel
639 strict_float
640 Input should be a valid number [type=float_type, input_value='1.0', input_type=str]
641 '''
642```
643"""
644FiniteFloat = Annotated[float, AllowInfNan(False)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
645"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). 1abcdefghijklmnopqrsJtuvwxyzAB
647```python
648from pydantic import BaseModel, FiniteFloat
650class Model(BaseModel):
651 finite: FiniteFloat
653m = Model(finite=1.0)
654print(m)
655#> finite=1.0
656```
657"""
660# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
663def conbytes( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
664 *,
665 min_length: int | None = None,
666 max_length: int | None = None,
667 strict: bool | None = None,
668) -> type[bytes]:
669 """A wrapper around `bytes` that allows for additional constraints.
671 Args:
672 min_length: The minimum length of the bytes.
673 max_length: The maximum length of the bytes.
674 strict: Whether to validate the bytes in strict mode.
676 Returns:
677 The wrapped bytes type.
678 """
679 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
680 bytes,
681 Strict(strict) if strict is not None else None,
682 annotated_types.Len(min_length or 0, max_length),
683 ]
686StrictBytes = Annotated[bytes, Strict()] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
687"""A bytes that must be validated in strict mode.""" 1abcdefghijklmnopqrsJtuvwxyzAB
690# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
693@_dataclasses.dataclass(frozen=True) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
694class StringConstraints(annotated_types.GroupedMetadata): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
695 """!!! abstract "Usage Documentation"
696 [`StringConstraints`](../concepts/fields.md#string-constraints)
698 A field metadata class to apply constraints to `str` types.
699 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
701 Attributes:
702 strip_whitespace: Whether to remove leading and trailing whitespace.
703 to_upper: Whether to convert the string to uppercase.
704 to_lower: Whether to convert the string to lowercase.
705 strict: Whether to validate the string in strict mode.
706 min_length: The minimum length of the string.
707 max_length: The maximum length of the string.
708 pattern: A regex pattern that the string must match.
710 Example:
711 ```python
712 from typing import Annotated
714 from pydantic.types import StringConstraints
716 ConstrainedStr = Annotated[str, StringConstraints(min_length=1, max_length=10)]
717 ```
718 """
720 strip_whitespace: bool | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
721 to_upper: bool | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
722 to_lower: bool | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
723 strict: bool | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
724 min_length: int | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
725 max_length: int | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
726 pattern: str | Pattern[str] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
728 def __iter__(self) -> Iterator[BaseMetadata]: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
729 if self.min_length is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
730 yield MinLen(self.min_length) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
731 if self.max_length is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
732 yield MaxLen(self.max_length) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
733 if self.strict is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
734 yield Strict(self.strict) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
735 if ( 1CDEj
736 self.strip_whitespace is not None
737 or self.pattern is not None
738 or self.to_lower is not None
739 or self.to_upper is not None
740 ):
741 yield _fields.pydantic_general_metadata( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
742 strip_whitespace=self.strip_whitespace,
743 to_upper=self.to_upper,
744 to_lower=self.to_lower,
745 pattern=self.pattern,
746 )
749def constr( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
750 *,
751 strip_whitespace: bool | None = None,
752 to_upper: bool | None = None,
753 to_lower: bool | None = None,
754 strict: bool | None = None,
755 min_length: int | None = None,
756 max_length: int | None = None,
757 pattern: str | Pattern[str] | None = None,
758) -> type[str]:
759 """
760 !!! warning "Discouraged"
761 This function is **discouraged** in favor of using
762 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
763 [`StringConstraints`][pydantic.types.StringConstraints] instead.
765 This function will be **deprecated** in Pydantic 3.0.
767 The reason is that `constr` returns a type, which doesn't play well with static analysis tools.
769 === ":x: Don't do this"
770 ```python
771 from pydantic import BaseModel, constr
773 class Foo(BaseModel):
774 bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$')
775 ```
777 === ":white_check_mark: Do this"
778 ```python
779 from typing import Annotated
781 from pydantic import BaseModel, StringConstraints
783 class Foo(BaseModel):
784 bar: Annotated[
785 str,
786 StringConstraints(
787 strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$'
788 ),
789 ]
790 ```
792 A wrapper around `str` that allows for additional constraints.
794 ```python
795 from pydantic import BaseModel, constr
797 class Foo(BaseModel):
798 bar: constr(strip_whitespace=True, to_upper=True)
800 foo = Foo(bar=' hello ')
801 print(foo)
802 #> bar='HELLO'
803 ```
805 Args:
806 strip_whitespace: Whether to remove leading and trailing whitespace.
807 to_upper: Whether to turn all characters to uppercase.
808 to_lower: Whether to turn all characters to lowercase.
809 strict: Whether to validate the string in strict mode.
810 min_length: The minimum length of the string.
811 max_length: The maximum length of the string.
812 pattern: A regex pattern to validate the string against.
814 Returns:
815 The wrapped string type.
816 """ # noqa: D212
817 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
818 str,
819 StringConstraints(
820 strip_whitespace=strip_whitespace,
821 to_upper=to_upper,
822 to_lower=to_lower,
823 strict=strict,
824 min_length=min_length,
825 max_length=max_length,
826 pattern=pattern,
827 ),
828 ]
831StrictStr = Annotated[str, Strict()] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
832"""A string that must be validated in strict mode.""" 1abcdefghijklmnopqrsJtuvwxyzAB
835# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
836HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
839def conset( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
840 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None
841) -> type[set[HashableItemType]]:
842 """A wrapper around `typing.Set` that allows for additional constraints.
844 Args:
845 item_type: The type of the items in the set.
846 min_length: The minimum length of the set.
847 max_length: The maximum length of the set.
849 Returns:
850 The wrapped set type.
851 """
852 return Annotated[set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
855def confrozenset( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
856 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None
857) -> type[frozenset[HashableItemType]]:
858 """A wrapper around `typing.FrozenSet` that allows for additional constraints.
860 Args:
861 item_type: The type of the items in the frozenset.
862 min_length: The minimum length of the frozenset.
863 max_length: The maximum length of the frozenset.
865 Returns:
866 The wrapped frozenset type.
867 """
868 return Annotated[frozenset[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
871AnyItemType = TypeVar('AnyItemType') 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
874def conlist( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
875 item_type: type[AnyItemType],
876 *,
877 min_length: int | None = None,
878 max_length: int | None = None,
879 unique_items: bool | None = None,
880) -> type[list[AnyItemType]]:
881 """A wrapper around [`list`][] that adds validation.
883 Args:
884 item_type: The type of the items in the list.
885 min_length: The minimum length of the list. Defaults to None.
886 max_length: The maximum length of the list. Defaults to None.
887 unique_items: Whether the items in the list must be unique. Defaults to None.
888 !!! warning Deprecated
889 The `unique_items` parameter is deprecated, use `Set` instead.
890 See [this issue](https://github.com/pydantic/pydantic-core/issues/296) for more details.
892 Returns:
893 The wrapped list type.
894 """
895 if unique_items is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
896 raise PydanticUserError( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
897 (
898 '`unique_items` is removed, use `Set` instead'
899 '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)'
900 ),
901 code='removed-kwargs',
902 )
903 return Annotated[list[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
906# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
908AnyType = TypeVar('AnyType') 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
909if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
910 ImportString = Annotated[AnyType, ...]
911else:
913 class ImportString: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
914 """A type that can be used to import a Python object from a string.
916 `ImportString` expects a string and loads the Python object importable at that dotted path.
917 Attributes of modules may be separated from the module by `:` or `.`, e.g. if `'math:cos'` is provided,
918 the resulting field value would be the function `cos`. If a `.` is used and both an attribute and submodule
919 are present at the same path, the module will be preferred.
921 On model instantiation, pointers will be evaluated and imported. There is
922 some nuance to this behavior, demonstrated in the examples below.
924 ```python
925 import math
927 from pydantic import BaseModel, Field, ImportString, ValidationError
929 class ImportThings(BaseModel):
930 obj: ImportString
932 # A string value will cause an automatic import
933 my_cos = ImportThings(obj='math.cos')
935 # You can use the imported function as you would expect
936 cos_of_0 = my_cos.obj(0)
937 assert cos_of_0 == 1
939 # A string whose value cannot be imported will raise an error
940 try:
941 ImportThings(obj='foo.bar')
942 except ValidationError as e:
943 print(e)
944 '''
945 1 validation error for ImportThings
946 obj
947 Invalid python path: No module named 'foo.bar' [type=import_error, input_value='foo.bar', input_type=str]
948 '''
950 # Actual python objects can be assigned as well
951 my_cos = ImportThings(obj=math.cos)
952 my_cos_2 = ImportThings(obj='math.cos')
953 my_cos_3 = ImportThings(obj='math:cos')
954 assert my_cos == my_cos_2 == my_cos_3
956 # You can set default field value either as Python object:
957 class ImportThingsDefaultPyObj(BaseModel):
958 obj: ImportString = math.cos
960 # or as a string value (but only if used with `validate_default=True`)
961 class ImportThingsDefaultString(BaseModel):
962 obj: ImportString = Field(default='math.cos', validate_default=True)
964 my_cos_default1 = ImportThingsDefaultPyObj()
965 my_cos_default2 = ImportThingsDefaultString()
966 assert my_cos_default1.obj == my_cos_default2.obj == math.cos
968 # note: this will not work!
969 class ImportThingsMissingValidateDefault(BaseModel):
970 obj: ImportString = 'math.cos'
972 my_cos_default3 = ImportThingsMissingValidateDefault()
973 assert my_cos_default3.obj == 'math.cos' # just string, not evaluated
974 ```
976 Serializing an `ImportString` type to json is also possible.
978 ```python
979 from pydantic import BaseModel, ImportString
981 class ImportThings(BaseModel):
982 obj: ImportString
984 # Create an instance
985 m = ImportThings(obj='math.cos')
986 print(m)
987 #> obj=<built-in function cos>
988 print(m.model_dump_json())
989 #> {"obj":"math.cos"}
990 ```
991 """
993 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
994 def __class_getitem__(cls, item: AnyType) -> AnyType: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
995 return Annotated[item, cls()] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
997 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
998 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
999 cls, source: type[Any], handler: GetCoreSchemaHandler
1000 ) -> core_schema.CoreSchema:
1001 serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1002 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1003 # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any]
1004 return core_schema.no_info_plain_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1005 function=_validators.import_string, serialization=serializer
1006 )
1007 else:
1008 return core_schema.no_info_before_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1009 function=_validators.import_string, schema=handler(source), serialization=serializer
1010 )
1012 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1013 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1014 return handler(core_schema.str_schema()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1016 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1017 def _serialize(v: Any) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1018 if isinstance(v, ModuleType): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1019 return v.__name__ 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1020 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1021 return f'{v.__module__}.{v.__name__}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1022 # Handle special cases for sys.XXX streams
1023 # if we see more of these, we should consider a more general solution
1024 elif hasattr(v, 'name'): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1025 if v.name == '<stdout>': 1025 ↛ 1026line 1025 didn't jump to line 1026 because the condition on line 1025 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1026 return 'sys.stdout'
1027 elif v.name == '<stdin>': 1027 ↛ 1028line 1027 didn't jump to line 1028 because the condition on line 1027 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1028 return 'sys.stdin'
1029 elif v.name == '<stderr>': 1029 ↛ 1030line 1029 didn't jump to line 1030 because the condition on line 1029 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1030 return 'sys.stderr'
1031 else:
1032 return v 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1034 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1035 return 'ImportString' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1038# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1041def condecimal( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1042 *,
1043 strict: bool | None = None,
1044 gt: int | Decimal | None = None,
1045 ge: int | Decimal | None = None,
1046 lt: int | Decimal | None = None,
1047 le: int | Decimal | None = None,
1048 multiple_of: int | Decimal | None = None,
1049 max_digits: int | None = None,
1050 decimal_places: int | None = None,
1051 allow_inf_nan: bool | None = None,
1052) -> type[Decimal]:
1053 """
1054 !!! warning "Discouraged"
1055 This function is **discouraged** in favor of using
1056 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
1057 [`Field`][pydantic.fields.Field] instead.
1059 This function will be **deprecated** in Pydantic 3.0.
1061 The reason is that `condecimal` returns a type, which doesn't play well with static analysis tools.
1063 === ":x: Don't do this"
1064 ```python
1065 from pydantic import BaseModel, condecimal
1067 class Foo(BaseModel):
1068 bar: condecimal(strict=True, allow_inf_nan=True)
1069 ```
1071 === ":white_check_mark: Do this"
1072 ```python
1073 from decimal import Decimal
1074 from typing import Annotated
1076 from pydantic import BaseModel, Field
1078 class Foo(BaseModel):
1079 bar: Annotated[Decimal, Field(strict=True, allow_inf_nan=True)]
1080 ```
1082 A wrapper around Decimal that adds validation.
1084 Args:
1085 strict: Whether to validate the value in strict mode. Defaults to `None`.
1086 gt: The value must be greater than this. Defaults to `None`.
1087 ge: The value must be greater than or equal to this. Defaults to `None`.
1088 lt: The value must be less than this. Defaults to `None`.
1089 le: The value must be less than or equal to this. Defaults to `None`.
1090 multiple_of: The value must be a multiple of this. Defaults to `None`.
1091 max_digits: The maximum number of digits. Defaults to `None`.
1092 decimal_places: The number of decimal places. Defaults to `None`.
1093 allow_inf_nan: Whether to allow infinity and NaN. Defaults to `None`.
1095 ```python
1096 from decimal import Decimal
1098 from pydantic import BaseModel, ValidationError, condecimal
1100 class ConstrainedExample(BaseModel):
1101 constrained_decimal: condecimal(gt=Decimal('1.0'))
1103 m = ConstrainedExample(constrained_decimal=Decimal('1.1'))
1104 print(repr(m))
1105 #> ConstrainedExample(constrained_decimal=Decimal('1.1'))
1107 try:
1108 ConstrainedExample(constrained_decimal=Decimal('0.9'))
1109 except ValidationError as e:
1110 print(e.errors())
1111 '''
1112 [
1113 {
1114 'type': 'greater_than',
1115 'loc': ('constrained_decimal',),
1116 'msg': 'Input should be greater than 1.0',
1117 'input': Decimal('0.9'),
1118 'ctx': {'gt': Decimal('1.0')},
1119 'url': 'https://errors.pydantic.dev/2/v/greater_than',
1120 }
1121 ]
1122 '''
1123 ```
1124 """ # noqa: D212
1125 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1126 Decimal,
1127 Strict(strict) if strict is not None else None,
1128 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
1129 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
1130 _fields.pydantic_general_metadata(max_digits=max_digits, decimal_places=decimal_places),
1131 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None,
1132 ]
1135# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1138@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1139class UuidVersion: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1140 """A field metadata class to indicate a [UUID](https://docs.python.org/3/library/uuid.html) version.
1142 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
1144 Attributes:
1145 uuid_version: The version of the UUID. Must be one of 1, 3, 4, 5, 6, 7 or 8.
1147 Example:
1148 ```python
1149 from typing import Annotated
1150 from uuid import UUID
1152 from pydantic.types import UuidVersion
1154 UUID1 = Annotated[UUID, UuidVersion(1)]
1155 ```
1156 """
1158 uuid_version: Literal[1, 3, 4, 5, 6, 7, 8] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1160 def __get_pydantic_json_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1161 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1162 ) -> JsonSchemaValue:
1163 field_schema = handler(core_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1164 field_schema.pop('anyOf', None) # remove the bytes/str union 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1165 field_schema.update(type='string', format=f'uuid{self.uuid_version}') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1166 return field_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1168 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1169 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1170 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1171 schema['version'] = self.uuid_version # type: ignore 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1172 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1174 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1175 return hash(type(self.uuid_version)) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1178UUID1 = Annotated[UUID, UuidVersion(1)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1179"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. 1abcdefghijklmnopqrsJtuvwxyzAB
1181```python
1182import uuid
1184from pydantic import UUID1, BaseModel
1186class Model(BaseModel):
1187 uuid1: UUID1
1189Model(uuid1=uuid.uuid1())
1190```
1191"""
1192UUID3 = Annotated[UUID, UuidVersion(3)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1193"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. 1abcdefghijklmnopqrsJtuvwxyzAB
1195```python
1196import uuid
1198from pydantic import UUID3, BaseModel
1200class Model(BaseModel):
1201 uuid3: UUID3
1203Model(uuid3=uuid.uuid3(uuid.NAMESPACE_DNS, 'pydantic.org'))
1204```
1205"""
1206UUID4 = Annotated[UUID, UuidVersion(4)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1207"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. 1abcdefghijklmnopqrsJtuvwxyzAB
1209```python
1210import uuid
1212from pydantic import UUID4, BaseModel
1214class Model(BaseModel):
1215 uuid4: UUID4
1217Model(uuid4=uuid.uuid4())
1218```
1219"""
1220UUID5 = Annotated[UUID, UuidVersion(5)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1221"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. 1abcdefghijklmnopqrsJtuvwxyzAB
1223```python
1224import uuid
1226from pydantic import UUID5, BaseModel
1228class Model(BaseModel):
1229 uuid5: UUID5
1231Model(uuid5=uuid.uuid5(uuid.NAMESPACE_DNS, 'pydantic.org'))
1232```
1233"""
1234UUID6 = Annotated[UUID, UuidVersion(6)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1235"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 6. 1abcdefghijklmnopqrsJtuvwxyzAB
1237```python
1238import uuid
1240from pydantic import UUID6, BaseModel
1242class Model(BaseModel):
1243 uuid6: UUID6
1245Model(uuid6=uuid.UUID('1efea953-c2d6-6790-aa0a-69db8c87df97'))
1246```
1247"""
1248UUID7 = Annotated[UUID, UuidVersion(7)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1249"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 7. 1abcdefghijklmnopqrsJtuvwxyzAB
1251```python
1252import uuid
1254from pydantic import UUID7, BaseModel
1256class Model(BaseModel):
1257 uuid7: UUID7
1259Model(uuid7=uuid.UUID('0194fdcb-1c47-7a09-b52c-561154de0b4a'))
1260```
1261"""
1262UUID8 = Annotated[UUID, UuidVersion(8)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1263"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 8. 1abcdefghijklmnopqrsJtuvwxyzAB
1265```python
1266import uuid
1268from pydantic import UUID8, BaseModel
1270class Model(BaseModel):
1271 uuid8: UUID8
1273Model(uuid8=uuid.UUID('81a0b92e-6078-8551-9c81-8ccb666bdab8'))
1274```
1275"""
1277# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1280@_dataclasses.dataclass 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1281class PathType: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1282 path_type: Literal['file', 'dir', 'new', 'socket'] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1284 def __get_pydantic_json_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1285 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1286 ) -> JsonSchemaValue:
1287 field_schema = handler(core_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1288 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1289 field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1290 return field_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1292 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1293 function_lookup = { 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1294 'file': cast(core_schema.WithInfoValidatorFunction, self.validate_file),
1295 'dir': cast(core_schema.WithInfoValidatorFunction, self.validate_directory),
1296 'new': cast(core_schema.WithInfoValidatorFunction, self.validate_new),
1297 'socket': cast(core_schema.WithInfoValidatorFunction, self.validate_socket),
1298 }
1300 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1301 function_lookup[self.path_type],
1302 handler(source),
1303 )
1305 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1306 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1307 if path.is_file(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1308 return path 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1309 else:
1310 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1312 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1313 def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1314 if path.is_socket(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1315 return path 1CDabcdefghiEj
1316 else:
1317 raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1319 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1320 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1321 if path.is_dir(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1322 return path 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1323 else:
1324 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1326 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1327 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1328 if path.exists(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1329 raise PydanticCustomError('path_exists', 'Path already exists') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1330 elif not path.parent.exists(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1331 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1332 else:
1333 return path 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1335 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1336 return hash(type(self.path_type)) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1339FilePath = Annotated[Path, PathType('file')] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1340"""A path that must point to a file. 1abcdefghijklmnopqrsJtuvwxyzAB
1342```python
1343from pathlib import Path
1345from pydantic import BaseModel, FilePath, ValidationError
1347class Model(BaseModel):
1348 f: FilePath
1350path = Path('text.txt')
1351path.touch()
1352m = Model(f='text.txt')
1353print(m.model_dump())
1354#> {'f': PosixPath('text.txt')}
1355path.unlink()
1357path = Path('directory')
1358path.mkdir(exist_ok=True)
1359try:
1360 Model(f='directory') # directory
1361except ValidationError as e:
1362 print(e)
1363 '''
1364 1 validation error for Model
1365 f
1366 Path does not point to a file [type=path_not_file, input_value='directory', input_type=str]
1367 '''
1368path.rmdir()
1370try:
1371 Model(f='not-exists-file')
1372except ValidationError as e:
1373 print(e)
1374 '''
1375 1 validation error for Model
1376 f
1377 Path does not point to a file [type=path_not_file, input_value='not-exists-file', input_type=str]
1378 '''
1379```
1380"""
1381DirectoryPath = Annotated[Path, PathType('dir')] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1382"""A path that must point to a directory. 1abcdefghijklmnopqrsJtuvwxyzAB
1384```python
1385from pathlib import Path
1387from pydantic import BaseModel, DirectoryPath, ValidationError
1389class Model(BaseModel):
1390 f: DirectoryPath
1392path = Path('directory/')
1393path.mkdir()
1394m = Model(f='directory/')
1395print(m.model_dump())
1396#> {'f': PosixPath('directory')}
1397path.rmdir()
1399path = Path('file.txt')
1400path.touch()
1401try:
1402 Model(f='file.txt') # file
1403except ValidationError as e:
1404 print(e)
1405 '''
1406 1 validation error for Model
1407 f
1408 Path does not point to a directory [type=path_not_directory, input_value='file.txt', input_type=str]
1409 '''
1410path.unlink()
1412try:
1413 Model(f='not-exists-directory')
1414except ValidationError as e:
1415 print(e)
1416 '''
1417 1 validation error for Model
1418 f
1419 Path does not point to a directory [type=path_not_directory, input_value='not-exists-directory', input_type=str]
1420 '''
1421```
1422"""
1423NewPath = Annotated[Path, PathType('new')] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1424"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" 1abcdefghijklmnopqrsJtuvwxyzAB
1426SocketPath = Annotated[Path, PathType('socket')] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1427"""A path to an existing socket file""" 1abcdefghijklmnopqrsJtuvwxyzAB
1429# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1431if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1432 # Json[list[str]] will be recognized by type checkers as list[str]
1433 Json = Annotated[AnyType, ...]
1435else:
1437 class Json: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1438 """A special type wrapper which loads JSON before parsing.
1440 You can use the `Json` data type to make Pydantic first load a raw JSON string before
1441 validating the loaded data into the parametrized type:
1443 ```python
1444 from typing import Any
1446 from pydantic import BaseModel, Json, ValidationError
1448 class AnyJsonModel(BaseModel):
1449 json_obj: Json[Any]
1451 class ConstrainedJsonModel(BaseModel):
1452 json_obj: Json[list[int]]
1454 print(AnyJsonModel(json_obj='{"b": 1}'))
1455 #> json_obj={'b': 1}
1456 print(ConstrainedJsonModel(json_obj='[1, 2, 3]'))
1457 #> json_obj=[1, 2, 3]
1459 try:
1460 ConstrainedJsonModel(json_obj=12)
1461 except ValidationError as e:
1462 print(e)
1463 '''
1464 1 validation error for ConstrainedJsonModel
1465 json_obj
1466 JSON input should be string, bytes or bytearray [type=json_type, input_value=12, input_type=int]
1467 '''
1469 try:
1470 ConstrainedJsonModel(json_obj='[a, b]')
1471 except ValidationError as e:
1472 print(e)
1473 '''
1474 1 validation error for ConstrainedJsonModel
1475 json_obj
1476 Invalid JSON: expected value at line 1 column 2 [type=json_invalid, input_value='[a, b]', input_type=str]
1477 '''
1479 try:
1480 ConstrainedJsonModel(json_obj='["a", "b"]')
1481 except ValidationError as e:
1482 print(e)
1483 '''
1484 2 validation errors for ConstrainedJsonModel
1485 json_obj.0
1486 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
1487 json_obj.1
1488 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='b', input_type=str]
1489 '''
1490 ```
1492 When you dump the model using `model_dump` or `model_dump_json`, the dumped value will be the result of validation,
1493 not the original JSON string. However, you can use the argument `round_trip=True` to get the original JSON string back:
1495 ```python
1496 from pydantic import BaseModel, Json
1498 class ConstrainedJsonModel(BaseModel):
1499 json_obj: Json[list[int]]
1501 print(ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json())
1502 #> {"json_obj":[1,2,3]}
1503 print(
1504 ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json(round_trip=True)
1505 )
1506 #> {"json_obj":"[1,2,3]"}
1507 ```
1508 """
1510 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1511 def __class_getitem__(cls, item: AnyType) -> AnyType: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1512 return Annotated[item, cls()] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1514 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1515 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1516 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1517 return core_schema.json_schema(None) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1518 else:
1519 return core_schema.json_schema(handler(source)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1521 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1522 return 'Json' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1524 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1525 return hash(type(self)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1527 def __eq__(self, other: Any) -> bool: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1528 return type(other) is type(self) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1531# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1533SecretType = TypeVar('SecretType') 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1536class _SecretBase(Generic[SecretType]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1537 def __init__(self, secret_value: SecretType) -> None: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1538 self._secret_value: SecretType = secret_value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1540 def get_secret_value(self) -> SecretType: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1541 """Get the secret value.
1543 Returns:
1544 The secret value.
1545 """
1546 return self._secret_value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1548 def __eq__(self, other: Any) -> bool: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1549 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1551 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1552 return hash(self.get_secret_value()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1554 def __str__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1555 return str(self._display()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1557 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1558 return f'{self.__class__.__name__}({self._display()!r})' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1560 def _display(self) -> str | bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1561 raise NotImplementedError
1564def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1565 if info.mode == 'json': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1566 return str(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1567 else:
1568 return value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1571class Secret(_SecretBase[SecretType]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1572 """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks.
1574 You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing
1575 is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both
1576 ways of using `Secret` to create a new secret type.
1578 1. Directly parametrizing `Secret` with a type:
1580 ```python
1581 from pydantic import BaseModel, Secret
1583 SecretBool = Secret[bool]
1585 class Model(BaseModel):
1586 secret_bool: SecretBool
1588 m = Model(secret_bool=True)
1589 print(m.model_dump())
1590 #> {'secret_bool': Secret('**********')}
1592 print(m.model_dump_json())
1593 #> {"secret_bool":"**********"}
1595 print(m.secret_bool.get_secret_value())
1596 #> True
1597 ```
1599 2. Subclassing from parametrized `Secret`:
1601 ```python
1602 from datetime import date
1604 from pydantic import BaseModel, Secret
1606 class SecretDate(Secret[date]):
1607 def _display(self) -> str:
1608 return '****/**/**'
1610 class Model(BaseModel):
1611 secret_date: SecretDate
1613 m = Model(secret_date=date(2022, 1, 1))
1614 print(m.model_dump())
1615 #> {'secret_date': SecretDate('****/**/**')}
1617 print(m.model_dump_json())
1618 #> {"secret_date":"****/**/**"}
1620 print(m.secret_date.get_secret_value())
1621 #> 2022-01-01
1622 ```
1624 The value returned by the `_display` method will be used for `repr()` and `str()`.
1626 You can enforce constraints on the underlying type through annotations:
1627 For example:
1629 ```python
1630 from typing import Annotated
1632 from pydantic import BaseModel, Field, Secret, ValidationError
1634 SecretPosInt = Secret[Annotated[int, Field(gt=0, strict=True)]]
1636 class Model(BaseModel):
1637 sensitive_int: SecretPosInt
1639 m = Model(sensitive_int=42)
1640 print(m.model_dump())
1641 #> {'sensitive_int': Secret('**********')}
1643 try:
1644 m = Model(sensitive_int=-42) # (1)!
1645 except ValidationError as exc_info:
1646 print(exc_info.errors(include_url=False, include_input=False))
1647 '''
1648 [
1649 {
1650 'type': 'greater_than',
1651 'loc': ('sensitive_int',),
1652 'msg': 'Input should be greater than 0',
1653 'ctx': {'gt': 0},
1654 }
1655 ]
1656 '''
1658 try:
1659 m = Model(sensitive_int='42') # (2)!
1660 except ValidationError as exc_info:
1661 print(exc_info.errors(include_url=False, include_input=False))
1662 '''
1663 [
1664 {
1665 'type': 'int_type',
1666 'loc': ('sensitive_int',),
1667 'msg': 'Input should be a valid integer',
1668 }
1669 ]
1670 '''
1671 ```
1673 1. The input value is not greater than 0, so it raises a validation error.
1674 2. The input value is not an integer, so it raises a validation error because the `SecretPosInt` type has strict mode enabled.
1675 """
1677 def _display(self) -> str | bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1678 return '**********' if self.get_secret_value() else '' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1680 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1681 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1682 inner_type = None 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1683 # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly
1684 origin_type = get_origin(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1685 if origin_type is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1686 inner_type = get_args(source)[0] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1687 # otherwise, we need to get the inner type from the base class
1688 else:
1689 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1690 for base in bases: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1691 if get_origin(base) is Secret: 1691 ↛ 1690line 1691 didn't jump to line 1690 because the condition on line 1691 was always true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1692 inner_type = get_args(base)[0] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1693 if bases == [] or inner_type is None: 1693 ↛ 1694line 1693 didn't jump to line 1694 because the condition on line 1693 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1694 raise TypeError(
1695 f"Can't get secret type from {cls.__name__}. "
1696 'Please use Secret[<type>], or subclass from Secret[<type>] instead.'
1697 )
1699 inner_schema = handler.generate_schema(inner_type) # type: ignore 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1701 def validate_secret_value(value, handler) -> Secret[SecretType]: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1702 if isinstance(value, Secret): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1703 value = value.get_secret_value() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1704 validated_inner = handler(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1705 return cls(validated_inner) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1707 return core_schema.json_or_python_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1708 python_schema=core_schema.no_info_wrap_validator_function(
1709 validate_secret_value,
1710 inner_schema,
1711 ),
1712 json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema),
1713 serialization=core_schema.plain_serializer_function_ser_schema(
1714 _serialize_secret,
1715 info_arg=True,
1716 when_used='always',
1717 ),
1718 )
1720 __pydantic_serializer__ = SchemaSerializer( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1721 core_schema.any_schema(
1722 serialization=core_schema.plain_serializer_function_ser_schema(
1723 _serialize_secret,
1724 info_arg=True,
1725 when_used='always',
1726 )
1727 )
1728 )
1731def _secret_display(value: SecretType) -> str: # type: ignore 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1732 return '**********' if value else '' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1735def _serialize_secret_field( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1736 value: _SecretField[SecretType], info: core_schema.SerializationInfo
1737) -> str | _SecretField[SecretType]:
1738 if info.mode == 'json': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1739 # we want the output to always be string without the `b'` prefix for bytes,
1740 # hence we just use `secret_display`
1741 return _secret_display(value.get_secret_value()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1742 else:
1743 return value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1746class _SecretField(_SecretBase[SecretType]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1747 _inner_schema: ClassVar[CoreSchema] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1748 _error_kind: ClassVar[str] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1750 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1751 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1752 def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1753 json_schema = handler(cls._inner_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1754 _utils.update_not_none( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1755 json_schema,
1756 type='string',
1757 writeOnly=True,
1758 format='password',
1759 )
1760 return json_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1762 def get_secret_schema(strict: bool) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1763 inner_schema = {**cls._inner_schema, 'strict': strict} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1764 json_schema = core_schema.no_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1765 source, # construct the type
1766 inner_schema, # pyright: ignore[reportArgumentType]
1767 )
1768 return core_schema.json_or_python_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1769 python_schema=core_schema.union_schema(
1770 [
1771 core_schema.is_instance_schema(source),
1772 json_schema,
1773 ],
1774 custom_error_type=cls._error_kind,
1775 ),
1776 json_schema=json_schema,
1777 serialization=core_schema.plain_serializer_function_ser_schema(
1778 _serialize_secret_field,
1779 info_arg=True,
1780 when_used='always',
1781 ),
1782 )
1784 return core_schema.lax_or_strict_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1785 lax_schema=get_secret_schema(strict=False),
1786 strict_schema=get_secret_schema(strict=True),
1787 metadata={'pydantic_js_functions': [get_json_schema]},
1788 )
1790 __pydantic_serializer__ = SchemaSerializer( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1791 core_schema.any_schema(
1792 serialization=core_schema.plain_serializer_function_ser_schema(
1793 _serialize_secret_field,
1794 info_arg=True,
1795 when_used='always',
1796 )
1797 )
1798 )
1801class SecretStr(_SecretField[str]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1802 """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1804 When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in
1805 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`.
1807 ```python
1808 from pydantic import BaseModel, SecretStr
1810 class User(BaseModel):
1811 username: str
1812 password: SecretStr
1814 user = User(username='scolvin', password='password1')
1816 print(user)
1817 #> username='scolvin' password=SecretStr('**********')
1818 print(user.password.get_secret_value())
1819 #> password1
1820 print((SecretStr('password'), SecretStr('')))
1821 #> (SecretStr('**********'), SecretStr(''))
1822 ```
1824 As seen above, by default, [`SecretStr`][pydantic.types.SecretStr] (and [`SecretBytes`][pydantic.types.SecretBytes])
1825 will be serialized as `**********` when serializing to json.
1827 You can use the [`field_serializer`][pydantic.functional_serializers.field_serializer] to dump the
1828 secret as plain-text when serializing to json.
1830 ```python
1831 from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer
1833 class Model(BaseModel):
1834 password: SecretStr
1835 password_bytes: SecretBytes
1837 @field_serializer('password', 'password_bytes', when_used='json')
1838 def dump_secret(self, v):
1839 return v.get_secret_value()
1841 model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes')
1842 print(model)
1843 #> password=SecretStr('**********') password_bytes=SecretBytes(b'**********')
1844 print(model.password)
1845 #> **********
1846 print(model.model_dump())
1847 '''
1848 {
1849 'password': SecretStr('**********'),
1850 'password_bytes': SecretBytes(b'**********'),
1851 }
1852 '''
1853 print(model.model_dump_json())
1854 #> {"password":"IAmSensitive","password_bytes":"IAmSensitiveBytes"}
1855 ```
1856 """
1858 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1859 _error_kind: ClassVar[str] = 'string_type' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1861 def __len__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1862 return len(self._secret_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1864 def _display(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1865 return _secret_display(self._secret_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1868class SecretBytes(_SecretField[bytes]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1869 """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1871 It displays `b'**********'` instead of the string value on `repr()` and `str()` calls.
1872 When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in
1873 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`.
1875 ```python
1876 from pydantic import BaseModel, SecretBytes
1878 class User(BaseModel):
1879 username: str
1880 password: SecretBytes
1882 user = User(username='scolvin', password=b'password1')
1883 #> username='scolvin' password=SecretBytes(b'**********')
1884 print(user.password.get_secret_value())
1885 #> b'password1'
1886 print((SecretBytes(b'password'), SecretBytes(b'')))
1887 #> (SecretBytes(b'**********'), SecretBytes(b''))
1888 ```
1889 """
1891 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1892 _error_kind: ClassVar[str] = 'bytes_type' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1894 def __len__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1895 return len(self._secret_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1897 def _display(self) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1898 return _secret_display(self._secret_value).encode() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1901# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1904class PaymentCardBrand(str, Enum): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1905 amex = 'American Express' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1906 mastercard = 'Mastercard' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1907 visa = 'Visa' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1908 other = 'other' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1910 def __str__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1911 return self.value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1914@deprecated( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1915 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. '
1916 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.',
1917 category=PydanticDeprecatedSince20,
1918)
1919class PaymentCardNumber(str): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1920 """Based on: https://en.wikipedia.org/wiki/Payment_card_number."""
1922 strip_whitespace: ClassVar[bool] = True 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1923 min_length: ClassVar[int] = 12 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1924 max_length: ClassVar[int] = 19 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1925 bin: str 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1926 last4: str 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1927 brand: PaymentCardBrand 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1929 def __init__(self, card_number: str): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1930 self.validate_digits(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1932 card_number = self.validate_luhn_check_digit(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1934 self.bin = card_number[:6] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1935 self.last4 = card_number[-4:] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1936 self.brand = self.validate_brand(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1938 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1939 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1940 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1941 cls.validate,
1942 core_schema.str_schema(
1943 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace
1944 ),
1945 )
1947 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1948 def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1949 """Validate the card number and return a `PaymentCardNumber` instance."""
1950 return cls(input_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1952 @property 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1953 def masked(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1954 """Mask all but the last 4 digits of the card number.
1956 Returns:
1957 A masked card number string.
1958 """
1959 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1960 return f'{self.bin}{"*" * num_masked}{self.last4}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1962 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1963 def validate_digits(cls, card_number: str) -> None: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1964 """Validate that the card number is all digits."""
1965 if not card_number.isdigit(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1966 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1968 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1969 def validate_luhn_check_digit(cls, card_number: str) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1970 """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm."""
1971 sum_ = int(card_number[-1]) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1972 length = len(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1973 parity = length % 2 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1974 for i in range(length - 1): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1975 digit = int(card_number[i]) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1976 if i % 2 == parity: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1977 digit *= 2 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1978 if digit > 9: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1979 digit -= 9 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1980 sum_ += digit 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1981 valid = sum_ % 10 == 0 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1982 if not valid: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1983 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1984 return card_number 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1986 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1987 def validate_brand(card_number: str) -> PaymentCardBrand: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1988 """Validate length based on BIN for major brands:
1989 https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN).
1990 """
1991 if card_number[0] == '4': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1992 brand = PaymentCardBrand.visa 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1993 elif 51 <= int(card_number[:2]) <= 55: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1994 brand = PaymentCardBrand.mastercard 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1995 elif card_number[:2] in {'34', '37'}: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1996 brand = PaymentCardBrand.amex 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1997 else:
1998 brand = PaymentCardBrand.other 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2000 required_length: None | int | str = None 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2001 if brand in PaymentCardBrand.mastercard: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2002 required_length = 16 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2003 valid = len(card_number) == required_length 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2004 elif brand == PaymentCardBrand.visa: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2005 required_length = '13, 16 or 19' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2006 valid = len(card_number) in {13, 16, 19} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2007 elif brand == PaymentCardBrand.amex: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2008 required_length = 15 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2009 valid = len(card_number) == required_length 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2010 else:
2011 valid = True 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2013 if not valid: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2014 raise PydanticCustomError( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2015 'payment_card_number_brand',
2016 'Length for a {brand} card must be {required_length}',
2017 {'brand': brand, 'required_length': required_length},
2018 )
2019 return brand 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2022# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2025class ByteSize(int): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2026 """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer.
2028 You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into
2029 an integer, and also to print out human-readable strings representing a number of bytes.
2031 In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes,
2032 and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2,
2033 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).
2035 !!! info
2036 Note that `1b` will be parsed as "1 byte" and not "1 bit".
2038 ```python
2039 from pydantic import BaseModel, ByteSize
2041 class MyModel(BaseModel):
2042 size: ByteSize
2044 print(MyModel(size=52000).size)
2045 #> 52000
2046 print(MyModel(size='3000 KiB').size)
2047 #> 3072000
2049 m = MyModel(size='50 PB')
2050 print(m.size.human_readable())
2051 #> 44.4PiB
2052 print(m.size.human_readable(decimal=True))
2053 #> 50.0PB
2054 print(m.size.human_readable(separator=' '))
2055 #> 44.4 PiB
2057 print(m.size.to('TiB'))
2058 #> 45474.73508864641
2059 ```
2060 """
2062 byte_sizes = { 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2063 'b': 1,
2064 'kb': 10**3,
2065 'mb': 10**6,
2066 'gb': 10**9,
2067 'tb': 10**12,
2068 'pb': 10**15,
2069 'eb': 10**18,
2070 'kib': 2**10,
2071 'mib': 2**20,
2072 'gib': 2**30,
2073 'tib': 2**40,
2074 'pib': 2**50,
2075 'eib': 2**60,
2076 'bit': 1 / 8,
2077 'kbit': 10**3 / 8,
2078 'mbit': 10**6 / 8,
2079 'gbit': 10**9 / 8,
2080 'tbit': 10**12 / 8,
2081 'pbit': 10**15 / 8,
2082 'ebit': 10**18 / 8,
2083 'kibit': 2**10 / 8,
2084 'mibit': 2**20 / 8,
2085 'gibit': 2**30 / 8,
2086 'tibit': 2**40 / 8,
2087 'pibit': 2**50 / 8,
2088 'eibit': 2**60 / 8,
2089 }
2090 byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2092 byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2093 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2095 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2096 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2097 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2098 function=cls._validate,
2099 schema=core_schema.union_schema(
2100 [
2101 core_schema.str_schema(pattern=cls.byte_string_pattern),
2102 core_schema.int_schema(ge=0),
2103 ],
2104 custom_error_type='byte_size',
2105 custom_error_message='could not parse value and unit from byte string',
2106 ),
2107 serialization=core_schema.plain_serializer_function_ser_schema(
2108 int, return_schema=core_schema.int_schema(ge=0)
2109 ),
2110 )
2112 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2113 def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2114 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2115 return cls(int(input_value)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2116 except ValueError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2117 pass 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2119 str_match = cls.byte_string_re.match(str(input_value)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2120 if str_match is None: 2120 ↛ 2121line 2120 didn't jump to line 2121 because the condition on line 2120 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2121 raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string')
2123 scalar, unit = str_match.groups() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2124 if unit is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2125 unit = 'b' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2127 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2128 unit_mult = cls.byte_sizes[unit.lower()] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2129 except KeyError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2130 raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2132 return cls(int(float(scalar) * unit_mult)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2134 def human_readable(self, decimal: bool = False, separator: str = '') -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2135 """Converts a byte size to a human readable string.
2137 Args:
2138 decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units
2139 (e.g. 1024 bytes per KiB).
2140 separator: A string used to split the value and unit. Defaults to an empty string ('').
2142 Returns:
2143 A human readable string representation of the byte size.
2144 """
2145 if decimal: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2146 divisor = 1000 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2147 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2148 final_unit = 'EB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2149 else:
2150 divisor = 1024 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2151 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2152 final_unit = 'EiB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2154 num = float(self) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2155 for unit in units: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2156 if abs(num) < divisor: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2157 if unit == 'B': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2158 return f'{num:0.0f}{separator}{unit}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2159 else:
2160 return f'{num:0.1f}{separator}{unit}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2161 num /= divisor 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2163 return f'{num:0.1f}{separator}{final_unit}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2165 def to(self, unit: str) -> float: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2166 """Converts a byte size to another unit, including both byte and bit units.
2168 Args:
2169 unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB,
2170 KiB, MiB, GiB, TiB, PiB, EiB (byte units) and
2171 bit, kbit, mbit, gbit, tbit, pbit, ebit,
2172 kibit, mibit, gibit, tibit, pibit, eibit (bit units).
2174 Returns:
2175 The byte size in the new unit.
2176 """
2177 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2178 unit_div = self.byte_sizes[unit.lower()] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2179 except KeyError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2180 raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2182 return self / unit_div 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2185# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2188def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2189 if annotated_type != expected_type: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2190 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2193if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2194 PastDate = Annotated[date, ...]
2195 FutureDate = Annotated[date, ...]
2196else:
2198 class PastDate: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2199 """A date in the past."""
2201 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2202 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2203 cls, source: type[Any], handler: GetCoreSchemaHandler
2204 ) -> core_schema.CoreSchema:
2205 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2206 # used directly as a type
2207 return core_schema.date_schema(now_op='past') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2208 else:
2209 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2210 _check_annotated_type(schema['type'], 'date', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2211 schema['now_op'] = 'past' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2212 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2214 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2215 return 'PastDate' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2217 class FutureDate: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2218 """A date in the future."""
2220 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2221 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2222 cls, source: type[Any], handler: GetCoreSchemaHandler
2223 ) -> core_schema.CoreSchema:
2224 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2225 # used directly as a type
2226 return core_schema.date_schema(now_op='future') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2227 else:
2228 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2229 _check_annotated_type(schema['type'], 'date', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2230 schema['now_op'] = 'future' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2231 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2233 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2234 return 'FutureDate' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2237def condate( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2238 *,
2239 strict: bool | None = None,
2240 gt: date | None = None,
2241 ge: date | None = None,
2242 lt: date | None = None,
2243 le: date | None = None,
2244) -> type[date]:
2245 """A wrapper for date that adds constraints.
2247 Args:
2248 strict: Whether to validate the date value in strict mode. Defaults to `None`.
2249 gt: The value must be greater than this. Defaults to `None`.
2250 ge: The value must be greater than or equal to this. Defaults to `None`.
2251 lt: The value must be less than this. Defaults to `None`.
2252 le: The value must be less than or equal to this. Defaults to `None`.
2254 Returns:
2255 A date type with the specified constraints.
2256 """
2257 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2258 date,
2259 Strict(strict) if strict is not None else None,
2260 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
2261 ]
2264# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2266if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2267 AwareDatetime = Annotated[datetime, ...]
2268 NaiveDatetime = Annotated[datetime, ...]
2269 PastDatetime = Annotated[datetime, ...]
2270 FutureDatetime = Annotated[datetime, ...]
2272else:
2274 class AwareDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2275 """A datetime that requires timezone info."""
2277 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2278 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2279 cls, source: type[Any], handler: GetCoreSchemaHandler
2280 ) -> core_schema.CoreSchema:
2281 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2282 # used directly as a type
2283 return core_schema.datetime_schema(tz_constraint='aware') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2284 else:
2285 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2286 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2287 schema['tz_constraint'] = 'aware' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2288 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2290 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2291 return 'AwareDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2293 class NaiveDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2294 """A datetime that doesn't require timezone info."""
2296 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2297 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2298 cls, source: type[Any], handler: GetCoreSchemaHandler
2299 ) -> core_schema.CoreSchema:
2300 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2301 # used directly as a type
2302 return core_schema.datetime_schema(tz_constraint='naive') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2303 else:
2304 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2305 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2306 schema['tz_constraint'] = 'naive' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2307 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2309 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2310 return 'NaiveDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2312 class PastDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2313 """A datetime that must be in the past."""
2315 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2316 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2317 cls, source: type[Any], handler: GetCoreSchemaHandler
2318 ) -> core_schema.CoreSchema:
2319 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2320 # used directly as a type
2321 return core_schema.datetime_schema(now_op='past') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2322 else:
2323 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2324 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2325 schema['now_op'] = 'past' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2326 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2328 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2329 return 'PastDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2331 class FutureDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2332 """A datetime that must be in the future."""
2334 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2335 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2336 cls, source: type[Any], handler: GetCoreSchemaHandler
2337 ) -> core_schema.CoreSchema:
2338 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2339 # used directly as a type
2340 return core_schema.datetime_schema(now_op='future') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2341 else:
2342 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2343 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2344 schema['now_op'] = 'future' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2345 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2347 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2348 return 'FutureDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2351# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2354class EncoderProtocol(Protocol): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2355 """Protocol for encoding and decoding data to and from bytes.""" 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2357 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2358 def decode(cls, data: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2359 """Decode the data using the encoder.
2361 Args:
2362 data: The data to decode.
2364 Returns:
2365 The decoded data.
2366 """
2367 ...
2369 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2370 def encode(cls, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2371 """Encode the data using the encoder.
2373 Args:
2374 value: The data to encode.
2376 Returns:
2377 The encoded data.
2378 """
2379 ...
2381 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2382 def get_json_format(cls) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2383 """Get the JSON format for the encoded data.
2385 Returns:
2386 The JSON format for the encoded data.
2387 """
2388 ...
2391class Base64Encoder(EncoderProtocol): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2392 """Standard (non-URL-safe) Base64 encoder."""
2394 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2395 def decode(cls, data: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2396 """Decode the data from base64 encoded bytes to original bytes data.
2398 Args:
2399 data: The data to decode.
2401 Returns:
2402 The decoded data.
2403 """
2404 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2405 return base64.b64decode(data) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2406 except ValueError as e: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2407 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2409 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2410 def encode(cls, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2411 """Encode the data from bytes to a base64 encoded bytes.
2413 Args:
2414 value: The data to encode.
2416 Returns:
2417 The encoded data.
2418 """
2419 return base64.b64encode(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2421 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2422 def get_json_format(cls) -> Literal['base64']: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2423 """Get the JSON format for the encoded data.
2425 Returns:
2426 The JSON format for the encoded data.
2427 """
2428 return 'base64' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2431class Base64UrlEncoder(EncoderProtocol): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2432 """URL-safe Base64 encoder."""
2434 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2435 def decode(cls, data: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2436 """Decode the data from base64 encoded bytes to original bytes data.
2438 Args:
2439 data: The data to decode.
2441 Returns:
2442 The decoded data.
2443 """
2444 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2445 return base64.urlsafe_b64decode(data) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2446 except ValueError as e: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2447 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2449 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2450 def encode(cls, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2451 """Encode the data from bytes to a base64 encoded bytes.
2453 Args:
2454 value: The data to encode.
2456 Returns:
2457 The encoded data.
2458 """
2459 return base64.urlsafe_b64encode(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2461 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2462 def get_json_format(cls) -> Literal['base64url']: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2463 """Get the JSON format for the encoded data.
2465 Returns:
2466 The JSON format for the encoded data.
2467 """
2468 return 'base64url' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2471@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2472class EncodedBytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2473 """A bytes type that is encoded and decoded using the specified encoder.
2475 `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate.
2477 ```python
2478 from typing import Annotated
2480 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError
2482 class MyEncoder(EncoderProtocol):
2483 @classmethod
2484 def decode(cls, data: bytes) -> bytes:
2485 if data == b'**undecodable**':
2486 raise ValueError('Cannot decode data')
2487 return data[13:]
2489 @classmethod
2490 def encode(cls, value: bytes) -> bytes:
2491 return b'**encoded**: ' + value
2493 @classmethod
2494 def get_json_format(cls) -> str:
2495 return 'my-encoder'
2497 MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)]
2499 class Model(BaseModel):
2500 my_encoded_bytes: MyEncodedBytes
2502 # Initialize the model with encoded data
2503 m = Model(my_encoded_bytes=b'**encoded**: some bytes')
2505 # Access decoded value
2506 print(m.my_encoded_bytes)
2507 #> b'some bytes'
2509 # Serialize into the encoded form
2510 print(m.model_dump())
2511 #> {'my_encoded_bytes': b'**encoded**: some bytes'}
2513 # Validate encoded data
2514 try:
2515 Model(my_encoded_bytes=b'**undecodable**')
2516 except ValidationError as e:
2517 print(e)
2518 '''
2519 1 validation error for Model
2520 my_encoded_bytes
2521 Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes]
2522 '''
2523 ```
2524 """
2526 encoder: type[EncoderProtocol] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2528 def __get_pydantic_json_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2529 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2530 ) -> JsonSchemaValue:
2531 field_schema = handler(core_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2532 field_schema.update(type='string', format=self.encoder.get_json_format()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2533 return field_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2535 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2536 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2537 _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2538 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2539 function=self.decode,
2540 schema=schema,
2541 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode),
2542 )
2544 def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2545 """Decode the data using the specified encoder.
2547 Args:
2548 data: The data to decode.
2550 Returns:
2551 The decoded data.
2552 """
2553 return self.encoder.decode(data) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2555 def encode(self, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2556 """Encode the data using the specified encoder.
2558 Args:
2559 value: The data to encode.
2561 Returns:
2562 The encoded data.
2563 """
2564 return self.encoder.encode(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2566 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2567 return hash(self.encoder) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2570@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2571class EncodedStr: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2572 """A str type that is encoded and decoded using the specified encoder.
2574 `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate.
2576 ```python
2577 from typing import Annotated
2579 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError
2581 class MyEncoder(EncoderProtocol):
2582 @classmethod
2583 def decode(cls, data: bytes) -> bytes:
2584 if data == b'**undecodable**':
2585 raise ValueError('Cannot decode data')
2586 return data[13:]
2588 @classmethod
2589 def encode(cls, value: bytes) -> bytes:
2590 return b'**encoded**: ' + value
2592 @classmethod
2593 def get_json_format(cls) -> str:
2594 return 'my-encoder'
2596 MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)]
2598 class Model(BaseModel):
2599 my_encoded_str: MyEncodedStr
2601 # Initialize the model with encoded data
2602 m = Model(my_encoded_str='**encoded**: some str')
2604 # Access decoded value
2605 print(m.my_encoded_str)
2606 #> some str
2608 # Serialize into the encoded form
2609 print(m.model_dump())
2610 #> {'my_encoded_str': '**encoded**: some str'}
2612 # Validate encoded data
2613 try:
2614 Model(my_encoded_str='**undecodable**')
2615 except ValidationError as e:
2616 print(e)
2617 '''
2618 1 validation error for Model
2619 my_encoded_str
2620 Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str]
2621 '''
2622 ```
2623 """
2625 encoder: type[EncoderProtocol] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2627 def __get_pydantic_json_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2628 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2629 ) -> JsonSchemaValue:
2630 field_schema = handler(core_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2631 field_schema.update(type='string', format=self.encoder.get_json_format()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2632 return field_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2634 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2635 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2636 _check_annotated_type(schema['type'], 'str', self.__class__.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2637 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2638 function=self.decode_str,
2639 schema=schema,
2640 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str),
2641 )
2643 def decode_str(self, data: str, _: core_schema.ValidationInfo) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2644 """Decode the data using the specified encoder.
2646 Args:
2647 data: The data to decode.
2649 Returns:
2650 The decoded data.
2651 """
2652 return self.encoder.decode(data.encode()).decode() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2654 def encode_str(self, value: str) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2655 """Encode the data using the specified encoder.
2657 Args:
2658 value: The data to encode.
2660 Returns:
2661 The encoded data.
2662 """
2663 return self.encoder.encode(value.encode()).decode() # noqa: UP008 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2665 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2666 return hash(self.encoder) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2669Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2670"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2672Note:
2673 Under the hood, `Base64Bytes` uses the standard library `base64.b64encode` and `base64.b64decode` functions.
2675 As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect
2676 decoding.
2678Warning:
2679 In versions of Pydantic prior to v2.10, `Base64Bytes` used [`base64.encodebytes`][base64.encodebytes]
2680 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html),
2681 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern
2682 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions.
2684 If you'd still like to use these legacy encoders / decoders, you can achieve this by creating a custom annotated type,
2685 like follows:
2687 ```python
2688 import base64
2689 from typing import Annotated, Literal
2691 from pydantic_core import PydanticCustomError
2693 from pydantic import EncodedBytes, EncoderProtocol
2695 class LegacyBase64Encoder(EncoderProtocol):
2696 @classmethod
2697 def decode(cls, data: bytes) -> bytes:
2698 try:
2699 return base64.decodebytes(data)
2700 except ValueError as e:
2701 raise PydanticCustomError(
2702 'base64_decode',
2703 "Base64 decoding error: '{error}'",
2704 {'error': str(e)},
2705 )
2707 @classmethod
2708 def encode(cls, value: bytes) -> bytes:
2709 return base64.encodebytes(value)
2711 @classmethod
2712 def get_json_format(cls) -> Literal['base64']:
2713 return 'base64'
2715 LegacyBase64Bytes = Annotated[bytes, EncodedBytes(encoder=LegacyBase64Encoder)]
2716 ```
2718```python
2719from pydantic import Base64Bytes, BaseModel, ValidationError
2721class Model(BaseModel):
2722 base64_bytes: Base64Bytes
2724# Initialize the model with base64 data
2725m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5')
2727# Access decoded value
2728print(m.base64_bytes)
2729#> b'This is the way'
2731# Serialize into the base64 form
2732print(m.model_dump())
2733#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5'}
2735# Validate base64 data
2736try:
2737 print(Model(base64_bytes=b'undecodable').base64_bytes)
2738except ValidationError as e:
2739 print(e)
2740 '''
2741 1 validation error for Model
2742 base64_bytes
2743 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes]
2744 '''
2745```
2746"""
2747Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2748"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2750Note:
2751 Under the hood, `Base64Str` uses the standard library `base64.b64encode` and `base64.b64decode` functions.
2753 As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect
2754 decoding.
2756Warning:
2757 In versions of Pydantic prior to v2.10, `Base64Str` used [`base64.encodebytes`][base64.encodebytes]
2758 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html),
2759 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern
2760 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions.
2762 See the [`Base64Bytes`][pydantic.types.Base64Bytes] type for more information on how to
2763 replicate the old behavior with the legacy encoders / decoders.
2765```python
2766from pydantic import Base64Str, BaseModel, ValidationError
2768class Model(BaseModel):
2769 base64_str: Base64Str
2771# Initialize the model with base64 data
2772m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y')
2774# Access decoded value
2775print(m.base64_str)
2776#> These aren't the droids you're looking for
2778# Serialize into the base64 form
2779print(m.model_dump())
2780#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y'}
2782# Validate base64 data
2783try:
2784 print(Model(base64_str='undecodable').base64_str)
2785except ValidationError as e:
2786 print(e)
2787 '''
2788 1 validation error for Model
2789 base64_str
2790 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str]
2791 '''
2792```
2793"""
2794Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2795"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2797Note:
2798 Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2799 functions.
2801 As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data
2802 (using `'+'` and `'/'`).
2804```python
2805from pydantic import Base64UrlBytes, BaseModel
2807class Model(BaseModel):
2808 base64url_bytes: Base64UrlBytes
2810# Initialize the model with base64 data
2811m = Model(base64url_bytes=b'SHc_dHc-TXc==')
2812print(m)
2813#> base64url_bytes=b'Hw?tw>Mw'
2814```
2815"""
2816Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2817"""A str type that is encoded and decoded using the URL-safe base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2819Note:
2820 Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2821 functions.
2823 As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`).
2825```python
2826from pydantic import Base64UrlStr, BaseModel
2828class Model(BaseModel):
2829 base64url_str: Base64UrlStr
2831# Initialize the model with base64 data
2832m = Model(base64url_str='SHc_dHc-TXc==')
2833print(m)
2834#> base64url_str='Hw?tw>Mw'
2835```
2836"""
2839__getattr__ = getattr_migration(__name__) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2842@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2843class GetPydanticSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2844 """!!! abstract "Usage Documentation"
2845 [Using `GetPydanticSchema` to Reduce Boilerplate](../concepts/types.md#using-getpydanticschema-to-reduce-boilerplate)
2847 A convenience class for creating an annotation that provides pydantic custom type hooks.
2849 This class is intended to eliminate the need to create a custom "marker" which defines the
2850 `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods.
2852 For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do:
2853 ```python
2854 from typing import Annotated, Any
2856 from pydantic import BaseModel, GetPydanticSchema
2858 HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any))
2860 class Model(BaseModel):
2861 x: Annotated[int, HandleAsAny] # pydantic sees `x: Any`
2863 print(repr(Model(x='abc').x))
2864 #> 'abc'
2865 ```
2866 """
2868 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2869 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2871 # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:`
2872 # which returns `GetPydanticSchema(lambda _s, h: h(type_))`
2874 if not TYPE_CHECKING: 2874 ↛ 2886line 2874 didn't jump to line 2886 because the condition on line 2874 was always true1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2875 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
2877 def __getattr__(self, item: str) -> Any: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2878 """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls."""
2879 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2880 return self.get_pydantic_core_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2881 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2881 ↛ 2882line 2881 didn't jump to line 2882 because the condition on line 2881 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2882 return self.get_pydantic_json_schema
2883 else:
2884 return object.__getattribute__(self, item) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2886 __hash__ = object.__hash__ 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2889@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2890class Tag: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2891 """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union.
2893 Also provides a way to label a union case in error messages.
2895 When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that
2896 should be used to identify that case. For example, in the below example, the `Tag` is used to specify that
2897 if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it
2898 returns `'pumpkin'`, the input should be validated as a `PumpkinPie`.
2900 The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to
2901 the appropriate member of the `Union` in question.
2903 ```python
2904 from typing import Annotated, Any, Literal, Union
2906 from pydantic import BaseModel, Discriminator, Tag
2908 class Pie(BaseModel):
2909 time_to_cook: int
2910 num_ingredients: int
2912 class ApplePie(Pie):
2913 fruit: Literal['apple'] = 'apple'
2915 class PumpkinPie(Pie):
2916 filling: Literal['pumpkin'] = 'pumpkin'
2918 def get_discriminator_value(v: Any) -> str:
2919 if isinstance(v, dict):
2920 return v.get('fruit', v.get('filling'))
2921 return getattr(v, 'fruit', getattr(v, 'filling', None))
2923 class ThanksgivingDinner(BaseModel):
2924 dessert: Annotated[
2925 Union[
2926 Annotated[ApplePie, Tag('apple')],
2927 Annotated[PumpkinPie, Tag('pumpkin')],
2928 ],
2929 Discriminator(get_discriminator_value),
2930 ]
2932 apple_variation = ThanksgivingDinner.model_validate(
2933 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
2934 )
2935 print(repr(apple_variation))
2936 '''
2937 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
2938 '''
2940 pumpkin_variation = ThanksgivingDinner.model_validate(
2941 {
2942 'dessert': {
2943 'filling': 'pumpkin',
2944 'time_to_cook': 40,
2945 'num_ingredients': 6,
2946 }
2947 }
2948 )
2949 print(repr(pumpkin_variation))
2950 '''
2951 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
2952 '''
2953 ```
2955 !!! note
2956 You must specify a `Tag` for every case in a `Tag` that is associated with a
2957 callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code
2958 [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag).
2960 See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s.
2962 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
2963 """
2965 tag: str 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2967 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2968 schema = handler(source_type) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2969 metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2970 metadata['pydantic_internal_union_tag_key'] = self.tag 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2971 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2974@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2975class Discriminator: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2976 """!!! abstract "Usage Documentation"
2977 [Discriminated Unions with `Callable` `Discriminator`](../concepts/unions.md#discriminated-unions-with-callable-discriminator)
2979 Provides a way to use a custom callable as the way to extract the value of a union discriminator.
2981 This allows you to get validation behavior like you'd get from `Field(discriminator=<field_name>)`,
2982 but without needing to have a single shared field across all the union choices. This also makes it
2983 possible to handle unions of models and primitive types with discriminated-union-style validation errors.
2984 Finally, this allows you to use a custom callable as the way to identify which member of a union a value
2985 belongs to, while still seeing all the performance benefits of a discriminated union.
2987 Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion`
2988 than it would be as a normal `Union`.
2990 ```python
2991 from typing import Annotated, Any, Literal, Union
2993 from pydantic import BaseModel, Discriminator, Tag
2995 class Pie(BaseModel):
2996 time_to_cook: int
2997 num_ingredients: int
2999 class ApplePie(Pie):
3000 fruit: Literal['apple'] = 'apple'
3002 class PumpkinPie(Pie):
3003 filling: Literal['pumpkin'] = 'pumpkin'
3005 def get_discriminator_value(v: Any) -> str:
3006 if isinstance(v, dict):
3007 return v.get('fruit', v.get('filling'))
3008 return getattr(v, 'fruit', getattr(v, 'filling', None))
3010 class ThanksgivingDinner(BaseModel):
3011 dessert: Annotated[
3012 Union[
3013 Annotated[ApplePie, Tag('apple')],
3014 Annotated[PumpkinPie, Tag('pumpkin')],
3015 ],
3016 Discriminator(get_discriminator_value),
3017 ]
3019 apple_variation = ThanksgivingDinner.model_validate(
3020 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
3021 )
3022 print(repr(apple_variation))
3023 '''
3024 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
3025 '''
3027 pumpkin_variation = ThanksgivingDinner.model_validate(
3028 {
3029 'dessert': {
3030 'filling': 'pumpkin',
3031 'time_to_cook': 40,
3032 'num_ingredients': 6,
3033 }
3034 }
3035 )
3036 print(repr(pumpkin_variation))
3037 '''
3038 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
3039 '''
3040 ```
3042 See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s.
3044 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
3045 """
3047 discriminator: str | Callable[[Any], Hashable] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3048 """The callable or field name for discriminating the type in a tagged union. 1abcdefghijklmnopqrsJtuvwxyzAB
3050 A `Callable` discriminator must extract the value of the discriminator from the input.
3051 A `str` discriminator must be the name of a field to discriminate against.
3052 """
3053 custom_error_type: str | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3054 """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union 1abcdefghijklmnopqrsJtuvwxyzAB
3055 validation errors.
3056 """
3057 custom_error_message: str | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3058 """Message to use in custom errors.""" 1abcdefghijklmnopqrsJtuvwxyzAB
3059 custom_error_context: dict[str, int | str | float] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3060 """Context to use in custom errors.""" 1abcdefghijklmnopqrsJtuvwxyzAB
3062 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3063 if not is_union_origin(get_origin(source_type)): 3063 ↛ 3064line 3063 didn't jump to line 3064 because the condition on line 3063 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3064 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}')
3066 if isinstance(self.discriminator, str): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3067 from pydantic import Field 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3069 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3070 else:
3071 original_schema = handler(source_type) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3072 return self._convert_schema(original_schema, handler) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3074 def _convert_schema( 1CDabcdefghiFGklmnopqrsJHItuvwxyzAB
3075 self, original_schema: core_schema.CoreSchema, handler: GetCoreSchemaHandler | None = None
3076 ) -> core_schema.TaggedUnionSchema:
3077 if original_schema['type'] != 'union': 3077 ↛ 3082line 3077 didn't jump to line 3082 because the condition on line 3077 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3078 # This likely indicates that the schema was a single-item union that was simplified.
3079 # In this case, we do the same thing we do in
3080 # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely,
3081 # package the generated schema back into a single-item union.
3082 original_schema = core_schema.union_schema([original_schema])
3084 tagged_union_choices = {} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3085 for choice in original_schema['choices']: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3086 tag = None 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3087 if isinstance(choice, tuple): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3088 choice, tag = choice 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3089 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3090 if metadata is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3091 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3092 if tag is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3093 # `handler` is None when this method is called from `apply_discriminator()` (deferred discriminators)
3094 if handler is not None and choice['type'] == 'definition-ref': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3095 # If choice was built from a PEP 695 type alias, try to resolve the def:
3096 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3097 choice = handler.resolve_ref_schema(choice) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3098 except LookupError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3099 pass 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3100 else:
3101 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3102 if metadata is not None: 3102 ↛ 3105line 3102 didn't jump to line 3105 because the condition on line 3102 was always true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3103 tag = metadata.get('pydantic_internal_union_tag_key') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3105 if tag is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3106 raise PydanticUserError( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3107 f'`Tag` not provided for choice {choice} used with `Discriminator`',
3108 code='callable-discriminator-no-tag',
3109 )
3110 tagged_union_choices[tag] = choice 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3112 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored
3113 custom_error_type = self.custom_error_type 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3114 if custom_error_type is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3115 custom_error_type = original_schema.get('custom_error_type') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3117 custom_error_message = self.custom_error_message 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3118 if custom_error_message is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3119 custom_error_message = original_schema.get('custom_error_message') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3121 custom_error_context = self.custom_error_context 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3122 if custom_error_context is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3123 custom_error_context = original_schema.get('custom_error_context') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3125 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3126 return core_schema.tagged_union_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3127 tagged_union_choices,
3128 self.discriminator,
3129 custom_error_type=custom_error_type,
3130 custom_error_message=custom_error_message,
3131 custom_error_context=custom_error_context,
3132 strict=original_schema.get('strict'),
3133 ref=original_schema.get('ref'),
3134 metadata=original_schema.get('metadata'),
3135 serialization=original_schema.get('serialization'),
3136 )
3139_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3142def _get_type_name(x: Any) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3143 type_ = type(x) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3144 if type_ in _JSON_TYPES: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3145 return type_.__name__ 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3147 # Handle proper subclasses; note we don't need to handle None or bool here
3148 if isinstance(x, int): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3149 return 'int' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3150 if isinstance(x, float): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3151 return 'float' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3152 if isinstance(x, str): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3153 return 'str' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3154 if isinstance(x, list): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3155 return 'list' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3156 if isinstance(x, dict): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3157 return 'dict' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3159 # Fail by returning the type's actual name
3160 return getattr(type_, '__name__', '<no type name>') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3163class _AllowAnyJson: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3164 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3165 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3166 python_schema = handler(source_type) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3167 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3170if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3171 # This seems to only be necessary for mypy
3172 JsonValue: TypeAlias = Union[
3173 list['JsonValue'],
3174 dict[str, 'JsonValue'],
3175 str,
3176 bool,
3177 int,
3178 float,
3179 None,
3180 ]
3181 """A `JsonValue` is used to represent a value that can be serialized to JSON.
3183 It may be one of:
3185 * `list['JsonValue']`
3186 * `dict[str, 'JsonValue']`
3187 * `str`
3188 * `bool`
3189 * `int`
3190 * `float`
3191 * `None`
3193 The following example demonstrates how to use `JsonValue` to validate JSON data,
3194 and what kind of errors to expect when input data is not json serializable.
3196 ```python
3197 import json
3199 from pydantic import BaseModel, JsonValue, ValidationError
3201 class Model(BaseModel):
3202 j: JsonValue
3204 valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}}
3205 invalid_json_data = {'j': {'a': {'b': ...}}}
3207 print(repr(Model.model_validate(valid_json_data)))
3208 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
3209 print(repr(Model.model_validate_json(json.dumps(valid_json_data))))
3210 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
3212 try:
3213 Model.model_validate(invalid_json_data)
3214 except ValidationError as e:
3215 print(e)
3216 '''
3217 1 validation error for Model
3218 j.dict.a.dict.b
3219 input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis]
3220 '''
3221 ```
3222 """
3224else:
3225 JsonValue = TypeAliasType( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3226 'JsonValue',
3227 Annotated[
3228 Union[
3229 Annotated[list['JsonValue'], Tag('list')],
3230 Annotated[dict[str, 'JsonValue'], Tag('dict')],
3231 Annotated[str, Tag('str')],
3232 Annotated[bool, Tag('bool')],
3233 Annotated[int, Tag('int')],
3234 Annotated[float, Tag('float')],
3235 Annotated[None, Tag('NoneType')],
3236 ],
3237 Discriminator(
3238 _get_type_name,
3239 custom_error_type='invalid-json-value',
3240 custom_error_message='input was not a valid JSON value',
3241 ),
3242 _AllowAnyJson,
3243 ],
3244 )
3247class _OnErrorOmit: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3248 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3249 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3250 # there is no actual default value here but we use with_default_schema since it already has the on_error
3251 # behavior implemented and it would be no more efficient to implement it on every other validator
3252 # or as a standalone validator
3253 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3256OnErrorOmit = Annotated[T, _OnErrorOmit] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3257""" 1abcdefghijklmnopqrsJtuvwxyzAB
3258When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc.
3259this annotation omits the item from the iteration if there is any error validating it.
3260That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded
3261any invalid items are discarded and the valid ones are returned.
3262"""
3265@_dataclasses.dataclass 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3266class FailFast(_fields.PydanticMetadata, BaseMetadata): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3267 """A `FailFast` annotation can be used to specify that validation should stop at the first error.
3269 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.
3271 You might want to enable this setting if you want to validate your data faster (basically, if you use this,
3272 validation will be more performant with the caveat that you get less information).
3274 ```python
3275 from typing import Annotated
3277 from pydantic import BaseModel, FailFast, ValidationError
3279 class Model(BaseModel):
3280 x: Annotated[list[int], FailFast()]
3282 # This will raise a single error for the first invalid value and stop validation
3283 try:
3284 obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c'])
3285 except ValidationError as e:
3286 print(e)
3287 '''
3288 1 validation error for Model
3289 x.2
3290 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
3291 '''
3292 ```
3293 """
3295 fail_fast: bool = True 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB