Coverage for pydantic/types.py: 97.46%
646 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-13 19:35 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-13 19:35 +0000
1"""The types module contains custom types used by pydantic."""
3from __future__ import annotations as _annotations 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
5import base64 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
6import dataclasses as _dataclasses 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
7import re 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
8from collections.abc import Hashable, Iterator 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
9from datetime import date, datetime 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
10from decimal import Decimal 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
11from enum import Enum 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
12from pathlib import Path 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
13from re import Pattern 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
14from types import ModuleType 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
15from typing import ( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
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 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
29import annotated_types 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
30from annotated_types import BaseMetadata, MaxLen, MinLen 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
31from pydantic_core import CoreSchema, PydanticCustomError, SchemaSerializer, core_schema 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
32from typing_extensions import Protocol, TypeAlias, TypeAliasType, deprecated, get_args, get_origin 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
34from ._internal import _fields, _internal_dataclass, _typing_extra, _utils, _validators 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
35from ._migration import getattr_migration 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
36from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
37from .errors import PydanticUserError 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
38from .json_schema import JsonSchemaValue 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
39from .warnings import PydanticDeprecatedSince20 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
41if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
42 from ._internal._core_metadata import CoreMetadata
44__all__ = ( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
45 'Strict',
46 'StrictStr',
47 'SocketPath',
48 'conbytes',
49 'conlist',
50 'conset',
51 'confrozenset',
52 'constr',
53 'ImportString',
54 'conint',
55 'PositiveInt',
56 'NegativeInt',
57 'NonNegativeInt',
58 'NonPositiveInt',
59 'confloat',
60 'PositiveFloat',
61 'NegativeFloat',
62 'NonNegativeFloat',
63 'NonPositiveFloat',
64 'FiniteFloat',
65 'condecimal',
66 'UUID1',
67 'UUID3',
68 'UUID4',
69 'UUID5',
70 'FilePath',
71 'DirectoryPath',
72 'NewPath',
73 'Json',
74 'Secret',
75 'SecretStr',
76 'SecretBytes',
77 'StrictBool',
78 'StrictBytes',
79 'StrictInt',
80 'StrictFloat',
81 'PaymentCardNumber',
82 'ByteSize',
83 'PastDate',
84 'FutureDate',
85 'PastDatetime',
86 'FutureDatetime',
87 'condate',
88 'AwareDatetime',
89 'NaiveDatetime',
90 'AllowInfNan',
91 'EncoderProtocol',
92 'EncodedBytes',
93 'EncodedStr',
94 'Base64Encoder',
95 'Base64Bytes',
96 'Base64Str',
97 'Base64UrlBytes',
98 'Base64UrlStr',
99 'GetPydanticSchema',
100 'StringConstraints',
101 'Tag',
102 'Discriminator',
103 'JsonValue',
104 'OnErrorOmit',
105 'FailFast',
106)
109T = TypeVar('T') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
112@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
113class Strict(_fields.PydanticMetadata, BaseMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
114 """!!! abstract "Usage Documentation"
115 [Strict Mode with `Annotated` `Strict`](../concepts/strict_mode.md#strict-mode-with-annotated-strict)
117 A field metadata class to indicate that a field should be validated in strict mode.
118 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
120 Attributes:
121 strict: Whether to validate the field in strict mode.
123 Example:
124 ```python
125 from typing import Annotated
127 from pydantic.types import Strict
129 StrictBool = Annotated[bool, Strict()]
130 ```
131 """
133 strict: bool = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
135 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
136 return hash(self.strict) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
139# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141StrictBool = Annotated[bool, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
142"""A boolean that must be either ``True`` or ``False``.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
144# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147def conint( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
148 *,
149 strict: bool | None = None,
150 gt: int | None = None,
151 ge: int | None = None,
152 lt: int | None = None,
153 le: int | None = None,
154 multiple_of: int | None = None,
155) -> type[int]:
156 """
157 !!! warning "Discouraged"
158 This function is **discouraged** in favor of using
159 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
160 [`Field`][pydantic.fields.Field] instead.
162 This function will be **deprecated** in Pydantic 3.0.
164 The reason is that `conint` returns a type, which doesn't play well with static analysis tools.
166 === ":x: Don't do this"
167 ```python
168 from pydantic import BaseModel, conint
170 class Foo(BaseModel):
171 bar: conint(strict=True, gt=0)
172 ```
174 === ":white_check_mark: Do this"
175 ```python
176 from typing import Annotated
178 from pydantic import BaseModel, Field
180 class Foo(BaseModel):
181 bar: Annotated[int, Field(strict=True, gt=0)]
182 ```
184 A wrapper around `int` that allows for additional constraints.
186 Args:
187 strict: Whether to validate the integer in strict mode. Defaults to `None`.
188 gt: The value must be greater than this.
189 ge: The value must be greater than or equal to this.
190 lt: The value must be less than this.
191 le: The value must be less than or equal to this.
192 multiple_of: The value must be a multiple of this.
194 Returns:
195 The wrapped integer type.
197 ```python
198 from pydantic import BaseModel, ValidationError, conint
200 class ConstrainedExample(BaseModel):
201 constrained_int: conint(gt=1)
203 m = ConstrainedExample(constrained_int=2)
204 print(repr(m))
205 #> ConstrainedExample(constrained_int=2)
207 try:
208 ConstrainedExample(constrained_int=0)
209 except ValidationError as e:
210 print(e.errors())
211 '''
212 [
213 {
214 'type': 'greater_than',
215 'loc': ('constrained_int',),
216 'msg': 'Input should be greater than 1',
217 'input': 0,
218 'ctx': {'gt': 1},
219 'url': 'https://errors.pydantic.dev/2/v/greater_than',
220 }
221 ]
222 '''
223 ```
225 """ # noqa: D212
226 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
227 int,
228 Strict(strict) if strict is not None else None,
229 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
230 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
231 ]
234PositiveInt = Annotated[int, annotated_types.Gt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
235"""An integer that must be greater than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
237```python
238from pydantic import BaseModel, PositiveInt, ValidationError
240class Model(BaseModel):
241 positive_int: PositiveInt
243m = Model(positive_int=1)
244print(repr(m))
245#> Model(positive_int=1)
247try:
248 Model(positive_int=-1)
249except ValidationError as e:
250 print(e.errors())
251 '''
252 [
253 {
254 'type': 'greater_than',
255 'loc': ('positive_int',),
256 'msg': 'Input should be greater than 0',
257 'input': -1,
258 'ctx': {'gt': 0},
259 'url': 'https://errors.pydantic.dev/2/v/greater_than',
260 }
261 ]
262 '''
263```
264"""
265NegativeInt = Annotated[int, annotated_types.Lt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
266"""An integer that must be less than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
268```python
269from pydantic import BaseModel, NegativeInt, ValidationError
271class Model(BaseModel):
272 negative_int: NegativeInt
274m = Model(negative_int=-1)
275print(repr(m))
276#> Model(negative_int=-1)
278try:
279 Model(negative_int=1)
280except ValidationError as e:
281 print(e.errors())
282 '''
283 [
284 {
285 'type': 'less_than',
286 'loc': ('negative_int',),
287 'msg': 'Input should be less than 0',
288 'input': 1,
289 'ctx': {'lt': 0},
290 'url': 'https://errors.pydantic.dev/2/v/less_than',
291 }
292 ]
293 '''
294```
295"""
296NonPositiveInt = Annotated[int, annotated_types.Le(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
297"""An integer that must be less than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
299```python
300from pydantic import BaseModel, NonPositiveInt, ValidationError
302class Model(BaseModel):
303 non_positive_int: NonPositiveInt
305m = Model(non_positive_int=0)
306print(repr(m))
307#> Model(non_positive_int=0)
309try:
310 Model(non_positive_int=1)
311except ValidationError as e:
312 print(e.errors())
313 '''
314 [
315 {
316 'type': 'less_than_equal',
317 'loc': ('non_positive_int',),
318 'msg': 'Input should be less than or equal to 0',
319 'input': 1,
320 'ctx': {'le': 0},
321 'url': 'https://errors.pydantic.dev/2/v/less_than_equal',
322 }
323 ]
324 '''
325```
326"""
327NonNegativeInt = Annotated[int, annotated_types.Ge(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
328"""An integer that must be greater than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
330```python
331from pydantic import BaseModel, NonNegativeInt, ValidationError
333class Model(BaseModel):
334 non_negative_int: NonNegativeInt
336m = Model(non_negative_int=0)
337print(repr(m))
338#> Model(non_negative_int=0)
340try:
341 Model(non_negative_int=-1)
342except ValidationError as e:
343 print(e.errors())
344 '''
345 [
346 {
347 'type': 'greater_than_equal',
348 'loc': ('non_negative_int',),
349 'msg': 'Input should be greater than or equal to 0',
350 'input': -1,
351 'ctx': {'ge': 0},
352 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal',
353 }
354 ]
355 '''
356```
357"""
358StrictInt = Annotated[int, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
359"""An integer that must be validated in strict mode. 1bcdefghiajklmnopqGHIJKLrstuvwxy
361```python
362from pydantic import BaseModel, StrictInt, ValidationError
364class StrictIntModel(BaseModel):
365 strict_int: StrictInt
367try:
368 StrictIntModel(strict_int=3.14159)
369except ValidationError as e:
370 print(e)
371 '''
372 1 validation error for StrictIntModel
373 strict_int
374 Input should be a valid integer [type=int_type, input_value=3.14159, input_type=float]
375 '''
376```
377"""
379# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
382@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
383class AllowInfNan(_fields.PydanticMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
384 """A field metadata class to indicate that a field should allow `-inf`, `inf`, and `nan`.
386 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
388 Attributes:
389 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. Defaults to `True`.
391 Example:
392 ```python
393 from typing import Annotated
395 from pydantic.types import AllowInfNan
397 LaxFloat = Annotated[float, AllowInfNan()]
398 ```
399 """
401 allow_inf_nan: bool = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
403 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
404 return hash(self.allow_inf_nan) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
407def confloat( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
408 *,
409 strict: bool | None = None,
410 gt: float | None = None,
411 ge: float | None = None,
412 lt: float | None = None,
413 le: float | None = None,
414 multiple_of: float | None = None,
415 allow_inf_nan: bool | None = None,
416) -> type[float]:
417 """
418 !!! warning "Discouraged"
419 This function is **discouraged** in favor of using
420 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
421 [`Field`][pydantic.fields.Field] instead.
423 This function will be **deprecated** in Pydantic 3.0.
425 The reason is that `confloat` returns a type, which doesn't play well with static analysis tools.
427 === ":x: Don't do this"
428 ```python
429 from pydantic import BaseModel, confloat
431 class Foo(BaseModel):
432 bar: confloat(strict=True, gt=0)
433 ```
435 === ":white_check_mark: Do this"
436 ```python
437 from typing import Annotated
439 from pydantic import BaseModel, Field
441 class Foo(BaseModel):
442 bar: Annotated[float, Field(strict=True, gt=0)]
443 ```
445 A wrapper around `float` that allows for additional constraints.
447 Args:
448 strict: Whether to validate the float in strict mode.
449 gt: The value must be greater than this.
450 ge: The value must be greater than or equal to this.
451 lt: The value must be less than this.
452 le: The value must be less than or equal to this.
453 multiple_of: The value must be a multiple of this.
454 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`.
456 Returns:
457 The wrapped float type.
459 ```python
460 from pydantic import BaseModel, ValidationError, confloat
462 class ConstrainedExample(BaseModel):
463 constrained_float: confloat(gt=1.0)
465 m = ConstrainedExample(constrained_float=1.1)
466 print(repr(m))
467 #> ConstrainedExample(constrained_float=1.1)
469 try:
470 ConstrainedExample(constrained_float=0.9)
471 except ValidationError as e:
472 print(e.errors())
473 '''
474 [
475 {
476 'type': 'greater_than',
477 'loc': ('constrained_float',),
478 'msg': 'Input should be greater than 1',
479 'input': 0.9,
480 'ctx': {'gt': 1.0},
481 'url': 'https://errors.pydantic.dev/2/v/greater_than',
482 }
483 ]
484 '''
485 ```
486 """ # noqa: D212
487 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
488 float,
489 Strict(strict) if strict is not None else None,
490 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
491 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
492 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None,
493 ]
496PositiveFloat = Annotated[float, annotated_types.Gt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
497"""A float that must be greater than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
499```python
500from pydantic import BaseModel, PositiveFloat, ValidationError
502class Model(BaseModel):
503 positive_float: PositiveFloat
505m = Model(positive_float=1.0)
506print(repr(m))
507#> Model(positive_float=1.0)
509try:
510 Model(positive_float=-1.0)
511except ValidationError as e:
512 print(e.errors())
513 '''
514 [
515 {
516 'type': 'greater_than',
517 'loc': ('positive_float',),
518 'msg': 'Input should be greater than 0',
519 'input': -1.0,
520 'ctx': {'gt': 0.0},
521 'url': 'https://errors.pydantic.dev/2/v/greater_than',
522 }
523 ]
524 '''
525```
526"""
527NegativeFloat = Annotated[float, annotated_types.Lt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
528"""A float that must be less than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
530```python
531from pydantic import BaseModel, NegativeFloat, ValidationError
533class Model(BaseModel):
534 negative_float: NegativeFloat
536m = Model(negative_float=-1.0)
537print(repr(m))
538#> Model(negative_float=-1.0)
540try:
541 Model(negative_float=1.0)
542except ValidationError as e:
543 print(e.errors())
544 '''
545 [
546 {
547 'type': 'less_than',
548 'loc': ('negative_float',),
549 'msg': 'Input should be less than 0',
550 'input': 1.0,
551 'ctx': {'lt': 0.0},
552 'url': 'https://errors.pydantic.dev/2/v/less_than',
553 }
554 ]
555 '''
556```
557"""
558NonPositiveFloat = Annotated[float, annotated_types.Le(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
559"""A float that must be less than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
561```python
562from pydantic import BaseModel, NonPositiveFloat, ValidationError
564class Model(BaseModel):
565 non_positive_float: NonPositiveFloat
567m = Model(non_positive_float=0.0)
568print(repr(m))
569#> Model(non_positive_float=0.0)
571try:
572 Model(non_positive_float=1.0)
573except ValidationError as e:
574 print(e.errors())
575 '''
576 [
577 {
578 'type': 'less_than_equal',
579 'loc': ('non_positive_float',),
580 'msg': 'Input should be less than or equal to 0',
581 'input': 1.0,
582 'ctx': {'le': 0.0},
583 'url': 'https://errors.pydantic.dev/2/v/less_than_equal',
584 }
585 ]
586 '''
587```
588"""
589NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
590"""A float that must be greater than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy
592```python
593from pydantic import BaseModel, NonNegativeFloat, ValidationError
595class Model(BaseModel):
596 non_negative_float: NonNegativeFloat
598m = Model(non_negative_float=0.0)
599print(repr(m))
600#> Model(non_negative_float=0.0)
602try:
603 Model(non_negative_float=-1.0)
604except ValidationError as e:
605 print(e.errors())
606 '''
607 [
608 {
609 'type': 'greater_than_equal',
610 'loc': ('non_negative_float',),
611 'msg': 'Input should be greater than or equal to 0',
612 'input': -1.0,
613 'ctx': {'ge': 0.0},
614 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal',
615 }
616 ]
617 '''
618```
619"""
620StrictFloat = Annotated[float, Strict(True)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
621"""A float that must be validated in strict mode. 1bcdefghiajklmnopqGHIJKLrstuvwxy
623```python
624from pydantic import BaseModel, StrictFloat, ValidationError
626class StrictFloatModel(BaseModel):
627 strict_float: StrictFloat
629try:
630 StrictFloatModel(strict_float='1.0')
631except ValidationError as e:
632 print(e)
633 '''
634 1 validation error for StrictFloatModel
635 strict_float
636 Input should be a valid number [type=float_type, input_value='1.0', input_type=str]
637 '''
638```
639"""
640FiniteFloat = Annotated[float, AllowInfNan(False)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
641"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). 1bcdefghiajklmnopqGHIJKLrstuvwxy
643```python
644from pydantic import BaseModel, FiniteFloat
646class Model(BaseModel):
647 finite: FiniteFloat
649m = Model(finite=1.0)
650print(m)
651#> finite=1.0
652```
653"""
656# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
659def conbytes( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
660 *,
661 min_length: int | None = None,
662 max_length: int | None = None,
663 strict: bool | None = None,
664) -> type[bytes]:
665 """A wrapper around `bytes` that allows for additional constraints.
667 Args:
668 min_length: The minimum length of the bytes.
669 max_length: The maximum length of the bytes.
670 strict: Whether to validate the bytes in strict mode.
672 Returns:
673 The wrapped bytes type.
674 """
675 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
676 bytes,
677 Strict(strict) if strict is not None else None,
678 annotated_types.Len(min_length or 0, max_length),
679 ]
682StrictBytes = Annotated[bytes, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
683"""A bytes that must be validated in strict mode.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
686# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
689@_dataclasses.dataclass(frozen=True) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
690class StringConstraints(annotated_types.GroupedMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
691 """!!! abstract "Usage Documentation"
692 [`StringConstraints`](../concepts/fields.md#string-constraints)
694 A field metadata class to apply constraints to `str` types.
695 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
697 Attributes:
698 strip_whitespace: Whether to remove leading and trailing whitespace.
699 to_upper: Whether to convert the string to uppercase.
700 to_lower: Whether to convert the string to lowercase.
701 strict: Whether to validate the string in strict mode.
702 min_length: The minimum length of the string.
703 max_length: The maximum length of the string.
704 pattern: A regex pattern that the string must match.
706 Example:
707 ```python
708 from typing import Annotated
710 from pydantic.types import StringConstraints
712 ConstrainedStr = Annotated[str, StringConstraints(min_length=1, max_length=10)]
713 ```
714 """
716 strip_whitespace: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
717 to_upper: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
718 to_lower: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
719 strict: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
720 min_length: int | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
721 max_length: int | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
722 pattern: str | Pattern[str] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
724 def __iter__(self) -> Iterator[BaseMetadata]: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
725 if self.min_length is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
726 yield MinLen(self.min_length) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
727 if self.max_length is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
728 yield MaxLen(self.max_length) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
729 if self.strict is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
730 yield Strict(self.strict) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
731 if ( 1zABa
732 self.strip_whitespace is not None
733 or self.pattern is not None
734 or self.to_lower is not None
735 or self.to_upper is not None
736 ):
737 yield _fields.pydantic_general_metadata( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
738 strip_whitespace=self.strip_whitespace,
739 to_upper=self.to_upper,
740 to_lower=self.to_lower,
741 pattern=self.pattern,
742 )
745def constr( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
746 *,
747 strip_whitespace: bool | None = None,
748 to_upper: bool | None = None,
749 to_lower: bool | None = None,
750 strict: bool | None = None,
751 min_length: int | None = None,
752 max_length: int | None = None,
753 pattern: str | Pattern[str] | None = None,
754) -> type[str]:
755 """
756 !!! warning "Discouraged"
757 This function is **discouraged** in favor of using
758 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
759 [`StringConstraints`][pydantic.types.StringConstraints] instead.
761 This function will be **deprecated** in Pydantic 3.0.
763 The reason is that `constr` returns a type, which doesn't play well with static analysis tools.
765 === ":x: Don't do this"
766 ```python
767 from pydantic import BaseModel, constr
769 class Foo(BaseModel):
770 bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$')
771 ```
773 === ":white_check_mark: Do this"
774 ```python
775 from typing import Annotated
777 from pydantic import BaseModel, StringConstraints
779 class Foo(BaseModel):
780 bar: Annotated[
781 str,
782 StringConstraints(
783 strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$'
784 ),
785 ]
786 ```
788 A wrapper around `str` that allows for additional constraints.
790 ```python
791 from pydantic import BaseModel, constr
793 class Foo(BaseModel):
794 bar: constr(strip_whitespace=True, to_upper=True)
796 foo = Foo(bar=' hello ')
797 print(foo)
798 #> bar='HELLO'
799 ```
801 Args:
802 strip_whitespace: Whether to remove leading and trailing whitespace.
803 to_upper: Whether to turn all characters to uppercase.
804 to_lower: Whether to turn all characters to lowercase.
805 strict: Whether to validate the string in strict mode.
806 min_length: The minimum length of the string.
807 max_length: The maximum length of the string.
808 pattern: A regex pattern to validate the string against.
810 Returns:
811 The wrapped string type.
812 """ # noqa: D212
813 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
814 str,
815 StringConstraints(
816 strip_whitespace=strip_whitespace,
817 to_upper=to_upper,
818 to_lower=to_lower,
819 strict=strict,
820 min_length=min_length,
821 max_length=max_length,
822 pattern=pattern,
823 ),
824 ]
827StrictStr = Annotated[str, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
828"""A string that must be validated in strict mode.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
831# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
832HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
835def conset( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
836 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None
837) -> type[set[HashableItemType]]:
838 """A wrapper around `typing.Set` that allows for additional constraints.
840 Args:
841 item_type: The type of the items in the set.
842 min_length: The minimum length of the set.
843 max_length: The maximum length of the set.
845 Returns:
846 The wrapped set type.
847 """
848 return Annotated[set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
851def confrozenset( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
852 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None
853) -> type[frozenset[HashableItemType]]:
854 """A wrapper around `typing.FrozenSet` that allows for additional constraints.
856 Args:
857 item_type: The type of the items in the frozenset.
858 min_length: The minimum length of the frozenset.
859 max_length: The maximum length of the frozenset.
861 Returns:
862 The wrapped frozenset type.
863 """
864 return Annotated[frozenset[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
867AnyItemType = TypeVar('AnyItemType') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
870def conlist( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
871 item_type: type[AnyItemType],
872 *,
873 min_length: int | None = None,
874 max_length: int | None = None,
875 unique_items: bool | None = None,
876) -> type[list[AnyItemType]]:
877 """A wrapper around [`list`][] that adds validation.
879 Args:
880 item_type: The type of the items in the list.
881 min_length: The minimum length of the list. Defaults to None.
882 max_length: The maximum length of the list. Defaults to None.
883 unique_items: Whether the items in the list must be unique. Defaults to None.
884 !!! warning Deprecated
885 The `unique_items` parameter is deprecated, use `Set` instead.
886 See [this issue](https://github.com/pydantic/pydantic-core/issues/296) for more details.
888 Returns:
889 The wrapped list type.
890 """
891 if unique_items is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
892 raise PydanticUserError( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
893 (
894 '`unique_items` is removed, use `Set` instead'
895 '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)'
896 ),
897 code='removed-kwargs',
898 )
899 return Annotated[list[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
902# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
904AnyType = TypeVar('AnyType') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
905if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
906 ImportString = Annotated[AnyType, ...]
907else:
909 class ImportString: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
910 """A type that can be used to import a Python object from a string.
912 `ImportString` expects a string and loads the Python object importable at that dotted path.
913 Attributes of modules may be separated from the module by `:` or `.`, e.g. if `'math:cos'` is provided,
914 the resulting field value would be the function `cos`. If a `.` is used and both an attribute and submodule
915 are present at the same path, the module will be preferred.
917 On model instantiation, pointers will be evaluated and imported. There is
918 some nuance to this behavior, demonstrated in the examples below.
920 ```python
921 import math
923 from pydantic import BaseModel, Field, ImportString, ValidationError
925 class ImportThings(BaseModel):
926 obj: ImportString
928 # A string value will cause an automatic import
929 my_cos = ImportThings(obj='math.cos')
931 # You can use the imported function as you would expect
932 cos_of_0 = my_cos.obj(0)
933 assert cos_of_0 == 1
935 # A string whose value cannot be imported will raise an error
936 try:
937 ImportThings(obj='foo.bar')
938 except ValidationError as e:
939 print(e)
940 '''
941 1 validation error for ImportThings
942 obj
943 Invalid python path: No module named 'foo.bar' [type=import_error, input_value='foo.bar', input_type=str]
944 '''
946 # Actual python objects can be assigned as well
947 my_cos = ImportThings(obj=math.cos)
948 my_cos_2 = ImportThings(obj='math.cos')
949 my_cos_3 = ImportThings(obj='math:cos')
950 assert my_cos == my_cos_2 == my_cos_3
952 # You can set default field value either as Python object:
953 class ImportThingsDefaultPyObj(BaseModel):
954 obj: ImportString = math.cos
956 # or as a string value (but only if used with `validate_default=True`)
957 class ImportThingsDefaultString(BaseModel):
958 obj: ImportString = Field(default='math.cos', validate_default=True)
960 my_cos_default1 = ImportThingsDefaultPyObj()
961 my_cos_default2 = ImportThingsDefaultString()
962 assert my_cos_default1.obj == my_cos_default2.obj == math.cos
964 # note: this will not work!
965 class ImportThingsMissingValidateDefault(BaseModel):
966 obj: ImportString = 'math.cos'
968 my_cos_default3 = ImportThingsMissingValidateDefault()
969 assert my_cos_default3.obj == 'math.cos' # just string, not evaluated
970 ```
972 Serializing an `ImportString` type to json is also possible.
974 ```python
975 from pydantic import BaseModel, ImportString
977 class ImportThings(BaseModel):
978 obj: ImportString
980 # Create an instance
981 m = ImportThings(obj='math.cos')
982 print(m)
983 #> obj=<built-in function cos>
984 print(m.model_dump_json())
985 #> {"obj":"math.cos"}
986 ```
987 """
989 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
990 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
991 return Annotated[item, cls()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
993 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
994 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
995 cls, source: type[Any], handler: GetCoreSchemaHandler
996 ) -> core_schema.CoreSchema:
997 serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
998 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
999 # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any]
1000 return core_schema.no_info_plain_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1001 function=_validators.import_string, serialization=serializer
1002 )
1003 else:
1004 return core_schema.no_info_before_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1005 function=_validators.import_string, schema=handler(source), serialization=serializer
1006 )
1008 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1009 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1010 return handler(core_schema.str_schema()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1012 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1013 def _serialize(v: Any) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1014 if isinstance(v, ModuleType): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1015 return v.__name__ 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1016 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1017 return f'{v.__module__}.{v.__name__}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1018 # Handle special cases for sys.XXX streams
1019 # if we see more of these, we should consider a more general solution
1020 elif hasattr(v, 'name'): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1021 if v.name == '<stdout>': 1021 ↛ 1022line 1021 didn't jump to line 1022 because the condition on line 1021 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1022 return 'sys.stdout'
1023 elif v.name == '<stdin>': 1023 ↛ 1024line 1023 didn't jump to line 1024 because the condition on line 1023 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1024 return 'sys.stdin'
1025 elif v.name == '<stderr>': 1025 ↛ 1026line 1025 didn't jump to line 1026 because the condition on line 1025 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1026 return 'sys.stderr'
1027 else:
1028 return v 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1030 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1031 return 'ImportString' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1034# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1037def condecimal( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1038 *,
1039 strict: bool | None = None,
1040 gt: int | Decimal | None = None,
1041 ge: int | Decimal | None = None,
1042 lt: int | Decimal | None = None,
1043 le: int | Decimal | None = None,
1044 multiple_of: int | Decimal | None = None,
1045 max_digits: int | None = None,
1046 decimal_places: int | None = None,
1047 allow_inf_nan: bool | None = None,
1048) -> type[Decimal]:
1049 """
1050 !!! warning "Discouraged"
1051 This function is **discouraged** in favor of using
1052 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with
1053 [`Field`][pydantic.fields.Field] instead.
1055 This function will be **deprecated** in Pydantic 3.0.
1057 The reason is that `condecimal` returns a type, which doesn't play well with static analysis tools.
1059 === ":x: Don't do this"
1060 ```python
1061 from pydantic import BaseModel, condecimal
1063 class Foo(BaseModel):
1064 bar: condecimal(strict=True, allow_inf_nan=True)
1065 ```
1067 === ":white_check_mark: Do this"
1068 ```python
1069 from decimal import Decimal
1070 from typing import Annotated
1072 from pydantic import BaseModel, Field
1074 class Foo(BaseModel):
1075 bar: Annotated[Decimal, Field(strict=True, allow_inf_nan=True)]
1076 ```
1078 A wrapper around Decimal that adds validation.
1080 Args:
1081 strict: Whether to validate the value in strict mode. Defaults to `None`.
1082 gt: The value must be greater than this. Defaults to `None`.
1083 ge: The value must be greater than or equal to this. Defaults to `None`.
1084 lt: The value must be less than this. Defaults to `None`.
1085 le: The value must be less than or equal to this. Defaults to `None`.
1086 multiple_of: The value must be a multiple of this. Defaults to `None`.
1087 max_digits: The maximum number of digits. Defaults to `None`.
1088 decimal_places: The number of decimal places. Defaults to `None`.
1089 allow_inf_nan: Whether to allow infinity and NaN. Defaults to `None`.
1091 ```python
1092 from decimal import Decimal
1094 from pydantic import BaseModel, ValidationError, condecimal
1096 class ConstrainedExample(BaseModel):
1097 constrained_decimal: condecimal(gt=Decimal('1.0'))
1099 m = ConstrainedExample(constrained_decimal=Decimal('1.1'))
1100 print(repr(m))
1101 #> ConstrainedExample(constrained_decimal=Decimal('1.1'))
1103 try:
1104 ConstrainedExample(constrained_decimal=Decimal('0.9'))
1105 except ValidationError as e:
1106 print(e.errors())
1107 '''
1108 [
1109 {
1110 'type': 'greater_than',
1111 'loc': ('constrained_decimal',),
1112 'msg': 'Input should be greater than 1.0',
1113 'input': Decimal('0.9'),
1114 'ctx': {'gt': Decimal('1.0')},
1115 'url': 'https://errors.pydantic.dev/2/v/greater_than',
1116 }
1117 ]
1118 '''
1119 ```
1120 """ # noqa: D212
1121 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1122 Decimal,
1123 Strict(strict) if strict is not None else None,
1124 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
1125 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None,
1126 _fields.pydantic_general_metadata(max_digits=max_digits, decimal_places=decimal_places),
1127 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None,
1128 ]
1131# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1134@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1135class UuidVersion: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1136 """A field metadata class to indicate a [UUID](https://docs.python.org/3/library/uuid.html) version.
1138 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below.
1140 Attributes:
1141 uuid_version: The version of the UUID. Must be one of 1, 3, 4, or 5.
1143 Example:
1144 ```python
1145 from typing import Annotated
1146 from uuid import UUID
1148 from pydantic.types import UuidVersion
1150 UUID1 = Annotated[UUID, UuidVersion(1)]
1151 ```
1152 """
1154 uuid_version: Literal[1, 3, 4, 5] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1156 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1157 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1158 ) -> JsonSchemaValue:
1159 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1160 field_schema.pop('anyOf', None) # remove the bytes/str union 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1161 field_schema.update(type='string', format=f'uuid{self.uuid_version}') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1162 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1164 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1165 if isinstance(self, source): 1165 ↛ 1167line 1165 didn't jump to line 1167 because the condition on line 1165 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1166 # used directly as a type
1167 return core_schema.uuid_schema(version=self.uuid_version)
1168 else:
1169 # update existing schema with self.uuid_version
1170 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1171 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1172 schema['version'] = self.uuid_version # type: ignore 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1173 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1175 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1176 return hash(type(self.uuid_version)) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1179UUID1 = Annotated[UUID, UuidVersion(1)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1180"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. 1bcdefghiajklmnopqGHIJKLrstuvwxy
1182```python
1183import uuid
1185from pydantic import UUID1, BaseModel
1187class Model(BaseModel):
1188 uuid1: UUID1
1190Model(uuid1=uuid.uuid1())
1191```
1192"""
1193UUID3 = Annotated[UUID, UuidVersion(3)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1194"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. 1bcdefghiajklmnopqGHIJKLrstuvwxy
1196```python
1197import uuid
1199from pydantic import UUID3, BaseModel
1201class Model(BaseModel):
1202 uuid3: UUID3
1204Model(uuid3=uuid.uuid3(uuid.NAMESPACE_DNS, 'pydantic.org'))
1205```
1206"""
1207UUID4 = Annotated[UUID, UuidVersion(4)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1208"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. 1bcdefghiajklmnopqGHIJKLrstuvwxy
1210```python
1211import uuid
1213from pydantic import UUID4, BaseModel
1215class Model(BaseModel):
1216 uuid4: UUID4
1218Model(uuid4=uuid.uuid4())
1219```
1220"""
1221UUID5 = Annotated[UUID, UuidVersion(5)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1222"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. 1bcdefghiajklmnopqGHIJKLrstuvwxy
1224```python
1225import uuid
1227from pydantic import UUID5, BaseModel
1229class Model(BaseModel):
1230 uuid5: UUID5
1232Model(uuid5=uuid.uuid5(uuid.NAMESPACE_DNS, 'pydantic.org'))
1233```
1234"""
1237# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1240@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1241class PathType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1242 path_type: Literal['file', 'dir', 'new', 'socket'] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1244 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1245 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1246 ) -> JsonSchemaValue:
1247 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1248 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1249 field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1250 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1252 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1253 function_lookup = { 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1254 'file': cast(core_schema.WithInfoValidatorFunction, self.validate_file),
1255 'dir': cast(core_schema.WithInfoValidatorFunction, self.validate_directory),
1256 'new': cast(core_schema.WithInfoValidatorFunction, self.validate_new),
1257 'socket': cast(core_schema.WithInfoValidatorFunction, self.validate_socket),
1258 }
1260 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1261 function_lookup[self.path_type],
1262 handler(source),
1263 )
1265 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1266 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1267 if path.is_file(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1268 return path 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1269 else:
1270 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1272 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1273 def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1274 if path.is_socket(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1275 return path 1zAbcdefghiBa
1276 else:
1277 raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1279 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1280 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1281 if path.is_dir(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1282 return path 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1283 else:
1284 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1286 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1287 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1288 if path.exists(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1289 raise PydanticCustomError('path_exists', 'Path already exists') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1290 elif not path.parent.exists(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1291 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1292 else:
1293 return path 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1295 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1296 return hash(type(self.path_type)) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1299FilePath = Annotated[Path, PathType('file')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1300"""A path that must point to a file. 1bcdefghiajklmnopqGHIJKLrstuvwxy
1302```python
1303from pathlib import Path
1305from pydantic import BaseModel, FilePath, ValidationError
1307class Model(BaseModel):
1308 f: FilePath
1310path = Path('text.txt')
1311path.touch()
1312m = Model(f='text.txt')
1313print(m.model_dump())
1314#> {'f': PosixPath('text.txt')}
1315path.unlink()
1317path = Path('directory')
1318path.mkdir(exist_ok=True)
1319try:
1320 Model(f='directory') # directory
1321except ValidationError as e:
1322 print(e)
1323 '''
1324 1 validation error for Model
1325 f
1326 Path does not point to a file [type=path_not_file, input_value='directory', input_type=str]
1327 '''
1328path.rmdir()
1330try:
1331 Model(f='not-exists-file')
1332except ValidationError as e:
1333 print(e)
1334 '''
1335 1 validation error for Model
1336 f
1337 Path does not point to a file [type=path_not_file, input_value='not-exists-file', input_type=str]
1338 '''
1339```
1340"""
1341DirectoryPath = Annotated[Path, PathType('dir')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1342"""A path that must point to a directory. 1bcdefghiajklmnopqGHIJKLrstuvwxy
1344```python
1345from pathlib import Path
1347from pydantic import BaseModel, DirectoryPath, ValidationError
1349class Model(BaseModel):
1350 f: DirectoryPath
1352path = Path('directory/')
1353path.mkdir()
1354m = Model(f='directory/')
1355print(m.model_dump())
1356#> {'f': PosixPath('directory')}
1357path.rmdir()
1359path = Path('file.txt')
1360path.touch()
1361try:
1362 Model(f='file.txt') # file
1363except ValidationError as e:
1364 print(e)
1365 '''
1366 1 validation error for Model
1367 f
1368 Path does not point to a directory [type=path_not_directory, input_value='file.txt', input_type=str]
1369 '''
1370path.unlink()
1372try:
1373 Model(f='not-exists-directory')
1374except ValidationError as e:
1375 print(e)
1376 '''
1377 1 validation error for Model
1378 f
1379 Path does not point to a directory [type=path_not_directory, input_value='not-exists-directory', input_type=str]
1380 '''
1381```
1382"""
1383NewPath = Annotated[Path, PathType('new')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1384"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
1386SocketPath = Annotated[Path, PathType('socket')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1387"""A path to an existing socket file""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
1389# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1391if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1392 # Json[list[str]] will be recognized by type checkers as list[str]
1393 Json = Annotated[AnyType, ...]
1395else:
1397 class Json: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1398 """A special type wrapper which loads JSON before parsing.
1400 You can use the `Json` data type to make Pydantic first load a raw JSON string before
1401 validating the loaded data into the parametrized type:
1403 ```python
1404 from typing import Any
1406 from pydantic import BaseModel, Json, ValidationError
1408 class AnyJsonModel(BaseModel):
1409 json_obj: Json[Any]
1411 class ConstrainedJsonModel(BaseModel):
1412 json_obj: Json[list[int]]
1414 print(AnyJsonModel(json_obj='{"b": 1}'))
1415 #> json_obj={'b': 1}
1416 print(ConstrainedJsonModel(json_obj='[1, 2, 3]'))
1417 #> json_obj=[1, 2, 3]
1419 try:
1420 ConstrainedJsonModel(json_obj=12)
1421 except ValidationError as e:
1422 print(e)
1423 '''
1424 1 validation error for ConstrainedJsonModel
1425 json_obj
1426 JSON input should be string, bytes or bytearray [type=json_type, input_value=12, input_type=int]
1427 '''
1429 try:
1430 ConstrainedJsonModel(json_obj='[a, b]')
1431 except ValidationError as e:
1432 print(e)
1433 '''
1434 1 validation error for ConstrainedJsonModel
1435 json_obj
1436 Invalid JSON: expected value at line 1 column 2 [type=json_invalid, input_value='[a, b]', input_type=str]
1437 '''
1439 try:
1440 ConstrainedJsonModel(json_obj='["a", "b"]')
1441 except ValidationError as e:
1442 print(e)
1443 '''
1444 2 validation errors for ConstrainedJsonModel
1445 json_obj.0
1446 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
1447 json_obj.1
1448 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='b', input_type=str]
1449 '''
1450 ```
1452 When you dump the model using `model_dump` or `model_dump_json`, the dumped value will be the result of validation,
1453 not the original JSON string. However, you can use the argument `round_trip=True` to get the original JSON string back:
1455 ```python
1456 from pydantic import BaseModel, Json
1458 class ConstrainedJsonModel(BaseModel):
1459 json_obj: Json[list[int]]
1461 print(ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json())
1462 #> {"json_obj":[1,2,3]}
1463 print(
1464 ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json(round_trip=True)
1465 )
1466 #> {"json_obj":"[1,2,3]"}
1467 ```
1468 """
1470 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1471 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1472 return Annotated[item, cls()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1474 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1475 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1476 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1477 return core_schema.json_schema(None) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1478 else:
1479 return core_schema.json_schema(handler(source)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1481 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1482 return 'Json' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1484 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1485 return hash(type(self)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1487 def __eq__(self, other: Any) -> bool: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1488 return type(other) is type(self) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1491# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1493SecretType = TypeVar('SecretType') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1496class _SecretBase(Generic[SecretType]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1497 def __init__(self, secret_value: SecretType) -> None: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1498 self._secret_value: SecretType = secret_value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1500 def get_secret_value(self) -> SecretType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1501 """Get the secret value.
1503 Returns:
1504 The secret value.
1505 """
1506 return self._secret_value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1508 def __eq__(self, other: Any) -> bool: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1509 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1511 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1512 return hash(self.get_secret_value()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1514 def __str__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1515 return str(self._display()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1517 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1518 return f'{self.__class__.__name__}({self._display()!r})' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1520 def _display(self) -> str | bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1521 raise NotImplementedError
1524def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1525 if info.mode == 'json': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1526 return str(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1527 else:
1528 return value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1531class Secret(_SecretBase[SecretType]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1532 """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks.
1534 You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing
1535 is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both
1536 ways of using `Secret` to create a new secret type.
1538 1. Directly parametrizing `Secret` with a type:
1540 ```python
1541 from pydantic import BaseModel, Secret
1543 SecretBool = Secret[bool]
1545 class Model(BaseModel):
1546 secret_bool: SecretBool
1548 m = Model(secret_bool=True)
1549 print(m.model_dump())
1550 #> {'secret_bool': Secret('**********')}
1552 print(m.model_dump_json())
1553 #> {"secret_bool":"**********"}
1555 print(m.secret_bool.get_secret_value())
1556 #> True
1557 ```
1559 2. Subclassing from parametrized `Secret`:
1561 ```python
1562 from datetime import date
1564 from pydantic import BaseModel, Secret
1566 class SecretDate(Secret[date]):
1567 def _display(self) -> str:
1568 return '****/**/**'
1570 class Model(BaseModel):
1571 secret_date: SecretDate
1573 m = Model(secret_date=date(2022, 1, 1))
1574 print(m.model_dump())
1575 #> {'secret_date': SecretDate('****/**/**')}
1577 print(m.model_dump_json())
1578 #> {"secret_date":"****/**/**"}
1580 print(m.secret_date.get_secret_value())
1581 #> 2022-01-01
1582 ```
1584 The value returned by the `_display` method will be used for `repr()` and `str()`.
1586 You can enforce constraints on the underlying type through annotations:
1587 For example:
1589 ```python
1590 from typing import Annotated
1592 from pydantic import BaseModel, Field, Secret, ValidationError
1594 SecretPosInt = Secret[Annotated[int, Field(gt=0, strict=True)]]
1596 class Model(BaseModel):
1597 sensitive_int: SecretPosInt
1599 m = Model(sensitive_int=42)
1600 print(m.model_dump())
1601 #> {'sensitive_int': Secret('**********')}
1603 try:
1604 m = Model(sensitive_int=-42) # (1)!
1605 except ValidationError as exc_info:
1606 print(exc_info.errors(include_url=False, include_input=False))
1607 '''
1608 [
1609 {
1610 'type': 'greater_than',
1611 'loc': ('sensitive_int',),
1612 'msg': 'Input should be greater than 0',
1613 'ctx': {'gt': 0},
1614 }
1615 ]
1616 '''
1618 try:
1619 m = Model(sensitive_int='42') # (2)!
1620 except ValidationError as exc_info:
1621 print(exc_info.errors(include_url=False, include_input=False))
1622 '''
1623 [
1624 {
1625 'type': 'int_type',
1626 'loc': ('sensitive_int',),
1627 'msg': 'Input should be a valid integer',
1628 }
1629 ]
1630 '''
1631 ```
1633 1. The input value is not greater than 0, so it raises a validation error.
1634 2. The input value is not an integer, so it raises a validation error because the `SecretPosInt` type has strict mode enabled.
1635 """
1637 def _display(self) -> str | bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1638 return '**********' if self.get_secret_value() else '' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1640 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1641 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1642 inner_type = None 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1643 # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly
1644 origin_type = get_origin(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1645 if origin_type is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1646 inner_type = get_args(source)[0] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1647 # otherwise, we need to get the inner type from the base class
1648 else:
1649 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1650 for base in bases: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1651 if get_origin(base) is Secret: 1651 ↛ 1650line 1651 didn't jump to line 1650 because the condition on line 1651 was always true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1652 inner_type = get_args(base)[0] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1653 if bases == [] or inner_type is None: 1653 ↛ 1654line 1653 didn't jump to line 1654 because the condition on line 1653 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1654 raise TypeError(
1655 f"Can't get secret type from {cls.__name__}. "
1656 'Please use Secret[<type>], or subclass from Secret[<type>] instead.'
1657 )
1659 inner_schema = handler.generate_schema(inner_type) # type: ignore 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1661 def validate_secret_value(value, handler) -> Secret[SecretType]: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1662 if isinstance(value, Secret): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1663 value = value.get_secret_value() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1664 validated_inner = handler(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1665 return cls(validated_inner) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1667 return core_schema.json_or_python_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1668 python_schema=core_schema.no_info_wrap_validator_function(
1669 validate_secret_value,
1670 inner_schema,
1671 ),
1672 json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema),
1673 serialization=core_schema.plain_serializer_function_ser_schema(
1674 _serialize_secret,
1675 info_arg=True,
1676 when_used='always',
1677 ),
1678 )
1680 __pydantic_serializer__ = SchemaSerializer( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1681 core_schema.any_schema(
1682 serialization=core_schema.plain_serializer_function_ser_schema(
1683 _serialize_secret,
1684 info_arg=True,
1685 when_used='always',
1686 )
1687 )
1688 )
1691def _secret_display(value: SecretType) -> str: # type: ignore 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1692 return '**********' if value else '' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1695def _serialize_secret_field( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1696 value: _SecretField[SecretType], info: core_schema.SerializationInfo
1697) -> str | _SecretField[SecretType]:
1698 if info.mode == 'json': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1699 # we want the output to always be string without the `b'` prefix for bytes,
1700 # hence we just use `secret_display`
1701 return _secret_display(value.get_secret_value()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1702 else:
1703 return value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1706class _SecretField(_SecretBase[SecretType]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1707 _inner_schema: ClassVar[CoreSchema] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1708 _error_kind: ClassVar[str] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1710 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1711 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1712 def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1713 json_schema = handler(cls._inner_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1714 _utils.update_not_none( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1715 json_schema,
1716 type='string',
1717 writeOnly=True,
1718 format='password',
1719 )
1720 return json_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1722 json_schema = core_schema.no_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1723 source, # construct the type
1724 cls._inner_schema,
1725 )
1727 def get_secret_schema(strict: bool) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1728 return core_schema.json_or_python_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1729 python_schema=core_schema.union_schema(
1730 [
1731 core_schema.is_instance_schema(source),
1732 json_schema,
1733 ],
1734 custom_error_type=cls._error_kind,
1735 strict=strict,
1736 ),
1737 json_schema=json_schema,
1738 serialization=core_schema.plain_serializer_function_ser_schema(
1739 _serialize_secret_field,
1740 info_arg=True,
1741 when_used='always',
1742 ),
1743 )
1745 return core_schema.lax_or_strict_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1746 lax_schema=get_secret_schema(strict=False),
1747 strict_schema=get_secret_schema(strict=True),
1748 metadata={'pydantic_js_functions': [get_json_schema]},
1749 )
1751 __pydantic_serializer__ = SchemaSerializer( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1752 core_schema.any_schema(
1753 serialization=core_schema.plain_serializer_function_ser_schema(
1754 _serialize_secret_field,
1755 info_arg=True,
1756 when_used='always',
1757 )
1758 )
1759 )
1762class SecretStr(_SecretField[str]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1763 """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1765 When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in
1766 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`.
1768 ```python
1769 from pydantic import BaseModel, SecretStr
1771 class User(BaseModel):
1772 username: str
1773 password: SecretStr
1775 user = User(username='scolvin', password='password1')
1777 print(user)
1778 #> username='scolvin' password=SecretStr('**********')
1779 print(user.password.get_secret_value())
1780 #> password1
1781 print((SecretStr('password'), SecretStr('')))
1782 #> (SecretStr('**********'), SecretStr(''))
1783 ```
1785 As seen above, by default, [`SecretStr`][pydantic.types.SecretStr] (and [`SecretBytes`][pydantic.types.SecretBytes])
1786 will be serialized as `**********` when serializing to json.
1788 You can use the [`field_serializer`][pydantic.functional_serializers.field_serializer] to dump the
1789 secret as plain-text when serializing to json.
1791 ```python
1792 from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer
1794 class Model(BaseModel):
1795 password: SecretStr
1796 password_bytes: SecretBytes
1798 @field_serializer('password', 'password_bytes', when_used='json')
1799 def dump_secret(self, v):
1800 return v.get_secret_value()
1802 model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes')
1803 print(model)
1804 #> password=SecretStr('**********') password_bytes=SecretBytes(b'**********')
1805 print(model.password)
1806 #> **********
1807 print(model.model_dump())
1808 '''
1809 {
1810 'password': SecretStr('**********'),
1811 'password_bytes': SecretBytes(b'**********'),
1812 }
1813 '''
1814 print(model.model_dump_json())
1815 #> {"password":"IAmSensitive","password_bytes":"IAmSensitiveBytes"}
1816 ```
1817 """
1819 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1820 _error_kind: ClassVar[str] = 'string_type' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1822 def __len__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1823 return len(self._secret_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1825 def _display(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1826 return _secret_display(self._secret_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1829class SecretBytes(_SecretField[bytes]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1830 """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks.
1832 It displays `b'**********'` instead of the string value on `repr()` and `str()` calls.
1833 When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in
1834 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`.
1836 ```python
1837 from pydantic import BaseModel, SecretBytes
1839 class User(BaseModel):
1840 username: str
1841 password: SecretBytes
1843 user = User(username='scolvin', password=b'password1')
1844 #> username='scolvin' password=SecretBytes(b'**********')
1845 print(user.password.get_secret_value())
1846 #> b'password1'
1847 print((SecretBytes(b'password'), SecretBytes(b'')))
1848 #> (SecretBytes(b'**********'), SecretBytes(b''))
1849 ```
1850 """
1852 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1853 _error_kind: ClassVar[str] = 'bytes_type' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1855 def __len__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1856 return len(self._secret_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1858 def _display(self) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1859 return _secret_display(self._secret_value).encode() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1862# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1865class PaymentCardBrand(str, Enum): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1866 amex = 'American Express' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1867 mastercard = 'Mastercard' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1868 visa = 'Visa' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1869 other = 'other' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1871 def __str__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1872 return self.value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1875@deprecated( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1876 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. '
1877 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.',
1878 category=PydanticDeprecatedSince20,
1879)
1880class PaymentCardNumber(str): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1881 """Based on: https://en.wikipedia.org/wiki/Payment_card_number."""
1883 strip_whitespace: ClassVar[bool] = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1884 min_length: ClassVar[int] = 12 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1885 max_length: ClassVar[int] = 19 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1886 bin: str 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1887 last4: str 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1888 brand: PaymentCardBrand 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1890 def __init__(self, card_number: str): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1891 self.validate_digits(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1893 card_number = self.validate_luhn_check_digit(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1895 self.bin = card_number[:6] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1896 self.last4 = card_number[-4:] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1897 self.brand = self.validate_brand(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1899 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1900 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1901 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1902 cls.validate,
1903 core_schema.str_schema(
1904 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace
1905 ),
1906 )
1908 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1909 def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1910 """Validate the card number and return a `PaymentCardNumber` instance."""
1911 return cls(input_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1913 @property 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1914 def masked(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1915 """Mask all but the last 4 digits of the card number.
1917 Returns:
1918 A masked card number string.
1919 """
1920 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1921 return f'{self.bin}{"*" * num_masked}{self.last4}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1923 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1924 def validate_digits(cls, card_number: str) -> None: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1925 """Validate that the card number is all digits."""
1926 if not card_number.isdigit(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1927 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1929 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1930 def validate_luhn_check_digit(cls, card_number: str) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1931 """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm."""
1932 sum_ = int(card_number[-1]) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1933 length = len(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1934 parity = length % 2 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1935 for i in range(length - 1): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1936 digit = int(card_number[i]) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1937 if i % 2 == parity: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1938 digit *= 2 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1939 if digit > 9: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1940 digit -= 9 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1941 sum_ += digit 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1942 valid = sum_ % 10 == 0 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1943 if not valid: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1944 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1945 return card_number 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1947 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1948 def validate_brand(card_number: str) -> PaymentCardBrand: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1949 """Validate length based on BIN for major brands:
1950 https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN).
1951 """
1952 if card_number[0] == '4': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1953 brand = PaymentCardBrand.visa 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1954 elif 51 <= int(card_number[:2]) <= 55: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1955 brand = PaymentCardBrand.mastercard 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1956 elif card_number[:2] in {'34', '37'}: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1957 brand = PaymentCardBrand.amex 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1958 else:
1959 brand = PaymentCardBrand.other 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1961 required_length: None | int | str = None 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1962 if brand in PaymentCardBrand.mastercard: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1963 required_length = 16 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1964 valid = len(card_number) == required_length 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1965 elif brand == PaymentCardBrand.visa: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1966 required_length = '13, 16 or 19' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1967 valid = len(card_number) in {13, 16, 19} 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1968 elif brand == PaymentCardBrand.amex: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1969 required_length = 15 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1970 valid = len(card_number) == required_length 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1971 else:
1972 valid = True 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1974 if not valid: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1975 raise PydanticCustomError( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1976 'payment_card_number_brand',
1977 'Length for a {brand} card must be {required_length}',
1978 {'brand': brand, 'required_length': required_length},
1979 )
1980 return brand 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
1983# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1986class ByteSize(int): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
1987 """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer.
1989 You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into
1990 an integer, and also to print out human-readable strings representing a number of bytes.
1992 In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes,
1993 and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2,
1994 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).
1996 !!! info
1997 Note that `1b` will be parsed as "1 byte" and not "1 bit".
1999 ```python
2000 from pydantic import BaseModel, ByteSize
2002 class MyModel(BaseModel):
2003 size: ByteSize
2005 print(MyModel(size=52000).size)
2006 #> 52000
2007 print(MyModel(size='3000 KiB').size)
2008 #> 3072000
2010 m = MyModel(size='50 PB')
2011 print(m.size.human_readable())
2012 #> 44.4PiB
2013 print(m.size.human_readable(decimal=True))
2014 #> 50.0PB
2015 print(m.size.human_readable(separator=' '))
2016 #> 44.4 PiB
2018 print(m.size.to('TiB'))
2019 #> 45474.73508864641
2020 ```
2021 """
2023 byte_sizes = { 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2024 'b': 1,
2025 'kb': 10**3,
2026 'mb': 10**6,
2027 'gb': 10**9,
2028 'tb': 10**12,
2029 'pb': 10**15,
2030 'eb': 10**18,
2031 'kib': 2**10,
2032 'mib': 2**20,
2033 'gib': 2**30,
2034 'tib': 2**40,
2035 'pib': 2**50,
2036 'eib': 2**60,
2037 'bit': 1 / 8,
2038 'kbit': 10**3 / 8,
2039 'mbit': 10**6 / 8,
2040 'gbit': 10**9 / 8,
2041 'tbit': 10**12 / 8,
2042 'pbit': 10**15 / 8,
2043 'ebit': 10**18 / 8,
2044 'kibit': 2**10 / 8,
2045 'mibit': 2**20 / 8,
2046 'gibit': 2**30 / 8,
2047 'tibit': 2**40 / 8,
2048 'pibit': 2**50 / 8,
2049 'eibit': 2**60 / 8,
2050 }
2051 byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2053 byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2054 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2056 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2057 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2058 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2059 function=cls._validate,
2060 schema=core_schema.union_schema(
2061 [
2062 core_schema.str_schema(pattern=cls.byte_string_pattern),
2063 core_schema.int_schema(ge=0),
2064 ],
2065 custom_error_type='byte_size',
2066 custom_error_message='could not parse value and unit from byte string',
2067 ),
2068 serialization=core_schema.plain_serializer_function_ser_schema(
2069 int, return_schema=core_schema.int_schema(ge=0)
2070 ),
2071 )
2073 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2074 def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2075 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2076 return cls(int(input_value)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2077 except ValueError: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2078 pass 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2080 str_match = cls.byte_string_re.match(str(input_value)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2081 if str_match is None: 2081 ↛ 2082line 2081 didn't jump to line 2082 because the condition on line 2081 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2082 raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string')
2084 scalar, unit = str_match.groups() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2085 if unit is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2086 unit = 'b' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2088 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2089 unit_mult = cls.byte_sizes[unit.lower()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2090 except KeyError: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2091 raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2093 return cls(int(float(scalar) * unit_mult)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2095 def human_readable(self, decimal: bool = False, separator: str = '') -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2096 """Converts a byte size to a human readable string.
2098 Args:
2099 decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units
2100 (e.g. 1024 bytes per KiB).
2101 separator: A string used to split the value and unit. Defaults to an empty string ('').
2103 Returns:
2104 A human readable string representation of the byte size.
2105 """
2106 if decimal: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2107 divisor = 1000 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2108 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2109 final_unit = 'EB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2110 else:
2111 divisor = 1024 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2112 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2113 final_unit = 'EiB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2115 num = float(self) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2116 for unit in units: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2117 if abs(num) < divisor: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2118 if unit == 'B': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2119 return f'{num:0.0f}{separator}{unit}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2120 else:
2121 return f'{num:0.1f}{separator}{unit}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2122 num /= divisor 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2124 return f'{num:0.1f}{separator}{final_unit}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2126 def to(self, unit: str) -> float: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2127 """Converts a byte size to another unit, including both byte and bit units.
2129 Args:
2130 unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB,
2131 KiB, MiB, GiB, TiB, PiB, EiB (byte units) and
2132 bit, kbit, mbit, gbit, tbit, pbit, ebit,
2133 kibit, mibit, gibit, tibit, pibit, eibit (bit units).
2135 Returns:
2136 The byte size in the new unit.
2137 """
2138 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2139 unit_div = self.byte_sizes[unit.lower()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2140 except KeyError: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2141 raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2143 return self / unit_div 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2146# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2149def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2150 if annotated_type != expected_type: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2151 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2154if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2155 PastDate = Annotated[date, ...]
2156 FutureDate = Annotated[date, ...]
2157else:
2159 class PastDate: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2160 """A date in the past."""
2162 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2163 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2164 cls, source: type[Any], handler: GetCoreSchemaHandler
2165 ) -> core_schema.CoreSchema:
2166 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2167 # used directly as a type
2168 return core_schema.date_schema(now_op='past') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2169 else:
2170 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2171 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2172 schema['now_op'] = 'past' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2173 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2175 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2176 return 'PastDate' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2178 class FutureDate: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2179 """A date in the future."""
2181 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2182 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2183 cls, source: type[Any], handler: GetCoreSchemaHandler
2184 ) -> core_schema.CoreSchema:
2185 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2186 # used directly as a type
2187 return core_schema.date_schema(now_op='future') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2188 else:
2189 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2190 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2191 schema['now_op'] = 'future' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2192 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2194 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2195 return 'FutureDate' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2198def condate( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2199 *,
2200 strict: bool | None = None,
2201 gt: date | None = None,
2202 ge: date | None = None,
2203 lt: date | None = None,
2204 le: date | None = None,
2205) -> type[date]:
2206 """A wrapper for date that adds constraints.
2208 Args:
2209 strict: Whether to validate the date value in strict mode. Defaults to `None`.
2210 gt: The value must be greater than this. Defaults to `None`.
2211 ge: The value must be greater than or equal to this. Defaults to `None`.
2212 lt: The value must be less than this. Defaults to `None`.
2213 le: The value must be less than or equal to this. Defaults to `None`.
2215 Returns:
2216 A date type with the specified constraints.
2217 """
2218 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2219 date,
2220 Strict(strict) if strict is not None else None,
2221 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le),
2222 ]
2225# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2227if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2228 AwareDatetime = Annotated[datetime, ...]
2229 NaiveDatetime = Annotated[datetime, ...]
2230 PastDatetime = Annotated[datetime, ...]
2231 FutureDatetime = Annotated[datetime, ...]
2233else:
2235 class AwareDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2236 """A datetime that requires timezone info."""
2238 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2239 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2240 cls, source: type[Any], handler: GetCoreSchemaHandler
2241 ) -> core_schema.CoreSchema:
2242 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2243 # used directly as a type
2244 return core_schema.datetime_schema(tz_constraint='aware') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2245 else:
2246 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2247 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2248 schema['tz_constraint'] = 'aware' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2249 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2251 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2252 return 'AwareDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2254 class NaiveDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2255 """A datetime that doesn't require timezone info."""
2257 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2258 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2259 cls, source: type[Any], handler: GetCoreSchemaHandler
2260 ) -> core_schema.CoreSchema:
2261 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2262 # used directly as a type
2263 return core_schema.datetime_schema(tz_constraint='naive') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2264 else:
2265 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2266 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2267 schema['tz_constraint'] = 'naive' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2268 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2270 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2271 return 'NaiveDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2273 class PastDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2274 """A datetime that must be in the past."""
2276 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2277 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2278 cls, source: type[Any], handler: GetCoreSchemaHandler
2279 ) -> core_schema.CoreSchema:
2280 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2281 # used directly as a type
2282 return core_schema.datetime_schema(now_op='past') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2283 else:
2284 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2285 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2286 schema['now_op'] = 'past' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2287 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2289 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2290 return 'PastDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2292 class FutureDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2293 """A datetime that must be in the future."""
2295 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2296 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2297 cls, source: type[Any], handler: GetCoreSchemaHandler
2298 ) -> core_schema.CoreSchema:
2299 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2300 # used directly as a type
2301 return core_schema.datetime_schema(now_op='future') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2302 else:
2303 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2304 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2305 schema['now_op'] = 'future' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2306 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2308 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2309 return 'FutureDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2312# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2315class EncoderProtocol(Protocol): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2316 """Protocol for encoding and decoding data to and from bytes.""" 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2318 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2319 def decode(cls, data: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2320 """Decode the data using the encoder.
2322 Args:
2323 data: The data to decode.
2325 Returns:
2326 The decoded data.
2327 """
2328 ...
2330 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2331 def encode(cls, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2332 """Encode the data using the encoder.
2334 Args:
2335 value: The data to encode.
2337 Returns:
2338 The encoded data.
2339 """
2340 ...
2342 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2343 def get_json_format(cls) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2344 """Get the JSON format for the encoded data.
2346 Returns:
2347 The JSON format for the encoded data.
2348 """
2349 ...
2352class Base64Encoder(EncoderProtocol): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2353 """Standard (non-URL-safe) Base64 encoder."""
2355 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2356 def decode(cls, data: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2357 """Decode the data from base64 encoded bytes to original bytes data.
2359 Args:
2360 data: The data to decode.
2362 Returns:
2363 The decoded data.
2364 """
2365 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2366 return base64.b64decode(data) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2367 except ValueError as e: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2368 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2370 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2371 def encode(cls, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2372 """Encode the data from bytes to a base64 encoded bytes.
2374 Args:
2375 value: The data to encode.
2377 Returns:
2378 The encoded data.
2379 """
2380 return base64.b64encode(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2382 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2383 def get_json_format(cls) -> Literal['base64']: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2384 """Get the JSON format for the encoded data.
2386 Returns:
2387 The JSON format for the encoded data.
2388 """
2389 return 'base64' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2392class Base64UrlEncoder(EncoderProtocol): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2393 """URL-safe Base64 encoder."""
2395 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2396 def decode(cls, data: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
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: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2406 return base64.urlsafe_b64decode(data) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2407 except ValueError as e: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2408 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2410 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2411 def encode(cls, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
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.urlsafe_b64encode(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2422 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2423 def get_json_format(cls) -> Literal['base64url']: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2424 """Get the JSON format for the encoded data.
2426 Returns:
2427 The JSON format for the encoded data.
2428 """
2429 return 'base64url' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2432@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2433class EncodedBytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2434 """A bytes type that is encoded and decoded using the specified encoder.
2436 `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate.
2438 ```python
2439 from typing import Annotated
2441 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError
2443 class MyEncoder(EncoderProtocol):
2444 @classmethod
2445 def decode(cls, data: bytes) -> bytes:
2446 if data == b'**undecodable**':
2447 raise ValueError('Cannot decode data')
2448 return data[13:]
2450 @classmethod
2451 def encode(cls, value: bytes) -> bytes:
2452 return b'**encoded**: ' + value
2454 @classmethod
2455 def get_json_format(cls) -> str:
2456 return 'my-encoder'
2458 MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)]
2460 class Model(BaseModel):
2461 my_encoded_bytes: MyEncodedBytes
2463 # Initialize the model with encoded data
2464 m = Model(my_encoded_bytes=b'**encoded**: some bytes')
2466 # Access decoded value
2467 print(m.my_encoded_bytes)
2468 #> b'some bytes'
2470 # Serialize into the encoded form
2471 print(m.model_dump())
2472 #> {'my_encoded_bytes': b'**encoded**: some bytes'}
2474 # Validate encoded data
2475 try:
2476 Model(my_encoded_bytes=b'**undecodable**')
2477 except ValidationError as e:
2478 print(e)
2479 '''
2480 1 validation error for Model
2481 my_encoded_bytes
2482 Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes]
2483 '''
2484 ```
2485 """
2487 encoder: type[EncoderProtocol] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2489 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2490 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2491 ) -> JsonSchemaValue:
2492 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2493 field_schema.update(type='string', format=self.encoder.get_json_format()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2494 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2496 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2497 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2498 _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2499 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2500 function=self.decode,
2501 schema=schema,
2502 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode),
2503 )
2505 def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2506 """Decode the data using the specified encoder.
2508 Args:
2509 data: The data to decode.
2511 Returns:
2512 The decoded data.
2513 """
2514 return self.encoder.decode(data) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2516 def encode(self, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2517 """Encode the data using the specified encoder.
2519 Args:
2520 value: The data to encode.
2522 Returns:
2523 The encoded data.
2524 """
2525 return self.encoder.encode(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2527 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2528 return hash(self.encoder) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2531@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2532class EncodedStr: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2533 """A str type that is encoded and decoded using the specified encoder.
2535 `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate.
2537 ```python
2538 from typing import Annotated
2540 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError
2542 class MyEncoder(EncoderProtocol):
2543 @classmethod
2544 def decode(cls, data: bytes) -> bytes:
2545 if data == b'**undecodable**':
2546 raise ValueError('Cannot decode data')
2547 return data[13:]
2549 @classmethod
2550 def encode(cls, value: bytes) -> bytes:
2551 return b'**encoded**: ' + value
2553 @classmethod
2554 def get_json_format(cls) -> str:
2555 return 'my-encoder'
2557 MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)]
2559 class Model(BaseModel):
2560 my_encoded_str: MyEncodedStr
2562 # Initialize the model with encoded data
2563 m = Model(my_encoded_str='**encoded**: some str')
2565 # Access decoded value
2566 print(m.my_encoded_str)
2567 #> some str
2569 # Serialize into the encoded form
2570 print(m.model_dump())
2571 #> {'my_encoded_str': '**encoded**: some str'}
2573 # Validate encoded data
2574 try:
2575 Model(my_encoded_str='**undecodable**')
2576 except ValidationError as e:
2577 print(e)
2578 '''
2579 1 validation error for Model
2580 my_encoded_str
2581 Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str]
2582 '''
2583 ```
2584 """
2586 encoder: type[EncoderProtocol] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2588 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2589 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2590 ) -> JsonSchemaValue:
2591 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2592 field_schema.update(type='string', format=self.encoder.get_json_format()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2593 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2595 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2596 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2597 _check_annotated_type(schema['type'], 'str', self.__class__.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2598 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2599 function=self.decode_str,
2600 schema=schema,
2601 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str),
2602 )
2604 def decode_str(self, data: str, _: core_schema.ValidationInfo) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2605 """Decode the data using the specified encoder.
2607 Args:
2608 data: The data to decode.
2610 Returns:
2611 The decoded data.
2612 """
2613 return self.encoder.decode(data.encode()).decode() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2615 def encode_str(self, value: str) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2616 """Encode the data using the specified encoder.
2618 Args:
2619 value: The data to encode.
2621 Returns:
2622 The encoded data.
2623 """
2624 return self.encoder.encode(value.encode()).decode() # noqa: UP008 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2626 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2627 return hash(self.encoder) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2630Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2631"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1bcdefghiajklmnopqGHIJKLrstuvwxy
2633Note:
2634 Under the hood, `Base64Bytes` uses the standard library `base64.b64encode` and `base64.b64decode` functions.
2636 As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect
2637 decoding.
2639Warning:
2640 In versions of Pydantic prior to v2.10, `Base64Bytes` used [`base64.encodebytes`][base64.encodebytes]
2641 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html),
2642 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern
2643 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions.
2645 If you'd still like to use these legacy encoders / decoders, you can achieve this by creating a custom annotated type,
2646 like follows:
2648 ```python
2649 import base64
2650 from typing import Annotated, Literal
2652 from pydantic_core import PydanticCustomError
2654 from pydantic import EncodedBytes, EncoderProtocol
2656 class LegacyBase64Encoder(EncoderProtocol):
2657 @classmethod
2658 def decode(cls, data: bytes) -> bytes:
2659 try:
2660 return base64.decodebytes(data)
2661 except ValueError as e:
2662 raise PydanticCustomError(
2663 'base64_decode',
2664 "Base64 decoding error: '{error}'",
2665 {'error': str(e)},
2666 )
2668 @classmethod
2669 def encode(cls, value: bytes) -> bytes:
2670 return base64.encodebytes(value)
2672 @classmethod
2673 def get_json_format(cls) -> Literal['base64']:
2674 return 'base64'
2676 LegacyBase64Bytes = Annotated[bytes, EncodedBytes(encoder=LegacyBase64Encoder)]
2677 ```
2679```python
2680from pydantic import Base64Bytes, BaseModel, ValidationError
2682class Model(BaseModel):
2683 base64_bytes: Base64Bytes
2685# Initialize the model with base64 data
2686m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5')
2688# Access decoded value
2689print(m.base64_bytes)
2690#> b'This is the way'
2692# Serialize into the base64 form
2693print(m.model_dump())
2694#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5'}
2696# Validate base64 data
2697try:
2698 print(Model(base64_bytes=b'undecodable').base64_bytes)
2699except ValidationError as e:
2700 print(e)
2701 '''
2702 1 validation error for Model
2703 base64_bytes
2704 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes]
2705 '''
2706```
2707"""
2708Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2709"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1bcdefghiajklmnopqGHIJKLrstuvwxy
2711Note:
2712 Under the hood, `Base64Str` uses the standard library `base64.b64encode` and `base64.b64decode` functions.
2714 As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect
2715 decoding.
2717Warning:
2718 In versions of Pydantic prior to v2.10, `Base64Str` used [`base64.encodebytes`][base64.encodebytes]
2719 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html),
2720 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern
2721 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions.
2723 See the [`Base64Bytes`][pydantic.types.Base64Bytes] type for more information on how to
2724 replicate the old behavior with the legacy encoders / decoders.
2726```python
2727from pydantic import Base64Str, BaseModel, ValidationError
2729class Model(BaseModel):
2730 base64_str: Base64Str
2732# Initialize the model with base64 data
2733m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y')
2735# Access decoded value
2736print(m.base64_str)
2737#> These aren't the droids you're looking for
2739# Serialize into the base64 form
2740print(m.model_dump())
2741#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y'}
2743# Validate base64 data
2744try:
2745 print(Model(base64_str='undecodable').base64_str)
2746except ValidationError as e:
2747 print(e)
2748 '''
2749 1 validation error for Model
2750 base64_str
2751 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str]
2752 '''
2753```
2754"""
2755Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2756"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. 1bcdefghiajklmnopqGHIJKLrstuvwxy
2758Note:
2759 Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2760 functions.
2762 As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data
2763 (using `'+'` and `'/'`).
2765```python
2766from pydantic import Base64UrlBytes, BaseModel
2768class Model(BaseModel):
2769 base64url_bytes: Base64UrlBytes
2771# Initialize the model with base64 data
2772m = Model(base64url_bytes=b'SHc_dHc-TXc==')
2773print(m)
2774#> base64url_bytes=b'Hw?tw>Mw'
2775```
2776"""
2777Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2778"""A str type that is encoded and decoded using the URL-safe base64 encoder. 1bcdefghiajklmnopqGHIJKLrstuvwxy
2780Note:
2781 Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode`
2782 functions.
2784 As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`).
2786```python
2787from pydantic import Base64UrlStr, BaseModel
2789class Model(BaseModel):
2790 base64url_str: Base64UrlStr
2792# Initialize the model with base64 data
2793m = Model(base64url_str='SHc_dHc-TXc==')
2794print(m)
2795#> base64url_str='Hw?tw>Mw'
2796```
2797"""
2800__getattr__ = getattr_migration(__name__) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2803@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2804class GetPydanticSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2805 """!!! abstract "Usage Documentation"
2806 [Using `GetPydanticSchema` to Reduce Boilerplate](../concepts/types.md#using-getpydanticschema-to-reduce-boilerplate)
2808 A convenience class for creating an annotation that provides pydantic custom type hooks.
2810 This class is intended to eliminate the need to create a custom "marker" which defines the
2811 `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods.
2813 For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do:
2814 ```python
2815 from typing import Annotated, Any
2817 from pydantic import BaseModel, GetPydanticSchema
2819 HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any))
2821 class Model(BaseModel):
2822 x: Annotated[int, HandleAsAny] # pydantic sees `x: Any`
2824 print(repr(Model(x='abc').x))
2825 #> 'abc'
2826 ```
2827 """
2829 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2830 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2832 # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:`
2833 # which returns `GetPydanticSchema(lambda _s, h: h(type_))`
2835 if not TYPE_CHECKING: 2835 ↛ 2847line 2835 didn't jump to line 2847 because the condition on line 2835 was always true1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2836 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
2838 def __getattr__(self, item: str) -> Any: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2839 """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls."""
2840 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2841 return self.get_pydantic_core_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2842 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2842 ↛ 2843line 2842 didn't jump to line 2843 because the condition on line 2842 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2843 return self.get_pydantic_json_schema
2844 else:
2845 return object.__getattribute__(self, item) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2847 __hash__ = object.__hash__ 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2850@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2851class Tag: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2852 """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union.
2854 Also provides a way to label a union case in error messages.
2856 When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that
2857 should be used to identify that case. For example, in the below example, the `Tag` is used to specify that
2858 if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it
2859 returns `'pumpkin'`, the input should be validated as a `PumpkinPie`.
2861 The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to
2862 the appropriate member of the `Union` in question.
2864 ```python
2865 from typing import Annotated, Any, Literal, Union
2867 from pydantic import BaseModel, Discriminator, Tag
2869 class Pie(BaseModel):
2870 time_to_cook: int
2871 num_ingredients: int
2873 class ApplePie(Pie):
2874 fruit: Literal['apple'] = 'apple'
2876 class PumpkinPie(Pie):
2877 filling: Literal['pumpkin'] = 'pumpkin'
2879 def get_discriminator_value(v: Any) -> str:
2880 if isinstance(v, dict):
2881 return v.get('fruit', v.get('filling'))
2882 return getattr(v, 'fruit', getattr(v, 'filling', None))
2884 class ThanksgivingDinner(BaseModel):
2885 dessert: Annotated[
2886 Union[
2887 Annotated[ApplePie, Tag('apple')],
2888 Annotated[PumpkinPie, Tag('pumpkin')],
2889 ],
2890 Discriminator(get_discriminator_value),
2891 ]
2893 apple_variation = ThanksgivingDinner.model_validate(
2894 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
2895 )
2896 print(repr(apple_variation))
2897 '''
2898 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
2899 '''
2901 pumpkin_variation = ThanksgivingDinner.model_validate(
2902 {
2903 'dessert': {
2904 'filling': 'pumpkin',
2905 'time_to_cook': 40,
2906 'num_ingredients': 6,
2907 }
2908 }
2909 )
2910 print(repr(pumpkin_variation))
2911 '''
2912 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
2913 '''
2914 ```
2916 !!! note
2917 You must specify a `Tag` for every case in a `Tag` that is associated with a
2918 callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code
2919 [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag).
2921 See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s.
2923 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
2924 """
2926 tag: str 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2928 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2929 schema = handler(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2930 metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2931 metadata['pydantic_internal_union_tag_key'] = self.tag 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2932 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
2935@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2936class Discriminator: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
2937 """!!! abstract "Usage Documentation"
2938 [Discriminated Unions with `Callable` `Discriminator`](../concepts/unions.md#discriminated-unions-with-callable-discriminator)
2940 Provides a way to use a custom callable as the way to extract the value of a union discriminator.
2942 This allows you to get validation behavior like you'd get from `Field(discriminator=<field_name>)`,
2943 but without needing to have a single shared field across all the union choices. This also makes it
2944 possible to handle unions of models and primitive types with discriminated-union-style validation errors.
2945 Finally, this allows you to use a custom callable as the way to identify which member of a union a value
2946 belongs to, while still seeing all the performance benefits of a discriminated union.
2948 Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion`
2949 than it would be as a normal `Union`.
2951 ```python
2952 from typing import Annotated, Any, Literal, Union
2954 from pydantic import BaseModel, Discriminator, Tag
2956 class Pie(BaseModel):
2957 time_to_cook: int
2958 num_ingredients: int
2960 class ApplePie(Pie):
2961 fruit: Literal['apple'] = 'apple'
2963 class PumpkinPie(Pie):
2964 filling: Literal['pumpkin'] = 'pumpkin'
2966 def get_discriminator_value(v: Any) -> str:
2967 if isinstance(v, dict):
2968 return v.get('fruit', v.get('filling'))
2969 return getattr(v, 'fruit', getattr(v, 'filling', None))
2971 class ThanksgivingDinner(BaseModel):
2972 dessert: Annotated[
2973 Union[
2974 Annotated[ApplePie, Tag('apple')],
2975 Annotated[PumpkinPie, Tag('pumpkin')],
2976 ],
2977 Discriminator(get_discriminator_value),
2978 ]
2980 apple_variation = ThanksgivingDinner.model_validate(
2981 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}}
2982 )
2983 print(repr(apple_variation))
2984 '''
2985 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple'))
2986 '''
2988 pumpkin_variation = ThanksgivingDinner.model_validate(
2989 {
2990 'dessert': {
2991 'filling': 'pumpkin',
2992 'time_to_cook': 40,
2993 'num_ingredients': 6,
2994 }
2995 }
2996 )
2997 print(repr(pumpkin_variation))
2998 '''
2999 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin'))
3000 '''
3001 ```
3003 See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s.
3005 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions
3006 """
3008 discriminator: str | Callable[[Any], Hashable] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3009 """The callable or field name for discriminating the type in a tagged union. 1bcdefghiajklmnopqGHIJKLrstuvwxy
3011 A `Callable` discriminator must extract the value of the discriminator from the input.
3012 A `str` discriminator must be the name of a field to discriminate against.
3013 """
3014 custom_error_type: str | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3015 """Type to use in [custom errors](../errors/errors.md#custom-errors) replacing the standard discriminated union 1bcdefghiajklmnopqGHIJKLrstuvwxy
3016 validation errors.
3017 """
3018 custom_error_message: str | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3019 """Message to use in custom errors.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
3020 custom_error_context: dict[str, int | str | float] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3021 """Context to use in custom errors.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
3023 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3024 origin = _typing_extra.get_origin(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3025 if not origin or not _typing_extra.origin_is_union(origin): 3025 ↛ 3026line 3025 didn't jump to line 3026 because the condition on line 3025 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3026 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}')
3028 if isinstance(self.discriminator, str): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3029 from pydantic import Field 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3031 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3032 else:
3033 original_schema = handler(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3034 return self._convert_schema(original_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3036 def _convert_schema(self, original_schema: core_schema.CoreSchema) -> core_schema.TaggedUnionSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3037 if original_schema['type'] != 'union': 3037 ↛ 3042line 3037 didn't jump to line 3042 because the condition on line 3037 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3038 # This likely indicates that the schema was a single-item union that was simplified.
3039 # In this case, we do the same thing we do in
3040 # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely,
3041 # package the generated schema back into a single-item union.
3042 original_schema = core_schema.union_schema([original_schema])
3044 tagged_union_choices = {} 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3045 for choice in original_schema['choices']: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3046 tag = None 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3047 if isinstance(choice, tuple): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3048 choice, tag = choice 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3049 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3050 if metadata is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3051 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3052 if tag is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3053 raise PydanticUserError( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3054 f'`Tag` not provided for choice {choice} used with `Discriminator`',
3055 code='callable-discriminator-no-tag',
3056 )
3057 tagged_union_choices[tag] = choice 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3059 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored
3060 custom_error_type = self.custom_error_type 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3061 if custom_error_type is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3062 custom_error_type = original_schema.get('custom_error_type') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3064 custom_error_message = self.custom_error_message 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3065 if custom_error_message is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3066 custom_error_message = original_schema.get('custom_error_message') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3068 custom_error_context = self.custom_error_context 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3069 if custom_error_context is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3070 custom_error_context = original_schema.get('custom_error_context') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3072 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3073 return core_schema.tagged_union_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3074 tagged_union_choices,
3075 self.discriminator,
3076 custom_error_type=custom_error_type,
3077 custom_error_message=custom_error_message,
3078 custom_error_context=custom_error_context,
3079 strict=original_schema.get('strict'),
3080 ref=original_schema.get('ref'),
3081 metadata=original_schema.get('metadata'),
3082 serialization=original_schema.get('serialization'),
3083 )
3086_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3089def _get_type_name(x: Any) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3090 type_ = type(x) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3091 if type_ in _JSON_TYPES: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3092 return type_.__name__ 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3094 # Handle proper subclasses; note we don't need to handle None or bool here
3095 if isinstance(x, int): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3096 return 'int' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3097 if isinstance(x, float): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3098 return 'float' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3099 if isinstance(x, str): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3100 return 'str' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3101 if isinstance(x, list): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3102 return 'list' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3103 if isinstance(x, dict): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3104 return 'dict' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3106 # Fail by returning the type's actual name
3107 return getattr(type_, '__name__', '<no type name>') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3110class _AllowAnyJson: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3111 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3112 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3113 python_schema = handler(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3114 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3117if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3118 # This seems to only be necessary for mypy
3119 JsonValue: TypeAlias = Union[
3120 list['JsonValue'],
3121 dict[str, 'JsonValue'],
3122 str,
3123 bool,
3124 int,
3125 float,
3126 None,
3127 ]
3128 """A `JsonValue` is used to represent a value that can be serialized to JSON.
3130 It may be one of:
3132 * `list['JsonValue']`
3133 * `dict[str, 'JsonValue']`
3134 * `str`
3135 * `bool`
3136 * `int`
3137 * `float`
3138 * `None`
3140 The following example demonstrates how to use `JsonValue` to validate JSON data,
3141 and what kind of errors to expect when input data is not json serializable.
3143 ```python
3144 import json
3146 from pydantic import BaseModel, JsonValue, ValidationError
3148 class Model(BaseModel):
3149 j: JsonValue
3151 valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}}
3152 invalid_json_data = {'j': {'a': {'b': ...}}}
3154 print(repr(Model.model_validate(valid_json_data)))
3155 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
3156 print(repr(Model.model_validate_json(json.dumps(valid_json_data))))
3157 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}})
3159 try:
3160 Model.model_validate(invalid_json_data)
3161 except ValidationError as e:
3162 print(e)
3163 '''
3164 1 validation error for Model
3165 j.dict.a.dict.b
3166 input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis]
3167 '''
3168 ```
3169 """
3171else:
3172 JsonValue = TypeAliasType( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3173 'JsonValue',
3174 Annotated[
3175 Union[
3176 Annotated[list['JsonValue'], Tag('list')],
3177 Annotated[dict[str, 'JsonValue'], Tag('dict')],
3178 Annotated[str, Tag('str')],
3179 Annotated[bool, Tag('bool')],
3180 Annotated[int, Tag('int')],
3181 Annotated[float, Tag('float')],
3182 Annotated[None, Tag('NoneType')],
3183 ],
3184 Discriminator(
3185 _get_type_name,
3186 custom_error_type='invalid-json-value',
3187 custom_error_message='input was not a valid JSON value',
3188 ),
3189 _AllowAnyJson,
3190 ],
3191 )
3194class _OnErrorOmit: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3195 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3196 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3197 # there is no actual default value here but we use with_default_schema since it already has the on_error
3198 # behavior implemented and it would be no more efficient to implement it on every other validator
3199 # or as a standalone validator
3200 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy
3203OnErrorOmit = Annotated[T, _OnErrorOmit] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3204""" 1bcdefghiajklmnopqGHIJKLrstuvwxy
3205When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc.
3206this annotation omits the item from the iteration if there is any error validating it.
3207That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded
3208any invalid items are discarded and the valid ones are returned.
3209"""
3212@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3213class FailFast(_fields.PydanticMetadata, BaseMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy
3214 """A `FailFast` annotation can be used to specify that validation should stop at the first error.
3216 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.
3218 You might want to enable this setting if you want to validate your data faster (basically, if you use this,
3219 validation will be more performant with the caveat that you get less information).
3221 ```python
3222 from typing import Annotated
3224 from pydantic import BaseModel, FailFast, ValidationError
3226 class Model(BaseModel):
3227 x: Annotated[list[int], FailFast()]
3229 # This will raise a single error for the first invalid value and stop validation
3230 try:
3231 obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c'])
3232 except ValidationError as e:
3233 print(e)
3234 '''
3235 1 validation error for Model
3236 x.2
3237 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
3238 '''
3239 ```
3240 """
3242 fail_fast: bool = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy