Coverage for pydantic/types.py: 97.64%
660 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 10:27 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 10:27 +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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1533# The `Secret` class being conceptually immutable, make the type variable covariant:
1534SecretType = TypeVar('SecretType', covariant=True) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1537class _SecretBase(Generic[SecretType]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1538 def __init__(self, secret_value: SecretType) -> None: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1539 self._secret_value: SecretType = secret_value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1541 def get_secret_value(self) -> SecretType: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1542 """Get the secret value.
1544 Returns:
1545 The secret value.
1546 """
1547 return self._secret_value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1549 def __eq__(self, other: Any) -> bool: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1550 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1552 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1553 return hash(self.get_secret_value()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1555 def __str__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1556 return str(self._display()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1558 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1559 return f'{self.__class__.__name__}({self._display()!r})' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1561 def _display(self) -> str | bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1562 raise NotImplementedError
1565def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1566 if info.mode == 'json': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1567 return str(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1568 else:
1569 return value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1572class Secret(_SecretBase[SecretType]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1573 """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks.
1575 You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing
1576 is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both
1577 ways of using `Secret` to create a new secret type.
1579 1. Directly parametrizing `Secret` with a type:
1581 ```python
1582 from pydantic import BaseModel, Secret
1584 SecretBool = Secret[bool]
1586 class Model(BaseModel):
1587 secret_bool: SecretBool
1589 m = Model(secret_bool=True)
1590 print(m.model_dump())
1591 #> {'secret_bool': Secret('**********')}
1593 print(m.model_dump_json())
1594 #> {"secret_bool":"**********"}
1596 print(m.secret_bool.get_secret_value())
1597 #> True
1598 ```
1600 2. Subclassing from parametrized `Secret`:
1602 ```python
1603 from datetime import date
1605 from pydantic import BaseModel, Secret
1607 class SecretDate(Secret[date]):
1608 def _display(self) -> str:
1609 return '****/**/**'
1611 class Model(BaseModel):
1612 secret_date: SecretDate
1614 m = Model(secret_date=date(2022, 1, 1))
1615 print(m.model_dump())
1616 #> {'secret_date': SecretDate('****/**/**')}
1618 print(m.model_dump_json())
1619 #> {"secret_date":"****/**/**"}
1621 print(m.secret_date.get_secret_value())
1622 #> 2022-01-01
1623 ```
1625 The value returned by the `_display` method will be used for `repr()` and `str()`.
1627 You can enforce constraints on the underlying type through annotations:
1628 For example:
1630 ```python
1631 from typing import Annotated
1633 from pydantic import BaseModel, Field, Secret, ValidationError
1635 SecretPosInt = Secret[Annotated[int, Field(gt=0, strict=True)]]
1637 class Model(BaseModel):
1638 sensitive_int: SecretPosInt
1640 m = Model(sensitive_int=42)
1641 print(m.model_dump())
1642 #> {'sensitive_int': Secret('**********')}
1644 try:
1645 m = Model(sensitive_int=-42) # (1)!
1646 except ValidationError as exc_info:
1647 print(exc_info.errors(include_url=False, include_input=False))
1648 '''
1649 [
1650 {
1651 'type': 'greater_than',
1652 'loc': ('sensitive_int',),
1653 'msg': 'Input should be greater than 0',
1654 'ctx': {'gt': 0},
1655 }
1656 ]
1657 '''
1659 try:
1660 m = Model(sensitive_int='42') # (2)!
1661 except ValidationError as exc_info:
1662 print(exc_info.errors(include_url=False, include_input=False))
1663 '''
1664 [
1665 {
1666 'type': 'int_type',
1667 'loc': ('sensitive_int',),
1668 'msg': 'Input should be a valid integer',
1669 }
1670 ]
1671 '''
1672 ```
1674 1. The input value is not greater than 0, so it raises a validation error.
1675 2. The input value is not an integer, so it raises a validation error because the `SecretPosInt` type has strict mode enabled.
1676 """
1678 def _display(self) -> str | bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1679 return '**********' if self.get_secret_value() else '' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1681 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1682 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1683 inner_type = None 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1684 # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly
1685 origin_type = get_origin(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1686 if origin_type is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1687 inner_type = get_args(source)[0] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1688 # otherwise, we need to get the inner type from the base class
1689 else:
1690 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1691 for base in bases: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1692 if get_origin(base) is Secret: 1692 ↛ 1691line 1692 didn't jump to line 1691 because the condition on line 1692 was always true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1693 inner_type = get_args(base)[0] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1694 if bases == [] or inner_type is None: 1694 ↛ 1695line 1694 didn't jump to line 1695 because the condition on line 1694 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1695 raise TypeError(
1696 f"Can't get secret type from {cls.__name__}. "
1697 'Please use Secret[<type>], or subclass from Secret[<type>] instead.'
1698 )
1700 inner_schema = handler.generate_schema(inner_type) # type: ignore 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1702 def validate_secret_value(value, handler) -> Secret[SecretType]: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1703 if isinstance(value, Secret): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1704 value = value.get_secret_value() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1705 validated_inner = handler(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1706 return cls(validated_inner) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1708 return core_schema.json_or_python_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1709 python_schema=core_schema.no_info_wrap_validator_function(
1710 validate_secret_value,
1711 inner_schema,
1712 ),
1713 json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema),
1714 serialization=core_schema.plain_serializer_function_ser_schema(
1715 _serialize_secret,
1716 info_arg=True,
1717 when_used='always',
1718 ),
1719 )
1721 __pydantic_serializer__ = SchemaSerializer( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1722 core_schema.any_schema(
1723 serialization=core_schema.plain_serializer_function_ser_schema(
1724 _serialize_secret,
1725 info_arg=True,
1726 when_used='always',
1727 )
1728 )
1729 )
1732def _secret_display(value: SecretType) -> str: # type: ignore 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1733 return '**********' if value else '' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1736def _serialize_secret_field( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1737 value: _SecretField[SecretType], info: core_schema.SerializationInfo
1738) -> str | _SecretField[SecretType]:
1739 if info.mode == 'json': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1740 # we want the output to always be string without the `b'` prefix for bytes,
1741 # hence we just use `secret_display`
1742 return _secret_display(value.get_secret_value()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1743 else:
1744 return value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1747class _SecretField(_SecretBase[SecretType]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1748 _inner_schema: ClassVar[CoreSchema] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1749 _error_kind: ClassVar[str] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1751 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1752 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1753 def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1754 json_schema = handler(cls._inner_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1755 _utils.update_not_none( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1756 json_schema,
1757 type='string',
1758 writeOnly=True,
1759 format='password',
1760 )
1761 return json_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1763 def get_secret_schema(strict: bool) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1764 inner_schema = {**cls._inner_schema, 'strict': strict} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1765 json_schema = core_schema.no_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1766 source, # construct the type
1767 inner_schema, # pyright: ignore[reportArgumentType]
1768 )
1769 return core_schema.json_or_python_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1770 python_schema=core_schema.union_schema(
1771 [
1772 core_schema.is_instance_schema(source),
1773 json_schema,
1774 ],
1775 custom_error_type=cls._error_kind,
1776 ),
1777 json_schema=json_schema,
1778 serialization=core_schema.plain_serializer_function_ser_schema(
1779 _serialize_secret_field,
1780 info_arg=True,
1781 when_used='always',
1782 ),
1783 )
1785 return core_schema.lax_or_strict_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1786 lax_schema=get_secret_schema(strict=False),
1787 strict_schema=get_secret_schema(strict=True),
1788 metadata={'pydantic_js_functions': [get_json_schema]},
1789 )
1791 __pydantic_serializer__ = SchemaSerializer( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1792 core_schema.any_schema(
1793 serialization=core_schema.plain_serializer_function_ser_schema(
1794 _serialize_secret_field,
1795 info_arg=True,
1796 when_used='always',
1797 )
1798 )
1799 )
1802class SecretStr(_SecretField[str]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1803 """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1805 When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in
1806 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`.
1808 ```python
1809 from pydantic import BaseModel, SecretStr
1811 class User(BaseModel):
1812 username: str
1813 password: SecretStr
1815 user = User(username='scolvin', password='password1')
1817 print(user)
1818 #> username='scolvin' password=SecretStr('**********')
1819 print(user.password.get_secret_value())
1820 #> password1
1821 print((SecretStr('password'), SecretStr('')))
1822 #> (SecretStr('**********'), SecretStr(''))
1823 ```
1825 As seen above, by default, [`SecretStr`][pydantic.types.SecretStr] (and [`SecretBytes`][pydantic.types.SecretBytes])
1826 will be serialized as `**********` when serializing to json.
1828 You can use the [`field_serializer`][pydantic.functional_serializers.field_serializer] to dump the
1829 secret as plain-text when serializing to json.
1831 ```python
1832 from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer
1834 class Model(BaseModel):
1835 password: SecretStr
1836 password_bytes: SecretBytes
1838 @field_serializer('password', 'password_bytes', when_used='json')
1839 def dump_secret(self, v):
1840 return v.get_secret_value()
1842 model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes')
1843 print(model)
1844 #> password=SecretStr('**********') password_bytes=SecretBytes(b'**********')
1845 print(model.password)
1846 #> **********
1847 print(model.model_dump())
1848 '''
1849 {
1850 'password': SecretStr('**********'),
1851 'password_bytes': SecretBytes(b'**********'),
1852 }
1853 '''
1854 print(model.model_dump_json())
1855 #> {"password":"IAmSensitive","password_bytes":"IAmSensitiveBytes"}
1856 ```
1857 """
1859 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1860 _error_kind: ClassVar[str] = 'string_type' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1862 def __len__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1863 return len(self._secret_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1865 def _display(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1866 return _secret_display(self._secret_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1869class SecretBytes(_SecretField[bytes]): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1870 """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1872 It displays `b'**********'` instead of the string value on `repr()` and `str()` calls.
1873 When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in
1874 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`.
1876 ```python
1877 from pydantic import BaseModel, SecretBytes
1879 class User(BaseModel):
1880 username: str
1881 password: SecretBytes
1883 user = User(username='scolvin', password=b'password1')
1884 #> username='scolvin' password=SecretBytes(b'**********')
1885 print(user.password.get_secret_value())
1886 #> b'password1'
1887 print((SecretBytes(b'password'), SecretBytes(b'')))
1888 #> (SecretBytes(b'**********'), SecretBytes(b''))
1889 ```
1890 """
1892 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1893 _error_kind: ClassVar[str] = 'bytes_type' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1895 def __len__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1896 return len(self._secret_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1898 def _display(self) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1899 return _secret_display(self._secret_value).encode() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1902# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1905class PaymentCardBrand(str, Enum): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1906 amex = 'American Express' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1907 mastercard = 'Mastercard' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1908 visa = 'Visa' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1909 other = 'other' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1911 def __str__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1912 return self.value 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1915@deprecated( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1916 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. '
1917 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.',
1918 category=PydanticDeprecatedSince20,
1919)
1920class PaymentCardNumber(str): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1921 """Based on: https://en.wikipedia.org/wiki/Payment_card_number."""
1923 strip_whitespace: ClassVar[bool] = True 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1924 min_length: ClassVar[int] = 12 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1925 max_length: ClassVar[int] = 19 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1926 bin: str 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1927 last4: str 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1928 brand: PaymentCardBrand 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1930 def __init__(self, card_number: str): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1931 self.validate_digits(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1933 card_number = self.validate_luhn_check_digit(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1935 self.bin = card_number[:6] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1936 self.last4 = card_number[-4:] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1937 self.brand = self.validate_brand(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1939 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1940 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1941 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1942 cls.validate,
1943 core_schema.str_schema(
1944 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace
1945 ),
1946 )
1948 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1949 def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1950 """Validate the card number and return a `PaymentCardNumber` instance."""
1951 return cls(input_value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1953 @property 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1954 def masked(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1955 """Mask all but the last 4 digits of the card number.
1957 Returns:
1958 A masked card number string.
1959 """
1960 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1961 return f'{self.bin}{"*" * num_masked}{self.last4}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1963 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1964 def validate_digits(cls, card_number: str) -> None: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1965 """Validate that the card number is all digits."""
1966 if not card_number.isdigit(): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1967 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1969 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1970 def validate_luhn_check_digit(cls, card_number: str) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1971 """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm."""
1972 sum_ = int(card_number[-1]) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1973 length = len(card_number) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1974 parity = length % 2 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1975 for i in range(length - 1): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1976 digit = int(card_number[i]) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1977 if i % 2 == parity: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1978 digit *= 2 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1979 if digit > 9: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1980 digit -= 9 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1981 sum_ += digit 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1982 valid = sum_ % 10 == 0 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1983 if not valid: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1984 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1985 return card_number 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1987 @staticmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1988 def validate_brand(card_number: str) -> PaymentCardBrand: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
1989 """Validate length based on BIN for major brands:
1990 https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN).
1991 """
1992 if card_number[0] == '4': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1993 brand = PaymentCardBrand.visa 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1994 elif 51 <= int(card_number[:2]) <= 55: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1995 brand = PaymentCardBrand.mastercard 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1996 elif card_number[:2] in {'34', '37'}: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1997 brand = PaymentCardBrand.amex 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
1998 else:
1999 brand = PaymentCardBrand.other 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2001 required_length: None | int | str = None 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2002 if brand in PaymentCardBrand.mastercard: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2003 required_length = 16 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2004 valid = len(card_number) == required_length 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2005 elif brand == PaymentCardBrand.visa: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2006 required_length = '13, 16 or 19' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2007 valid = len(card_number) in {13, 16, 19} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2008 elif brand == PaymentCardBrand.amex: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2009 required_length = 15 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2010 valid = len(card_number) == required_length 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2011 else:
2012 valid = True 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2014 if not valid: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2015 raise PydanticCustomError( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2016 'payment_card_number_brand',
2017 'Length for a {brand} card must be {required_length}',
2018 {'brand': brand, 'required_length': required_length},
2019 )
2020 return brand 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2023# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2026class ByteSize(int): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2027 """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer.
2029 You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into
2030 an integer, and also to print out human-readable strings representing a number of bytes.
2032 In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes,
2033 and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2,
2034 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).
2036 !!! info
2037 Note that `1b` will be parsed as "1 byte" and not "1 bit".
2039 ```python
2040 from pydantic import BaseModel, ByteSize
2042 class MyModel(BaseModel):
2043 size: ByteSize
2045 print(MyModel(size=52000).size)
2046 #> 52000
2047 print(MyModel(size='3000 KiB').size)
2048 #> 3072000
2050 m = MyModel(size='50 PB')
2051 print(m.size.human_readable())
2052 #> 44.4PiB
2053 print(m.size.human_readable(decimal=True))
2054 #> 50.0PB
2055 print(m.size.human_readable(separator=' '))
2056 #> 44.4 PiB
2058 print(m.size.to('TiB'))
2059 #> 45474.73508864641
2060 ```
2061 """
2063 byte_sizes = { 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2064 'b': 1,
2065 'kb': 10**3,
2066 'mb': 10**6,
2067 'gb': 10**9,
2068 'tb': 10**12,
2069 'pb': 10**15,
2070 'eb': 10**18,
2071 'kib': 2**10,
2072 'mib': 2**20,
2073 'gib': 2**30,
2074 'tib': 2**40,
2075 'pib': 2**50,
2076 'eib': 2**60,
2077 'bit': 1 / 8,
2078 'kbit': 10**3 / 8,
2079 'mbit': 10**6 / 8,
2080 'gbit': 10**9 / 8,
2081 'tbit': 10**12 / 8,
2082 'pbit': 10**15 / 8,
2083 'ebit': 10**18 / 8,
2084 'kibit': 2**10 / 8,
2085 'mibit': 2**20 / 8,
2086 'gibit': 2**30 / 8,
2087 'tibit': 2**40 / 8,
2088 'pibit': 2**50 / 8,
2089 'eibit': 2**60 / 8,
2090 }
2091 byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2093 byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2094 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2096 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2097 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2098 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2099 function=cls._validate,
2100 schema=core_schema.union_schema(
2101 [
2102 core_schema.str_schema(pattern=cls.byte_string_pattern),
2103 core_schema.int_schema(ge=0),
2104 ],
2105 custom_error_type='byte_size',
2106 custom_error_message='could not parse value and unit from byte string',
2107 ),
2108 serialization=core_schema.plain_serializer_function_ser_schema(
2109 int, return_schema=core_schema.int_schema(ge=0)
2110 ),
2111 )
2113 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2114 def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2115 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2116 return cls(int(input_value)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2117 except ValueError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2118 pass 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2120 str_match = cls.byte_string_re.match(str(input_value)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2121 if str_match is None: 2121 ↛ 2122line 2121 didn't jump to line 2122 because the condition on line 2121 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2122 raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string')
2124 scalar, unit = str_match.groups() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2125 if unit is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2126 unit = 'b' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2128 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2129 unit_mult = cls.byte_sizes[unit.lower()] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2130 except KeyError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2131 raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2133 return cls(int(float(scalar) * unit_mult)) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2135 def human_readable(self, decimal: bool = False, separator: str = '') -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2136 """Converts a byte size to a human readable string.
2138 Args:
2139 decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units
2140 (e.g. 1024 bytes per KiB).
2141 separator: A string used to split the value and unit. Defaults to an empty string ('').
2143 Returns:
2144 A human readable string representation of the byte size.
2145 """
2146 if decimal: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2147 divisor = 1000 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2148 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2149 final_unit = 'EB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2150 else:
2151 divisor = 1024 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2152 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2153 final_unit = 'EiB' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2155 num = float(self) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2156 for unit in units: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2157 if abs(num) < divisor: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2158 if unit == 'B': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2159 return f'{num:0.0f}{separator}{unit}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2160 else:
2161 return f'{num:0.1f}{separator}{unit}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2162 num /= divisor 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2164 return f'{num:0.1f}{separator}{final_unit}' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2166 def to(self, unit: str) -> float: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2167 """Converts a byte size to another unit, including both byte and bit units.
2169 Args:
2170 unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB,
2171 KiB, MiB, GiB, TiB, PiB, EiB (byte units) and
2172 bit, kbit, mbit, gbit, tbit, pbit, ebit,
2173 kibit, mibit, gibit, tibit, pibit, eibit (bit units).
2175 Returns:
2176 The byte size in the new unit.
2177 """
2178 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2179 unit_div = self.byte_sizes[unit.lower()] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2180 except KeyError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2181 raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2183 return self / unit_div 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2186# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2189def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2190 if annotated_type != expected_type: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2191 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2194if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2195 PastDate = Annotated[date, ...]
2196 FutureDate = Annotated[date, ...]
2197else:
2199 class PastDate: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2200 """A date in the past."""
2202 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2203 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2204 cls, source: type[Any], handler: GetCoreSchemaHandler
2205 ) -> core_schema.CoreSchema:
2206 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2207 # used directly as a type
2208 return core_schema.date_schema(now_op='past') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2209 else:
2210 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2211 _check_annotated_type(schema['type'], 'date', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2212 schema['now_op'] = 'past' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2213 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2215 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2216 return 'PastDate' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2218 class FutureDate: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2219 """A date in the future."""
2221 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2222 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2223 cls, source: type[Any], handler: GetCoreSchemaHandler
2224 ) -> core_schema.CoreSchema:
2225 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2226 # used directly as a type
2227 return core_schema.date_schema(now_op='future') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2228 else:
2229 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2230 _check_annotated_type(schema['type'], 'date', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2231 schema['now_op'] = 'future' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2232 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2234 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2235 return 'FutureDate' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2238def condate( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2239 *,
2240 strict: bool | None = None,
2241 gt: date | None = None,
2242 ge: date | None = None,
2243 lt: date | None = None,
2244 le: date | None = None,
2245) -> type[date]:
2246 """A wrapper for date that adds constraints.
2248 Args:
2249 strict: Whether to validate the date value in strict mode. Defaults to `None`.
2250 gt: The value must be greater than this. Defaults to `None`.
2251 ge: The value must be greater than or equal to this. Defaults to `None`.
2252 lt: The value must be less than this. Defaults to `None`.
2253 le: The value must be less than or equal to this. Defaults to `None`.
2255 Returns:
2256 A date type with the specified constraints.
2257 """
2258 return Annotated[ # pyright: ignore[reportReturnType] 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2259 date,
2260 Strict(strict) if strict is not None else None,
2261 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
2262 ]
2265# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2267if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2268 AwareDatetime = Annotated[datetime, ...]
2269 NaiveDatetime = Annotated[datetime, ...]
2270 PastDatetime = Annotated[datetime, ...]
2271 FutureDatetime = Annotated[datetime, ...]
2273else:
2275 class AwareDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2276 """A datetime that requires timezone info."""
2278 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2279 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2280 cls, source: type[Any], handler: GetCoreSchemaHandler
2281 ) -> core_schema.CoreSchema:
2282 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2283 # used directly as a type
2284 return core_schema.datetime_schema(tz_constraint='aware') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2285 else:
2286 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2287 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2288 schema['tz_constraint'] = 'aware' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2289 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2291 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2292 return 'AwareDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2294 class NaiveDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2295 """A datetime that doesn't require timezone info."""
2297 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2298 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2299 cls, source: type[Any], handler: GetCoreSchemaHandler
2300 ) -> core_schema.CoreSchema:
2301 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2302 # used directly as a type
2303 return core_schema.datetime_schema(tz_constraint='naive') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2304 else:
2305 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2306 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2307 schema['tz_constraint'] = 'naive' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2308 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2310 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2311 return 'NaiveDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2313 class PastDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2314 """A datetime that must be in the past."""
2316 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2317 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2318 cls, source: type[Any], handler: GetCoreSchemaHandler
2319 ) -> core_schema.CoreSchema:
2320 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2321 # used directly as a type
2322 return core_schema.datetime_schema(now_op='past') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2323 else:
2324 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2325 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2326 schema['now_op'] = 'past' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2327 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2329 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2330 return 'PastDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2332 class FutureDatetime: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2333 """A datetime that must be in the future."""
2335 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2336 def __get_pydantic_core_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2337 cls, source: type[Any], handler: GetCoreSchemaHandler
2338 ) -> core_schema.CoreSchema:
2339 if cls is source: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2340 # used directly as a type
2341 return core_schema.datetime_schema(now_op='future') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2342 else:
2343 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2344 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2345 schema['now_op'] = 'future' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2346 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2348 def __repr__(self) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2349 return 'FutureDatetime' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2352# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2355class EncoderProtocol(Protocol): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2356 """Protocol for encoding and decoding data to and from bytes.""" 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2358 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2359 def decode(cls, data: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2360 """Decode the data using the encoder.
2362 Args:
2363 data: The data to decode.
2365 Returns:
2366 The decoded data.
2367 """
2368 ...
2370 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2371 def encode(cls, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2372 """Encode the data using the encoder.
2374 Args:
2375 value: The data to encode.
2377 Returns:
2378 The encoded data.
2379 """
2380 ...
2382 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2383 def get_json_format(cls) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2384 """Get the JSON format for the encoded data.
2386 Returns:
2387 The JSON format for the encoded data.
2388 """
2389 ...
2392class Base64Encoder(EncoderProtocol): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2393 """Standard (non-URL-safe) Base64 encoder."""
2395 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2396 def decode(cls, data: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2397 """Decode the data from base64 encoded bytes to original bytes data.
2399 Args:
2400 data: The data to decode.
2402 Returns:
2403 The decoded data.
2404 """
2405 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2406 return base64.b64decode(data) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2407 except ValueError as e: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2408 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2410 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2411 def encode(cls, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2412 """Encode the data from bytes to a base64 encoded bytes.
2414 Args:
2415 value: The data to encode.
2417 Returns:
2418 The encoded data.
2419 """
2420 return base64.b64encode(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2422 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2423 def get_json_format(cls) -> Literal['base64']: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2424 """Get the JSON format for the encoded data.
2426 Returns:
2427 The JSON format for the encoded data.
2428 """
2429 return 'base64' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2432class Base64UrlEncoder(EncoderProtocol): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2433 """URL-safe Base64 encoder."""
2435 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2436 def decode(cls, data: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2437 """Decode the data from base64 encoded bytes to original bytes data.
2439 Args:
2440 data: The data to decode.
2442 Returns:
2443 The decoded data.
2444 """
2445 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2446 return base64.urlsafe_b64decode(data) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2447 except ValueError as e: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2448 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2450 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2451 def encode(cls, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2452 """Encode the data from bytes to a base64 encoded bytes.
2454 Args:
2455 value: The data to encode.
2457 Returns:
2458 The encoded data.
2459 """
2460 return base64.urlsafe_b64encode(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2462 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2463 def get_json_format(cls) -> Literal['base64url']: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2464 """Get the JSON format for the encoded data.
2466 Returns:
2467 The JSON format for the encoded data.
2468 """
2469 return 'base64url' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2472@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2473class EncodedBytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2474 """A bytes type that is encoded and decoded using the specified encoder.
2476 `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate.
2478 ```python
2479 from typing import Annotated
2481 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError
2483 class MyEncoder(EncoderProtocol):
2484 @classmethod
2485 def decode(cls, data: bytes) -> bytes:
2486 if data == b'**undecodable**':
2487 raise ValueError('Cannot decode data')
2488 return data[13:]
2490 @classmethod
2491 def encode(cls, value: bytes) -> bytes:
2492 return b'**encoded**: ' + value
2494 @classmethod
2495 def get_json_format(cls) -> str:
2496 return 'my-encoder'
2498 MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)]
2500 class Model(BaseModel):
2501 my_encoded_bytes: MyEncodedBytes
2503 # Initialize the model with encoded data
2504 m = Model(my_encoded_bytes=b'**encoded**: some bytes')
2506 # Access decoded value
2507 print(m.my_encoded_bytes)
2508 #> b'some bytes'
2510 # Serialize into the encoded form
2511 print(m.model_dump())
2512 #> {'my_encoded_bytes': b'**encoded**: some bytes'}
2514 # Validate encoded data
2515 try:
2516 Model(my_encoded_bytes=b'**undecodable**')
2517 except ValidationError as e:
2518 print(e)
2519 '''
2520 1 validation error for Model
2521 my_encoded_bytes
2522 Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes]
2523 '''
2524 ```
2525 """
2527 encoder: type[EncoderProtocol] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2529 def __get_pydantic_json_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2530 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2531 ) -> JsonSchemaValue:
2532 field_schema = handler(core_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2533 field_schema.update(type='string', format=self.encoder.get_json_format()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2534 return field_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2536 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2537 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2538 _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2539 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2540 function=self.decode,
2541 schema=schema,
2542 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode),
2543 )
2545 def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2546 """Decode the data using the specified encoder.
2548 Args:
2549 data: The data to decode.
2551 Returns:
2552 The decoded data.
2553 """
2554 return self.encoder.decode(data) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2556 def encode(self, value: bytes) -> bytes: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2557 """Encode the data using the specified encoder.
2559 Args:
2560 value: The data to encode.
2562 Returns:
2563 The encoded data.
2564 """
2565 return self.encoder.encode(value) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2567 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2568 return hash(self.encoder) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2571@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2572class EncodedStr: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2573 """A str type that is encoded and decoded using the specified encoder.
2575 `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate.
2577 ```python
2578 from typing import Annotated
2580 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError
2582 class MyEncoder(EncoderProtocol):
2583 @classmethod
2584 def decode(cls, data: bytes) -> bytes:
2585 if data == b'**undecodable**':
2586 raise ValueError('Cannot decode data')
2587 return data[13:]
2589 @classmethod
2590 def encode(cls, value: bytes) -> bytes:
2591 return b'**encoded**: ' + value
2593 @classmethod
2594 def get_json_format(cls) -> str:
2595 return 'my-encoder'
2597 MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)]
2599 class Model(BaseModel):
2600 my_encoded_str: MyEncodedStr
2602 # Initialize the model with encoded data
2603 m = Model(my_encoded_str='**encoded**: some str')
2605 # Access decoded value
2606 print(m.my_encoded_str)
2607 #> some str
2609 # Serialize into the encoded form
2610 print(m.model_dump())
2611 #> {'my_encoded_str': '**encoded**: some str'}
2613 # Validate encoded data
2614 try:
2615 Model(my_encoded_str='**undecodable**')
2616 except ValidationError as e:
2617 print(e)
2618 '''
2619 1 validation error for Model
2620 my_encoded_str
2621 Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str]
2622 '''
2623 ```
2624 """
2626 encoder: type[EncoderProtocol] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2628 def __get_pydantic_json_schema__( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2629 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2630 ) -> JsonSchemaValue:
2631 field_schema = handler(core_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2632 field_schema.update(type='string', format=self.encoder.get_json_format()) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2633 return field_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2635 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2636 schema = handler(source) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2637 _check_annotated_type(schema['type'], 'str', self.__class__.__name__) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2638 return core_schema.with_info_after_validator_function( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2639 function=self.decode_str,
2640 schema=schema,
2641 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str),
2642 )
2644 def decode_str(self, data: str, _: core_schema.ValidationInfo) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2645 """Decode the data using the specified encoder.
2647 Args:
2648 data: The data to decode.
2650 Returns:
2651 The decoded data.
2652 """
2653 return self.encoder.decode(data.encode()).decode() 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2655 def encode_str(self, value: str) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2656 """Encode the data using the specified encoder.
2658 Args:
2659 value: The data to encode.
2661 Returns:
2662 The encoded data.
2663 """
2664 return self.encoder.encode(value.encode()).decode() # noqa: UP008 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2666 def __hash__(self) -> int: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2667 return hash(self.encoder) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2670Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2671"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2673Note:
2674 Under the hood, `Base64Bytes` uses the standard library `base64.b64encode` and `base64.b64decode` functions.
2676 As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect
2677 decoding.
2679Warning:
2680 In versions of Pydantic prior to v2.10, `Base64Bytes` used [`base64.encodebytes`][base64.encodebytes]
2681 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html),
2682 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern
2683 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions.
2685 If you'd still like to use these legacy encoders / decoders, you can achieve this by creating a custom annotated type,
2686 like follows:
2688 ```python
2689 import base64
2690 from typing import Annotated, Literal
2692 from pydantic_core import PydanticCustomError
2694 from pydantic import EncodedBytes, EncoderProtocol
2696 class LegacyBase64Encoder(EncoderProtocol):
2697 @classmethod
2698 def decode(cls, data: bytes) -> bytes:
2699 try:
2700 return base64.decodebytes(data)
2701 except ValueError as e:
2702 raise PydanticCustomError(
2703 'base64_decode',
2704 "Base64 decoding error: '{error}'",
2705 {'error': str(e)},
2706 )
2708 @classmethod
2709 def encode(cls, value: bytes) -> bytes:
2710 return base64.encodebytes(value)
2712 @classmethod
2713 def get_json_format(cls) -> Literal['base64']:
2714 return 'base64'
2716 LegacyBase64Bytes = Annotated[bytes, EncodedBytes(encoder=LegacyBase64Encoder)]
2717 ```
2719```python
2720from pydantic import Base64Bytes, BaseModel, ValidationError
2722class Model(BaseModel):
2723 base64_bytes: Base64Bytes
2725# Initialize the model with base64 data
2726m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5')
2728# Access decoded value
2729print(m.base64_bytes)
2730#> b'This is the way'
2732# Serialize into the base64 form
2733print(m.model_dump())
2734#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5'}
2736# Validate base64 data
2737try:
2738 print(Model(base64_bytes=b'undecodable').base64_bytes)
2739except ValidationError as e:
2740 print(e)
2741 '''
2742 1 validation error for Model
2743 base64_bytes
2744 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes]
2745 '''
2746```
2747"""
2748Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2749"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2751Note:
2752 Under the hood, `Base64Str` uses the standard library `base64.b64encode` and `base64.b64decode` functions.
2754 As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect
2755 decoding.
2757Warning:
2758 In versions of Pydantic prior to v2.10, `Base64Str` used [`base64.encodebytes`][base64.encodebytes]
2759 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html),
2760 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern
2761 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions.
2763 See the [`Base64Bytes`][pydantic.types.Base64Bytes] type for more information on how to
2764 replicate the old behavior with the legacy encoders / decoders.
2766```python
2767from pydantic import Base64Str, BaseModel, ValidationError
2769class Model(BaseModel):
2770 base64_str: Base64Str
2772# Initialize the model with base64 data
2773m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y')
2775# Access decoded value
2776print(m.base64_str)
2777#> These aren't the droids you're looking for
2779# Serialize into the base64 form
2780print(m.model_dump())
2781#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y'}
2783# Validate base64 data
2784try:
2785 print(Model(base64_str='undecodable').base64_str)
2786except ValidationError as e:
2787 print(e)
2788 '''
2789 1 validation error for Model
2790 base64_str
2791 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str]
2792 '''
2793```
2794"""
2795Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2796"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2798Note:
2799 Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2800 functions.
2802 As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data
2803 (using `'+'` and `'/'`).
2805```python
2806from pydantic import Base64UrlBytes, BaseModel
2808class Model(BaseModel):
2809 base64url_bytes: Base64UrlBytes
2811# Initialize the model with base64 data
2812m = Model(base64url_bytes=b'SHc_dHc-TXc==')
2813print(m)
2814#> base64url_bytes=b'Hw?tw>Mw'
2815```
2816"""
2817Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2818"""A str type that is encoded and decoded using the URL-safe base64 encoder. 1abcdefghijklmnopqrsJtuvwxyzAB
2820Note:
2821 Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2822 functions.
2824 As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`).
2826```python
2827from pydantic import Base64UrlStr, BaseModel
2829class Model(BaseModel):
2830 base64url_str: Base64UrlStr
2832# Initialize the model with base64 data
2833m = Model(base64url_str='SHc_dHc-TXc==')
2834print(m)
2835#> base64url_str='Hw?tw>Mw'
2836```
2837"""
2840__getattr__ = getattr_migration(__name__) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2843@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2844class GetPydanticSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2845 """!!! abstract "Usage Documentation"
2846 [Using `GetPydanticSchema` to Reduce Boilerplate](../concepts/types.md#using-getpydanticschema-to-reduce-boilerplate)
2848 A convenience class for creating an annotation that provides pydantic custom type hooks.
2850 This class is intended to eliminate the need to create a custom "marker" which defines the
2851 `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods.
2853 For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do:
2854 ```python
2855 from typing import Annotated, Any
2857 from pydantic import BaseModel, GetPydanticSchema
2859 HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any))
2861 class Model(BaseModel):
2862 x: Annotated[int, HandleAsAny] # pydantic sees `x: Any`
2864 print(repr(Model(x='abc').x))
2865 #> 'abc'
2866 ```
2867 """
2869 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2870 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2872 # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:`
2873 # which returns `GetPydanticSchema(lambda _s, h: h(type_))`
2875 if not TYPE_CHECKING: 2875 ↛ 2887line 2875 didn't jump to line 2887 because the condition on line 2875 was always true1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2876 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
2878 def __getattr__(self, item: str) -> Any: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2879 """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls."""
2880 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2881 return self.get_pydantic_core_schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2882 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2882 ↛ 2883line 2882 didn't jump to line 2883 because the condition on line 2882 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2883 return self.get_pydantic_json_schema
2884 else:
2885 return object.__getattribute__(self, item) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2887 __hash__ = object.__hash__ 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2890@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2891class Tag: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2892 """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union.
2894 Also provides a way to label a union case in error messages.
2896 When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that
2897 should be used to identify that case. For example, in the below example, the `Tag` is used to specify that
2898 if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it
2899 returns `'pumpkin'`, the input should be validated as a `PumpkinPie`.
2901 The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to
2902 the appropriate member of the `Union` in question.
2904 ```python
2905 from typing import Annotated, Any, Literal, Union
2907 from pydantic import BaseModel, Discriminator, Tag
2909 class Pie(BaseModel):
2910 time_to_cook: int
2911 num_ingredients: int
2913 class ApplePie(Pie):
2914 fruit: Literal['apple'] = 'apple'
2916 class PumpkinPie(Pie):
2917 filling: Literal['pumpkin'] = 'pumpkin'
2919 def get_discriminator_value(v: Any) -> str:
2920 if isinstance(v, dict):
2921 return v.get('fruit', v.get('filling'))
2922 return getattr(v, 'fruit', getattr(v, 'filling', None))
2924 class ThanksgivingDinner(BaseModel):
2925 dessert: Annotated[
2926 Union[
2927 Annotated[ApplePie, Tag('apple')],
2928 Annotated[PumpkinPie, Tag('pumpkin')],
2929 ],
2930 Discriminator(get_discriminator_value),
2931 ]
2933 apple_variation = ThanksgivingDinner.model_validate(
2934 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
2935 )
2936 print(repr(apple_variation))
2937 '''
2938 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
2939 '''
2941 pumpkin_variation = ThanksgivingDinner.model_validate(
2942 {
2943 'dessert': {
2944 'filling': 'pumpkin',
2945 'time_to_cook': 40,
2946 'num_ingredients': 6,
2947 }
2948 }
2949 )
2950 print(repr(pumpkin_variation))
2951 '''
2952 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
2953 '''
2954 ```
2956 !!! note
2957 You must specify a `Tag` for every case in a `Tag` that is associated with a
2958 callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code
2959 [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag).
2961 See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s.
2963 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
2964 """
2966 tag: str 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2968 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2969 schema = handler(source_type) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2970 metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2971 metadata['pydantic_internal_union_tag_key'] = self.tag 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2972 return schema 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
2975@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2976class Discriminator: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
2977 """!!! abstract "Usage Documentation"
2978 [Discriminated Unions with `Callable` `Discriminator`](../concepts/unions.md#discriminated-unions-with-callable-discriminator)
2980 Provides a way to use a custom callable as the way to extract the value of a union discriminator.
2982 This allows you to get validation behavior like you'd get from `Field(discriminator=<field_name>)`,
2983 but without needing to have a single shared field across all the union choices. This also makes it
2984 possible to handle unions of models and primitive types with discriminated-union-style validation errors.
2985 Finally, this allows you to use a custom callable as the way to identify which member of a union a value
2986 belongs to, while still seeing all the performance benefits of a discriminated union.
2988 Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion`
2989 than it would be as a normal `Union`.
2991 ```python
2992 from typing import Annotated, Any, Literal, Union
2994 from pydantic import BaseModel, Discriminator, Tag
2996 class Pie(BaseModel):
2997 time_to_cook: int
2998 num_ingredients: int
3000 class ApplePie(Pie):
3001 fruit: Literal['apple'] = 'apple'
3003 class PumpkinPie(Pie):
3004 filling: Literal['pumpkin'] = 'pumpkin'
3006 def get_discriminator_value(v: Any) -> str:
3007 if isinstance(v, dict):
3008 return v.get('fruit', v.get('filling'))
3009 return getattr(v, 'fruit', getattr(v, 'filling', None))
3011 class ThanksgivingDinner(BaseModel):
3012 dessert: Annotated[
3013 Union[
3014 Annotated[ApplePie, Tag('apple')],
3015 Annotated[PumpkinPie, Tag('pumpkin')],
3016 ],
3017 Discriminator(get_discriminator_value),
3018 ]
3020 apple_variation = ThanksgivingDinner.model_validate(
3021 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
3022 )
3023 print(repr(apple_variation))
3024 '''
3025 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
3026 '''
3028 pumpkin_variation = ThanksgivingDinner.model_validate(
3029 {
3030 'dessert': {
3031 'filling': 'pumpkin',
3032 'time_to_cook': 40,
3033 'num_ingredients': 6,
3034 }
3035 }
3036 )
3037 print(repr(pumpkin_variation))
3038 '''
3039 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
3040 '''
3041 ```
3043 See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s.
3045 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
3046 """
3048 discriminator: str | Callable[[Any], Hashable] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3049 """The callable or field name for discriminating the type in a tagged union. 1abcdefghijklmnopqrsJtuvwxyzAB
3051 A `Callable` discriminator must extract the value of the discriminator from the input.
3052 A `str` discriminator must be the name of a field to discriminate against.
3053 """
3054 custom_error_type: str | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3055 """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union 1abcdefghijklmnopqrsJtuvwxyzAB
3056 validation errors.
3057 """
3058 custom_error_message: str | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3059 """Message to use in custom errors.""" 1abcdefghijklmnopqrsJtuvwxyzAB
3060 custom_error_context: dict[str, int | str | float] | None = None 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3061 """Context to use in custom errors.""" 1abcdefghijklmnopqrsJtuvwxyzAB
3063 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3064 if not is_union_origin(get_origin(source_type)): 3064 ↛ 3065line 3064 didn't jump to line 3065 because the condition on line 3064 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3065 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}')
3067 if isinstance(self.discriminator, str): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3068 from pydantic import Field 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3070 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3071 else:
3072 original_schema = handler(source_type) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3073 return self._convert_schema(original_schema, handler) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3075 def _convert_schema( 1CDabcdefghiFGklmnopqrsJHItuvwxyzAB
3076 self, original_schema: core_schema.CoreSchema, handler: GetCoreSchemaHandler | None = None
3077 ) -> core_schema.TaggedUnionSchema:
3078 if original_schema['type'] != 'union': 3078 ↛ 3083line 3078 didn't jump to line 3083 because the condition on line 3078 was never true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3079 # This likely indicates that the schema was a single-item union that was simplified.
3080 # In this case, we do the same thing we do in
3081 # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely,
3082 # package the generated schema back into a single-item union.
3083 original_schema = core_schema.union_schema([original_schema])
3085 tagged_union_choices = {} 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3086 for choice in original_schema['choices']: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3087 tag = None 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3088 if isinstance(choice, tuple): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3089 choice, tag = choice 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3090 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3091 if metadata is not None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3092 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3093 if tag is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3094 # `handler` is None when this method is called from `apply_discriminator()` (deferred discriminators)
3095 if handler is not None and choice['type'] == 'definition-ref': 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3096 # If choice was built from a PEP 695 type alias, try to resolve the def:
3097 try: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3098 choice = handler.resolve_ref_schema(choice) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3099 except LookupError: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3100 pass 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3101 else:
3102 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3103 if metadata is not None: 3103 ↛ 3106line 3103 didn't jump to line 3106 because the condition on line 3103 was always true1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3104 tag = metadata.get('pydantic_internal_union_tag_key') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3106 if tag is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3107 raise PydanticUserError( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3108 f'`Tag` not provided for choice {choice} used with `Discriminator`',
3109 code='callable-discriminator-no-tag',
3110 )
3111 tagged_union_choices[tag] = choice 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3113 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored
3114 custom_error_type = self.custom_error_type 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3115 if custom_error_type is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3116 custom_error_type = original_schema.get('custom_error_type') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3118 custom_error_message = self.custom_error_message 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3119 if custom_error_message is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3120 custom_error_message = original_schema.get('custom_error_message') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3122 custom_error_context = self.custom_error_context 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3123 if custom_error_context is None: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3124 custom_error_context = original_schema.get('custom_error_context') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3126 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3127 return core_schema.tagged_union_schema( 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3128 tagged_union_choices,
3129 self.discriminator,
3130 custom_error_type=custom_error_type,
3131 custom_error_message=custom_error_message,
3132 custom_error_context=custom_error_context,
3133 strict=original_schema.get('strict'),
3134 ref=original_schema.get('ref'),
3135 metadata=original_schema.get('metadata'),
3136 serialization=original_schema.get('serialization'),
3137 )
3140_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3143def _get_type_name(x: Any) -> str: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3144 type_ = type(x) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3145 if type_ in _JSON_TYPES: 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3146 return type_.__name__ 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3148 # Handle proper subclasses; note we don't need to handle None or bool here
3149 if isinstance(x, int): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3150 return 'int' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3151 if isinstance(x, float): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3152 return 'float' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3153 if isinstance(x, str): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3154 return 'str' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3155 if isinstance(x, list): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3156 return 'list' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3157 if isinstance(x, dict): 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3158 return 'dict' 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3160 # Fail by returning the type's actual name
3161 return getattr(type_, '__name__', '<no type name>') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3164class _AllowAnyJson: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3165 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3166 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3167 python_schema = handler(source_type) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3168 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3171if TYPE_CHECKING: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3172 # This seems to only be necessary for mypy
3173 JsonValue: TypeAlias = Union[
3174 list['JsonValue'],
3175 dict[str, 'JsonValue'],
3176 str,
3177 bool,
3178 int,
3179 float,
3180 None,
3181 ]
3182 """A `JsonValue` is used to represent a value that can be serialized to JSON.
3184 It may be one of:
3186 * `list['JsonValue']`
3187 * `dict[str, 'JsonValue']`
3188 * `str`
3189 * `bool`
3190 * `int`
3191 * `float`
3192 * `None`
3194 The following example demonstrates how to use `JsonValue` to validate JSON data,
3195 and what kind of errors to expect when input data is not json serializable.
3197 ```python
3198 import json
3200 from pydantic import BaseModel, JsonValue, ValidationError
3202 class Model(BaseModel):
3203 j: JsonValue
3205 valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}}
3206 invalid_json_data = {'j': {'a': {'b': ...}}}
3208 print(repr(Model.model_validate(valid_json_data)))
3209 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
3210 print(repr(Model.model_validate_json(json.dumps(valid_json_data))))
3211 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
3213 try:
3214 Model.model_validate(invalid_json_data)
3215 except ValidationError as e:
3216 print(e)
3217 '''
3218 1 validation error for Model
3219 j.dict.a.dict.b
3220 input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis]
3221 '''
3222 ```
3223 """
3225else:
3226 JsonValue = TypeAliasType( 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3227 'JsonValue',
3228 Annotated[
3229 Union[
3230 Annotated[list['JsonValue'], Tag('list')],
3231 Annotated[dict[str, 'JsonValue'], Tag('dict')],
3232 Annotated[str, Tag('str')],
3233 Annotated[bool, Tag('bool')],
3234 Annotated[int, Tag('int')],
3235 Annotated[float, Tag('float')],
3236 Annotated[None, Tag('NoneType')],
3237 ],
3238 Discriminator(
3239 _get_type_name,
3240 custom_error_type='invalid-json-value',
3241 custom_error_message='input was not a valid JSON value',
3242 ),
3243 _AllowAnyJson,
3244 ],
3245 )
3248class _OnErrorOmit: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3249 @classmethod 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3250 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3251 # there is no actual default value here but we use with_default_schema since it already has the on_error
3252 # behavior implemented and it would be no more efficient to implement it on every other validator
3253 # or as a standalone validator
3254 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1CDabcdefghiEjFGklmnopqrsHItuvwxyzAB
3257OnErrorOmit = Annotated[T, _OnErrorOmit] 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3258""" 1abcdefghijklmnopqrsJtuvwxyzAB
3259When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc.
3260this annotation omits the item from the iteration if there is any error validating it.
3261That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded
3262any invalid items are discarded and the valid ones are returned.
3263"""
3266@_dataclasses.dataclass 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3267class FailFast(_fields.PydanticMetadata, BaseMetadata): 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB
3268 """A `FailFast` annotation can be used to specify that validation should stop at the first error.
3270 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.
3272 You might want to enable this setting if you want to validate your data faster (basically, if you use this,
3273 validation will be more performant with the caveat that you get less information).
3275 ```python
3276 from typing import Annotated
3278 from pydantic import BaseModel, FailFast, ValidationError
3280 class Model(BaseModel):
3281 x: Annotated[list[int], FailFast()]
3283 # This will raise a single error for the first invalid value and stop validation
3284 try:
3285 obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c'])
3286 except ValidationError as e:
3287 print(e)
3288 '''
3289 1 validation error for Model
3290 x.2
3291 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
3292 '''
3293 ```
3294 """
3296 fail_fast: bool = True 1CDabcdefghiEjFGklmnopqrsJHItuvwxyzAB