Coverage for pydantic/types.py: 97.64%
660 statements
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-26 11:49 +0000
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-26 11:49 +0000
1"""The types module contains custom types used by pydantic."""
3from __future__ import annotations as _annotations 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
5import base64 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
6import dataclasses as _dataclasses 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
7import re 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
8from collections.abc import Hashable, Iterator 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
9from datetime import date, datetime 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
10from decimal import Decimal 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
11from enum import Enum 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
12from pathlib import Path 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
13from re import Pattern 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
14from types import ModuleType 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
15from typing import ( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
29import annotated_types 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
30from annotated_types import BaseMetadata, MaxLen, MinLen 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
31from pydantic_core import CoreSchema, PydanticCustomError, SchemaSerializer, core_schema 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
32from typing_extensions import Protocol, TypeAlias, TypeAliasType, deprecated, get_args, get_origin 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
33from typing_inspection.introspection import is_union_origin 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
35from ._internal import _fields, _internal_dataclass, _utils, _validators 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
36from ._migration import getattr_migration 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
37from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
38from .errors import PydanticUserError 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
39from .json_schema import JsonSchemaValue 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
40from .warnings import PydanticDeprecatedSince20 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
42if TYPE_CHECKING: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
43 from ._internal._core_metadata import CoreMetadata
45__all__ = ( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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') 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
116@_dataclasses.dataclass 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
117class Strict(_fields.PydanticMetadata, BaseMetadata): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
139 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
140 return hash(self.strict) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
143# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145StrictBool = Annotated[bool, Strict()] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
146"""A boolean that must be either ``True`` or ``False``.""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
148# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151def conint( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
239"""An integer that must be greater than zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
270"""An integer that must be less than zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
301"""An integer that must be less than or equal to zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
332"""An integer that must be greater than or equal to zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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()] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
363"""An integer that must be validated in strict mode. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
387class AllowInfNan(_fields.PydanticMetadata): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
407 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
408 return hash(self.allow_inf_nan) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
411def confloat( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
501"""A float that must be greater than zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
532"""A float that must be less than zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
563"""A float that must be less than or equal to zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
594"""A float that must be greater than or equal to zero. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
625"""A float that must be validated in strict mode. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
645"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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()] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
687"""A bytes that must be validated in strict mode.""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
690# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
693@_dataclasses.dataclass(frozen=True) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
694class StringConstraints(annotated_types.GroupedMetadata): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
721 to_upper: bool | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
722 to_lower: bool | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
723 strict: bool | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
724 min_length: int | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
725 max_length: int | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
726 pattern: str | Pattern[str] | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
728 def __iter__(self) -> Iterator[BaseMetadata]: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
729 if self.min_length is not None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
730 yield MinLen(self.min_length) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
731 if self.max_length is not None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
732 yield MaxLen(self.max_length) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
733 if self.strict is not None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
734 yield Strict(self.strict) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
735 if ( 1IJKl
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( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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()] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
832"""A string that must be validated in strict mode.""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
835# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
836HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
839def conset( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
855def confrozenset( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
871AnyItemType = TypeVar('AnyItemType') 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
874def conlist( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
896 raise PydanticUserError( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
906# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
908AnyType = TypeVar('AnyType') 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
909if TYPE_CHECKING: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
910 ImportString = Annotated[AnyType, ...]
911else:
913 class ImportString: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
994 def __class_getitem__(cls, item: AnyType) -> AnyType: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
995 return Annotated[item, cls()] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
997 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
998 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1002 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1003 # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any]
1004 return core_schema.no_info_plain_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1005 function=_validators.import_string, serialization=serializer
1006 )
1007 else:
1008 return core_schema.no_info_before_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1009 function=_validators.import_string, schema=handler(source), serialization=serializer
1010 )
1012 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1013 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1014 return handler(core_schema.str_schema()) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1016 @staticmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1017 def _serialize(v: Any) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1018 if isinstance(v, ModuleType): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1019 return v.__name__ 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1020 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1021 return f'{v.__module__}.{v.__name__}' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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'): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1025 if v.name == '<stdout>': 1025 ↛ 1026line 1025 didn't jump to line 1026 because the condition on line 1025 was never true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1030 return 'sys.stderr'
1031 else:
1032 return v 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1034 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1035 return 'ImportString' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1038# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1041def condecimal( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1139class UuidVersion: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1160 def __get_pydantic_json_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1161 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1162 ) -> JsonSchemaValue:
1163 field_schema = handler(core_schema) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1164 field_schema.pop('anyOf', None) # remove the bytes/str union 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1165 field_schema.update(type='string', format=f'uuid{self.uuid_version}') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1166 return field_schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1168 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1169 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1170 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1171 schema['version'] = self.uuid_version # type: ignore 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1172 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1174 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1175 return hash(type(self.uuid_version)) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1178UUID1 = Annotated[UUID, UuidVersion(1)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1179"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1193"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1207"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1221"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1235"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 6. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1249"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 7. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1263"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 8. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1281class PathType: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1282 path_type: Literal['file', 'dir', 'new', 'socket'] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1284 def __get_pydantic_json_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1285 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
1286 ) -> JsonSchemaValue:
1287 field_schema = handler(core_schema) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1288 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1289 field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1290 return field_schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1292 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1293 function_lookup = { 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1301 function_lookup[self.path_type],
1302 handler(source),
1303 )
1305 @staticmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1306 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1307 if path.is_file(): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1308 return path 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1309 else:
1310 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1312 @staticmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1313 def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1314 if path.is_socket(): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1315 return path 1IJabcdefghijkKl
1316 else:
1317 raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1319 @staticmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1320 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1321 if path.is_dir(): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1322 return path 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1323 else:
1324 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1326 @staticmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1327 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1328 if path.exists(): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1329 raise PydanticCustomError('path_exists', 'Path already exists') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1330 elif not path.parent.exists(): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1331 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1332 else:
1333 return path 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1335 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1336 return hash(type(self.path_type)) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1339FilePath = Annotated[Path, PathType('file')] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1340"""A path that must point to a file. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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')] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1382"""A path that must point to a directory. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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')] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1424"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
1426SocketPath = Annotated[Path, PathType('socket')] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1427"""A path to an existing socket file""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
1429# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1431if TYPE_CHECKING: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1432 # Json[list[str]] will be recognized by type checkers as list[str]
1433 Json = Annotated[AnyType, ...]
1435else:
1437 class Json: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1511 def __class_getitem__(cls, item: AnyType) -> AnyType: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1512 return Annotated[item, cls()] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1514 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1515 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1516 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1517 return core_schema.json_schema(None) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1518 else:
1519 return core_schema.json_schema(handler(source)) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1521 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1522 return 'Json' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1524 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1525 return hash(type(self)) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1527 def __eq__(self, other: Any) -> bool: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1528 return type(other) is type(self) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1531# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1533# The `Secret` class being conceptually immutable, make the type variable covariant:
1534SecretType = TypeVar('SecretType', covariant=True) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1537class _SecretBase(Generic[SecretType]): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1538 def __init__(self, secret_value: SecretType) -> None: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1539 self._secret_value: SecretType = secret_value 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1541 def get_secret_value(self) -> SecretType: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1542 """Get the secret value.
1544 Returns:
1545 The secret value.
1546 """
1547 return self._secret_value 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1549 def __eq__(self, other: Any) -> bool: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1550 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1552 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1553 return hash(self.get_secret_value()) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1555 def __str__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1556 return str(self._display()) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1558 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1559 return f'{self.__class__.__name__}({self._display()!r})' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1561 def _display(self) -> str | bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1562 raise NotImplementedError
1565def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1566 if info.mode == 'json': 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1567 return str(value) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1568 else:
1569 return value 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1572class Secret(_SecretBase[SecretType]): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1679 return '**********' if self.get_secret_value() else '' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1681 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1682 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1683 inner_type = None 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1686 if origin_type is not None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1687 inner_type = get_args(source)[0] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1688 # otherwise, we need to get the inner type from the base class
1689 else:
1690 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1691 for base in bases: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1692 if get_origin(base) is Secret: 1692 ↛ 1691line 1692 didn't jump to line 1691 because the condition on line 1692 was always true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1693 inner_type = get_args(base)[0] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1702 def validate_secret_value(value, handler) -> Secret[SecretType]: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1703 if isinstance(value, Secret): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1704 value = value.get_secret_value() 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1705 validated_inner = handler(value) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1706 return cls(validated_inner) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1708 return core_schema.json_or_python_schema( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1733 return '**********' if value else '' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1736def _serialize_secret_field( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1737 value: _SecretField[SecretType], info: core_schema.SerializationInfo
1738) -> str | _SecretField[SecretType]:
1739 if info.mode == 'json': 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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()) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1743 else:
1744 return value 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1747class _SecretField(_SecretBase[SecretType]): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1748 _inner_schema: ClassVar[CoreSchema] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1749 _error_kind: ClassVar[str] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1751 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1752 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1753 def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1754 json_schema = handler(cls._inner_schema) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1755 _utils.update_not_none( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1756 json_schema,
1757 type='string',
1758 writeOnly=True,
1759 format='password',
1760 )
1761 return json_schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1763 def get_secret_schema(strict: bool) -> CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1764 inner_schema = {**cls._inner_schema, 'strict': strict} 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1765 json_schema = core_schema.no_info_after_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1766 source, # construct the type
1767 inner_schema, # pyright: ignore[reportArgumentType]
1768 )
1769 return core_schema.json_or_python_schema( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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]): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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() 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1860 _error_kind: ClassVar[str] = 'string_type' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1862 def __len__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1863 return len(self._secret_value) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1865 def _display(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1866 return _secret_display(self._secret_value) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1869class SecretBytes(_SecretField[bytes]): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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() 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1893 _error_kind: ClassVar[str] = 'bytes_type' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1895 def __len__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1896 return len(self._secret_value) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1898 def _display(self) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1899 return _secret_display(self._secret_value).encode() 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1902# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1905class PaymentCardBrand(str, Enum): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1906 amex = 'American Express' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1907 mastercard = 'Mastercard' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1908 visa = 'Visa' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1909 other = 'other' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1911 def __str__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1912 return self.value 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1915@deprecated( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1921 """Based on: https://en.wikipedia.org/wiki/Payment_card_number."""
1923 strip_whitespace: ClassVar[bool] = True 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1924 min_length: ClassVar[int] = 12 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1925 max_length: ClassVar[int] = 19 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1926 bin: str 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1927 last4: str 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1928 brand: PaymentCardBrand 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1930 def __init__(self, card_number: str): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1931 self.validate_digits(card_number) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1933 card_number = self.validate_luhn_check_digit(card_number) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1935 self.bin = card_number[:6] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1936 self.last4 = card_number[-4:] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1937 self.brand = self.validate_brand(card_number) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1939 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1940 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1941 return core_schema.with_info_after_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1949 def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1950 """Validate the card number and return a `PaymentCardNumber` instance."""
1951 return cls(input_value) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1953 @property 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1954 def masked(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1961 return f'{self.bin}{"*" * num_masked}{self.last4}' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1963 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1964 def validate_digits(cls, card_number: str) -> None: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1965 """Validate that the card number is all digits."""
1966 if not card_number.isdigit(): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1967 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1969 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1970 def validate_luhn_check_digit(cls, card_number: str) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1971 """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm."""
1972 sum_ = int(card_number[-1]) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1973 length = len(card_number) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1974 parity = length % 2 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1975 for i in range(length - 1): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1976 digit = int(card_number[i]) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1977 if i % 2 == parity: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1978 digit *= 2 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1979 if digit > 9: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1980 digit -= 9 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1981 sum_ += digit 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1982 valid = sum_ % 10 == 0 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1983 if not valid: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1984 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1985 return card_number 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1987 @staticmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
1988 def validate_brand(card_number: str) -> PaymentCardBrand: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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': 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1993 brand = PaymentCardBrand.visa 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1994 elif 51 <= int(card_number[:2]) <= 55: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1995 brand = PaymentCardBrand.mastercard 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1996 elif card_number[:2] in {'34', '37'}: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1997 brand = PaymentCardBrand.amex 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
1998 else:
1999 brand = PaymentCardBrand.other 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2001 required_length: None | int | str = None 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2002 if brand in PaymentCardBrand.mastercard: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2003 required_length = 16 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2004 valid = len(card_number) == required_length 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2005 elif brand == PaymentCardBrand.visa: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2006 required_length = '13, 16 or 19' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2007 valid = len(card_number) in {13, 16, 19} 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2008 elif brand == PaymentCardBrand.amex: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2009 required_length = 15 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2010 valid = len(card_number) == required_length 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2011 else:
2012 valid = True 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2014 if not valid: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2015 raise PydanticCustomError( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2023# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2026class ByteSize(int): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 = { 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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}) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2093 byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2094 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2096 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2097 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2098 return core_schema.with_info_after_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2114 def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2115 try: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2116 return cls(int(input_value)) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2117 except ValueError: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2118 pass 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2120 str_match = cls.byte_string_re.match(str(input_value)) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2121 if str_match is None: 2121 ↛ 2122line 2121 didn't jump to line 2122 because the condition on line 2121 was never true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2122 raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string')
2124 scalar, unit = str_match.groups() 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2125 if unit is None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2126 unit = 'b' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2128 try: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2129 unit_mult = cls.byte_sizes[unit.lower()] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2130 except KeyError: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2131 raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2133 return cls(int(float(scalar) * unit_mult)) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2135 def human_readable(self, decimal: bool = False, separator: str = '') -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2147 divisor = 1000 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2148 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2149 final_unit = 'EB' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2150 else:
2151 divisor = 1024 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2152 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2153 final_unit = 'EiB' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2155 num = float(self) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2156 for unit in units: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2157 if abs(num) < divisor: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2158 if unit == 'B': 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2159 return f'{num:0.0f}{separator}{unit}' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2160 else:
2161 return f'{num:0.1f}{separator}{unit}' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2162 num /= divisor 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2164 return f'{num:0.1f}{separator}{final_unit}' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2166 def to(self, unit: str) -> float: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2179 unit_div = self.byte_sizes[unit.lower()] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2180 except KeyError: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2181 raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2183 return self / unit_div 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2186# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2189def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2190 if annotated_type != expected_type: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2191 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2194if TYPE_CHECKING: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2195 PastDate = Annotated[date, ...]
2196 FutureDate = Annotated[date, ...]
2197else:
2199 class PastDate: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2200 """A date in the past."""
2202 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2203 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2204 cls, source: type[Any], handler: GetCoreSchemaHandler
2205 ) -> core_schema.CoreSchema:
2206 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2207 # used directly as a type
2208 return core_schema.date_schema(now_op='past') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2209 else:
2210 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2211 _check_annotated_type(schema['type'], 'date', cls.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2212 schema['now_op'] = 'past' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2213 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2215 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2216 return 'PastDate' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2218 class FutureDate: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2219 """A date in the future."""
2221 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2222 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2223 cls, source: type[Any], handler: GetCoreSchemaHandler
2224 ) -> core_schema.CoreSchema:
2225 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2226 # used directly as a type
2227 return core_schema.date_schema(now_op='future') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2228 else:
2229 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2230 _check_annotated_type(schema['type'], 'date', cls.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2231 schema['now_op'] = 'future' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2232 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2234 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2235 return 'FutureDate' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2238def condate( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2268 AwareDatetime = Annotated[datetime, ...]
2269 NaiveDatetime = Annotated[datetime, ...]
2270 PastDatetime = Annotated[datetime, ...]
2271 FutureDatetime = Annotated[datetime, ...]
2273else:
2275 class AwareDatetime: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2276 """A datetime that requires timezone info."""
2278 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2279 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2280 cls, source: type[Any], handler: GetCoreSchemaHandler
2281 ) -> core_schema.CoreSchema:
2282 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2283 # used directly as a type
2284 return core_schema.datetime_schema(tz_constraint='aware') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2285 else:
2286 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2287 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2288 schema['tz_constraint'] = 'aware' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2289 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2291 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2292 return 'AwareDatetime' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2294 class NaiveDatetime: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2295 """A datetime that doesn't require timezone info."""
2297 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2298 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2299 cls, source: type[Any], handler: GetCoreSchemaHandler
2300 ) -> core_schema.CoreSchema:
2301 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2302 # used directly as a type
2303 return core_schema.datetime_schema(tz_constraint='naive') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2304 else:
2305 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2306 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2307 schema['tz_constraint'] = 'naive' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2308 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2310 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2311 return 'NaiveDatetime' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2313 class PastDatetime: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2314 """A datetime that must be in the past."""
2316 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2317 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2318 cls, source: type[Any], handler: GetCoreSchemaHandler
2319 ) -> core_schema.CoreSchema:
2320 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2321 # used directly as a type
2322 return core_schema.datetime_schema(now_op='past') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2323 else:
2324 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2325 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2326 schema['now_op'] = 'past' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2327 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2329 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2330 return 'PastDatetime' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2332 class FutureDatetime: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2333 """A datetime that must be in the future."""
2335 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2336 def __get_pydantic_core_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2337 cls, source: type[Any], handler: GetCoreSchemaHandler
2338 ) -> core_schema.CoreSchema:
2339 if cls is source: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2340 # used directly as a type
2341 return core_schema.datetime_schema(now_op='future') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2342 else:
2343 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2344 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2345 schema['now_op'] = 'future' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2346 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2348 def __repr__(self) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2349 return 'FutureDatetime' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2352# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2355class EncoderProtocol(Protocol): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2356 """Protocol for encoding and decoding data to and from bytes.""" 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2358 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2359 def decode(cls, data: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2371 def encode(cls, value: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2383 def get_json_format(cls) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2384 """Get the JSON format for the encoded data.
2386 Returns:
2387 The JSON format for the encoded data.
2388 """
2389 ...
2392class Base64Encoder(EncoderProtocol): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2393 """Standard (non-URL-safe) Base64 encoder."""
2395 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2396 def decode(cls, data: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2406 return base64.b64decode(data) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2407 except ValueError as e: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2408 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2410 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2411 def encode(cls, value: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2422 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2423 def get_json_format(cls) -> Literal['base64']: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2424 """Get the JSON format for the encoded data.
2426 Returns:
2427 The JSON format for the encoded data.
2428 """
2429 return 'base64' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2432class Base64UrlEncoder(EncoderProtocol): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2433 """URL-safe Base64 encoder."""
2435 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2436 def decode(cls, data: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2446 return base64.urlsafe_b64decode(data) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2447 except ValueError as e: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2448 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2450 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2451 def encode(cls, value: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2462 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2463 def get_json_format(cls) -> Literal['base64url']: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2464 """Get the JSON format for the encoded data.
2466 Returns:
2467 The JSON format for the encoded data.
2468 """
2469 return 'base64url' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2472@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2473class EncodedBytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2529 def __get_pydantic_json_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2530 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2531 ) -> JsonSchemaValue:
2532 field_schema = handler(core_schema) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2533 field_schema.update(type='string', format=self.encoder.get_json_format()) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2534 return field_schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2536 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2537 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2538 _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2539 return core_schema.with_info_after_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2556 def encode(self, value: bytes) -> bytes: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2567 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2568 return hash(self.encoder) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2571@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2572class EncodedStr: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2628 def __get_pydantic_json_schema__( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2629 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2630 ) -> JsonSchemaValue:
2631 field_schema = handler(core_schema) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2632 field_schema.update(type='string', format=self.encoder.get_json_format()) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2633 return field_schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2635 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2636 schema = handler(source) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2637 _check_annotated_type(schema['type'], 'str', self.__class__.__name__) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2638 return core_schema.with_info_after_validator_function( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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() 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2655 def encode_str(self, value: str) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2666 def __hash__(self) -> int: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2667 return hash(self.encoder) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2670Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2671"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2749"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2796"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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)] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2818"""A str type that is encoded and decoded using the URL-safe base64 encoder. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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__) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2843@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2844class GetPydanticSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2870 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2876 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
2878 def __getattr__(self, item: str) -> Any: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2881 return self.get_pydantic_core_schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2883 return self.get_pydantic_json_schema
2884 else:
2885 return object.__getattribute__(self, item) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2887 __hash__ = object.__hash__ 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2890@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2891class Tag: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2968 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2969 schema = handler(source_type) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2970 metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2971 metadata['pydantic_internal_union_tag_key'] = self.tag 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2972 return schema 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
2975@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
2976class Discriminator: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3049 """The callable or field name for discriminating the type in a tagged union. 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3055 """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
3056 validation errors.
3057 """
3058 custom_error_message: str | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3059 """Message to use in custom errors.""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
3060 custom_error_context: dict[str, int | str | float] | None = None 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3061 """Context to use in custom errors.""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
3063 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3065 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}')
3067 if isinstance(self.discriminator, str): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3068 from pydantic import Field 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3070 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3071 else:
3072 original_schema = handler(source_type) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3073 return self._convert_schema(original_schema, handler) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3075 def _convert_schema( 1IJabcdefghijkLMmnopqrstuvwPNOxyzABCDEFGH
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 true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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 = {} 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3086 for choice in original_schema['choices']: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3087 tag = None 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3088 if isinstance(choice, tuple): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3089 choice, tag = choice 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3090 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3091 if metadata is not None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3092 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3093 if tag is None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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': 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3096 # If choice was built from a PEP 695 type alias, try to resolve the def:
3097 try: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3098 choice = handler.resolve_ref_schema(choice) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3099 except LookupError: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3100 pass 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3101 else:
3102 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3103 if metadata is not None: 3103 ↛ 3106line 3103 didn't jump to line 3106 because the condition on line 3103 was always true1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3104 tag = metadata.get('pydantic_internal_union_tag_key') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3106 if tag is None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3107 raise PydanticUserError( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3108 f'`Tag` not provided for choice {choice} used with `Discriminator`',
3109 code='callable-discriminator-no-tag',
3110 )
3111 tagged_union_choices[tag] = choice 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3113 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored
3114 custom_error_type = self.custom_error_type 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3115 if custom_error_type is None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3116 custom_error_type = original_schema.get('custom_error_type') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3118 custom_error_message = self.custom_error_message 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3119 if custom_error_message is None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3120 custom_error_message = original_schema.get('custom_error_message') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3122 custom_error_context = self.custom_error_context 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3123 if custom_error_context is None: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3124 custom_error_context = original_schema.get('custom_error_context') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3126 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3127 return core_schema.tagged_union_schema( 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
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)} 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3143def _get_type_name(x: Any) -> str: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3144 type_ = type(x) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3145 if type_ in _JSON_TYPES: 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3146 return type_.__name__ 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3148 # Handle proper subclasses; note we don't need to handle None or bool here
3149 if isinstance(x, int): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3150 return 'int' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3151 if isinstance(x, float): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3152 return 'float' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3153 if isinstance(x, str): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3154 return 'str' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3155 if isinstance(x, list): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3156 return 'list' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3157 if isinstance(x, dict): 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3158 return 'dict' 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3160 # Fail by returning the type's actual name
3161 return getattr(type_, '__name__', '<no type name>') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3164class _AllowAnyJson: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3165 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3166 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3167 python_schema = handler(source_type) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3168 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3171if TYPE_CHECKING: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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( 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3249 @classmethod 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3250 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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') 1IJabcdefghijkKlLMmnopqrstuvwNOxyzABCDEFGH
3257OnErrorOmit = Annotated[T, _OnErrorOmit] 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3258""" 1abcdefghijklmnopqrstuvwPxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
3267class FailFast(_fields.PydanticMetadata, BaseMetadata): 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH
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 1IJabcdefghijkKlLMmnopqrstuvwPNOxyzABCDEFGH