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