Загрузить файлы в «venv/Lib/site-packages/pydantic»

This commit is contained in:
2026-07-02 20:06:03 +00:00
parent 3a98e50f06
commit de54c840cf
5 changed files with 4280 additions and 0 deletions

View File

@@ -0,0 +1,470 @@
"""This module contains related classes and functions for serialization."""
from __future__ import annotations
import dataclasses
from functools import partial, partialmethod
from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, overload
from pydantic_core import PydanticUndefined, core_schema
from pydantic_core.core_schema import SerializationInfo, SerializerFunctionWrapHandler, WhenUsed
from typing_extensions import TypeAlias
from . import PydanticUndefinedAnnotation
from ._internal import _decorators, _internal_dataclass
from .annotated_handlers import GetCoreSchemaHandler
from .errors import PydanticUserError
@dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True)
class PlainSerializer:
"""Plain serializers use a function to modify the output of serialization.
This is particularly helpful when you want to customize the serialization for annotated types.
Consider an input of `list`, which will be serialized into a space-delimited string.
```python
from typing import Annotated
from pydantic import BaseModel, PlainSerializer
CustomStr = Annotated[
list, PlainSerializer(lambda x: ' '.join(x), return_type=str)
]
class StudentModel(BaseModel):
courses: CustomStr
student = StudentModel(courses=['Math', 'Chemistry', 'English'])
print(student.model_dump())
#> {'courses': 'Math Chemistry English'}
```
Attributes:
func: The serializer function.
return_type: The return type for the function. If omitted it will be inferred from the type annotation.
when_used: Determines when this serializer should be used. Accepts a string with values `'always'`,
`'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'.
"""
func: core_schema.SerializerFunction
return_type: Any = PydanticUndefined
when_used: WhenUsed = 'always'
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
"""Gets the Pydantic core schema.
Args:
source_type: The source type.
handler: The `GetCoreSchemaHandler` instance.
Returns:
The Pydantic core schema.
"""
schema = handler(source_type)
if self.return_type is not PydanticUndefined:
return_type = self.return_type
else:
try:
# Do not pass in globals as the function could be defined in a different module.
# Instead, let `get_callable_return_type` infer the globals to use, but still pass
# in locals that may contain a parent/rebuild namespace:
return_type = _decorators.get_callable_return_type(
self.func,
localns=handler._get_types_namespace().locals,
)
except NameError as e:
raise PydanticUndefinedAnnotation.from_name_error(e) from e
return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type)
schema['serialization'] = core_schema.plain_serializer_function_ser_schema(
function=self.func,
info_arg=_decorators.inspect_annotated_serializer(self.func, 'plain'),
return_schema=return_schema,
when_used=self.when_used,
)
return schema
@dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True)
class WrapSerializer:
"""Wrap serializers receive the raw inputs along with a handler function that applies the standard serialization
logic, and can modify the resulting value before returning it as the final output of serialization.
For example, here's a scenario in which a wrap serializer transforms timezones to UTC **and** utilizes the existing `datetime` serialization logic.
```python
from datetime import datetime, timezone
from typing import Annotated, Any
from pydantic import BaseModel, WrapSerializer
class EventDatetime(BaseModel):
start: datetime
end: datetime
def convert_to_utc(value: Any, handler, info) -> dict[str, datetime]:
# Note that `handler` can actually help serialize the `value` for
# further custom serialization in case it's a subclass.
partial_result = handler(value, info)
if info.mode == 'json':
return {
k: datetime.fromisoformat(v).astimezone(timezone.utc)
for k, v in partial_result.items()
}
return {k: v.astimezone(timezone.utc) for k, v in partial_result.items()}
UTCEventDatetime = Annotated[EventDatetime, WrapSerializer(convert_to_utc)]
class EventModel(BaseModel):
event_datetime: UTCEventDatetime
dt = EventDatetime(
start='2024-01-01T07:00:00-08:00', end='2024-01-03T20:00:00+06:00'
)
event = EventModel(event_datetime=dt)
print(event.model_dump())
'''
{
'event_datetime': {
'start': datetime.datetime(
2024, 1, 1, 15, 0, tzinfo=datetime.timezone.utc
),
'end': datetime.datetime(
2024, 1, 3, 14, 0, tzinfo=datetime.timezone.utc
),
}
}
'''
print(event.model_dump_json())
'''
{"event_datetime":{"start":"2024-01-01T15:00:00Z","end":"2024-01-03T14:00:00Z"}}
'''
```
Attributes:
func: The serializer function to be wrapped.
return_type: The return type for the function. If omitted it will be inferred from the type annotation.
when_used: Determines when this serializer should be used. Accepts a string with values `'always'`,
`'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'.
"""
func: core_schema.WrapSerializerFunction
return_type: Any = PydanticUndefined
when_used: WhenUsed = 'always'
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
"""This method is used to get the Pydantic core schema of the class.
Args:
source_type: Source type.
handler: Core schema handler.
Returns:
The generated core schema of the class.
"""
schema = handler(source_type)
if self.return_type is not PydanticUndefined:
return_type = self.return_type
else:
try:
# Do not pass in globals as the function could be defined in a different module.
# Instead, let `get_callable_return_type` infer the globals to use, but still pass
# in locals that may contain a parent/rebuild namespace:
return_type = _decorators.get_callable_return_type(
self.func,
localns=handler._get_types_namespace().locals,
)
except NameError as e:
raise PydanticUndefinedAnnotation.from_name_error(e) from e
return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type)
schema['serialization'] = core_schema.wrap_serializer_function_ser_schema(
function=self.func,
info_arg=_decorators.inspect_annotated_serializer(self.func, 'wrap'),
return_schema=return_schema,
when_used=self.when_used,
)
return schema
if TYPE_CHECKING:
_Partial: TypeAlias = 'partial[Any] | partialmethod[Any]'
FieldPlainSerializer: TypeAlias = 'core_schema.SerializerFunction | _Partial'
"""A field serializer method or function in `plain` mode."""
FieldWrapSerializer: TypeAlias = 'core_schema.WrapSerializerFunction | _Partial'
"""A field serializer method or function in `wrap` mode."""
FieldSerializer: TypeAlias = 'FieldPlainSerializer | FieldWrapSerializer'
"""A field serializer method or function."""
_FieldPlainSerializerT = TypeVar('_FieldPlainSerializerT', bound=FieldPlainSerializer)
_FieldWrapSerializerT = TypeVar('_FieldWrapSerializerT', bound=FieldWrapSerializer)
@overload
def field_serializer(
field: str,
/,
*fields: str,
mode: Literal['wrap'],
return_type: Any = ...,
when_used: WhenUsed = ...,
check_fields: bool | None = ...,
) -> Callable[[_FieldWrapSerializerT], _FieldWrapSerializerT]: ...
@overload
def field_serializer(
field: str,
/,
*fields: str,
mode: Literal['plain'] = ...,
return_type: Any = ...,
when_used: WhenUsed = ...,
check_fields: bool | None = ...,
) -> Callable[[_FieldPlainSerializerT], _FieldPlainSerializerT]: ...
def field_serializer( # noqa: D417
field: str,
/,
*fields: str,
mode: Literal['plain', 'wrap'] = 'plain',
# TODO PEP 747 (grep for 'return_type' on the whole code base):
return_type: Any = PydanticUndefined,
when_used: WhenUsed = 'always',
check_fields: bool | None = None,
) -> (
Callable[[_FieldWrapSerializerT], _FieldWrapSerializerT]
| Callable[[_FieldPlainSerializerT], _FieldPlainSerializerT]
):
"""Decorator that enables custom field serialization.
In the below example, a field of type `set` is used to mitigate duplication. A `field_serializer` is used to serialize the data as a sorted list.
```python
from pydantic import BaseModel, field_serializer
class StudentModel(BaseModel):
name: str = 'Jane'
courses: set[str]
@field_serializer('courses', when_used='json')
def serialize_courses_in_order(self, courses: set[str]):
return sorted(courses)
student = StudentModel(courses={'Math', 'Chemistry', 'English'})
print(student.model_dump_json())
#> {"name":"Jane","courses":["Chemistry","English","Math"]}
```
See [the usage documentation](../concepts/serialization.md#serializers) for more information.
Four signatures are supported for the decorated serializer:
- `(self, value: Any, info: FieldSerializationInfo)`
- `(self, value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo)`
- `(value: Any, info: SerializationInfo)`
- `(value: Any, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)`
Args:
*fields: The field names the serializer should apply to.
mode: The serialization mode.
- `plain` means the function will be called instead of the default serialization logic,
- `wrap` means the function will be called with an argument to optionally call the
default serialization logic.
return_type: Optional return type for the function, if omitted it will be inferred from the type annotation.
when_used: Determines the serializer will be used for serialization.
check_fields: Whether to check that the fields actually exist on the model.
Raises:
PydanticUserError:
- If the decorator is used without any arguments (at least one field name must be provided).
- If the provided field names are not strings.
"""
if callable(field) or isinstance(field, classmethod):
raise PydanticUserError(
'The `@field_serializer` decorator cannot be used without arguments, at least one field must be provided. '
"For example: `@field_serializer('<field_name>', ...)`.",
code='decorator-missing-arguments',
)
fields = field, *fields
if not all(isinstance(field, str) for field in fields):
raise PydanticUserError(
'The provided field names to the `@field_serializer` decorator should be strings. '
"For example: `@field_serializer('<field_name_1>', '<field_name_2>', ...).`",
code='decorator-invalid-fields',
)
def dec(f: FieldSerializer) -> _decorators.PydanticDescriptorProxy[Any]:
dec_info = _decorators.FieldSerializerDecoratorInfo(
fields=fields,
mode=mode,
return_type=return_type,
when_used=when_used,
check_fields=check_fields,
)
return _decorators.PydanticDescriptorProxy(f, dec_info) # pyright: ignore[reportArgumentType]
return dec # pyright: ignore[reportReturnType]
if TYPE_CHECKING:
# The first argument in the following callables represent the `self` type:
ModelPlainSerializerWithInfo: TypeAlias = Callable[[Any, SerializationInfo[Any]], Any]
"""A model serializer method with the `info` argument, in `plain` mode."""
ModelPlainSerializerWithoutInfo: TypeAlias = Callable[[Any], Any]
"""A model serializer method without the `info` argument, in `plain` mode."""
ModelPlainSerializer: TypeAlias = 'ModelPlainSerializerWithInfo | ModelPlainSerializerWithoutInfo'
"""A model serializer method in `plain` mode."""
ModelWrapSerializerWithInfo: TypeAlias = Callable[[Any, SerializerFunctionWrapHandler, SerializationInfo[Any]], Any]
"""A model serializer method with the `info` argument, in `wrap` mode."""
ModelWrapSerializerWithoutInfo: TypeAlias = Callable[[Any, SerializerFunctionWrapHandler], Any]
"""A model serializer method without the `info` argument, in `wrap` mode."""
ModelWrapSerializer: TypeAlias = 'ModelWrapSerializerWithInfo | ModelWrapSerializerWithoutInfo'
"""A model serializer method in `wrap` mode."""
ModelSerializer: TypeAlias = 'ModelPlainSerializer | ModelWrapSerializer'
_ModelPlainSerializerT = TypeVar('_ModelPlainSerializerT', bound=ModelPlainSerializer)
_ModelWrapSerializerT = TypeVar('_ModelWrapSerializerT', bound=ModelWrapSerializer)
@overload
def model_serializer(f: _ModelPlainSerializerT, /) -> _ModelPlainSerializerT: ...
@overload
def model_serializer(
*, mode: Literal['wrap'], when_used: WhenUsed = 'always', return_type: Any = ...
) -> Callable[[_ModelWrapSerializerT], _ModelWrapSerializerT]: ...
@overload
def model_serializer(
*,
mode: Literal['plain'] = ...,
when_used: WhenUsed = 'always',
return_type: Any = ...,
) -> Callable[[_ModelPlainSerializerT], _ModelPlainSerializerT]: ...
def model_serializer(
f: _ModelPlainSerializerT | _ModelWrapSerializerT | None = None,
/,
*,
mode: Literal['plain', 'wrap'] = 'plain',
when_used: WhenUsed = 'always',
return_type: Any = PydanticUndefined,
) -> (
_ModelPlainSerializerT
| Callable[[_ModelWrapSerializerT], _ModelWrapSerializerT]
| Callable[[_ModelPlainSerializerT], _ModelPlainSerializerT]
):
"""Decorator that enables custom model serialization.
This is useful when a model need to be serialized in a customized manner, allowing for flexibility beyond just specific fields.
An example would be to serialize temperature to the same temperature scale, such as degrees Celsius.
```python
from typing import Literal
from pydantic import BaseModel, model_serializer
class TemperatureModel(BaseModel):
unit: Literal['C', 'F']
value: int
@model_serializer()
def serialize_model(self):
if self.unit == 'F':
return {'unit': 'C', 'value': int((self.value - 32) / 1.8)}
return {'unit': self.unit, 'value': self.value}
temperature = TemperatureModel(unit='F', value=212)
print(temperature.model_dump())
#> {'unit': 'C', 'value': 100}
```
Two signatures are supported for `mode='plain'`, which is the default:
- `(self)`
- `(self, info: SerializationInfo)`
And two other signatures for `mode='wrap'`:
- `(self, nxt: SerializerFunctionWrapHandler)`
- `(self, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)`
See [the usage documentation](../concepts/serialization.md#serializers) for more information.
Args:
f: The function to be decorated.
mode: The serialization mode.
- `'plain'` means the function will be called instead of the default serialization logic
- `'wrap'` means the function will be called with an argument to optionally call the default
serialization logic.
when_used: Determines when this serializer should be used.
return_type: The return type for the function. If omitted it will be inferred from the type annotation.
Returns:
The decorator function.
"""
def dec(f: ModelSerializer) -> _decorators.PydanticDescriptorProxy[Any]:
dec_info = _decorators.ModelSerializerDecoratorInfo(mode=mode, return_type=return_type, when_used=when_used)
return _decorators.PydanticDescriptorProxy(f, dec_info)
if f is None:
return dec # pyright: ignore[reportReturnType]
else:
return dec(f) # pyright: ignore[reportReturnType]
AnyType = TypeVar('AnyType')
if TYPE_CHECKING:
SerializeAsAny = Annotated[AnyType, ...] # SerializeAsAny[list[str]] will be treated by type checkers as list[str]
"""Annotation used to mark a type as having duck-typing serialization behavior.
See [usage documentation](../concepts/serialization.md#serializing-with-duck-typing) for more details.
"""
else:
@dataclasses.dataclass(**_internal_dataclass.slots_true)
class SerializeAsAny:
"""Annotation used to mark a type as having duck-typing serialization behavior.
See [usage documentation](../concepts/serialization.md#serializing-with-duck-typing) for more details.
"""
def __class_getitem__(cls, item: Any) -> Any:
return Annotated[item, SerializeAsAny()]
def __get_pydantic_core_schema__(
self, source_type: Any, handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
schema = handler(source_type)
schema_to_update = schema
while schema_to_update['type'] == 'definitions':
schema_to_update = schema_to_update.copy()
schema_to_update = schema_to_update['schema']
schema_to_update['serialization'] = core_schema.simple_ser_schema('any')
return schema
__hash__ = object.__hash__

View File

@@ -0,0 +1,889 @@
"""This module contains related classes and functions for validation."""
from __future__ import annotations as _annotations
import dataclasses
import sys
import warnings
from functools import partialmethod
from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload
from pydantic_core import PydanticUndefined, core_schema
from typing_extensions import Self, TypeAlias
from ._internal import _decorators, _generics, _internal_dataclass
from .annotated_handlers import GetCoreSchemaHandler
from .errors import PydanticUserError
from .version import version_short
from .warnings import ArbitraryTypeWarning, PydanticDeprecatedSince212
if sys.version_info < (3, 11):
from typing_extensions import Protocol
else:
from typing import Protocol
_inspect_validator = _decorators.inspect_validator
@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)
class AfterValidator:
"""!!! abstract "Usage Documentation"
[field *after* validators](../concepts/validators.md#field-after-validator)
A metadata class that indicates that a validation should be applied **after** the inner validation logic.
Attributes:
func: The validator function.
Example:
```python
from typing import Annotated
from pydantic import AfterValidator, BaseModel, ValidationError
MyInt = Annotated[int, AfterValidator(lambda v: v + 1)]
class Model(BaseModel):
a: MyInt
print(Model(a=1).a)
#> 2
try:
Model(a='a')
except ValidationError as e:
print(e.json(indent=2))
'''
[
{
"type": "int_parsing",
"loc": [
"a"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "a",
"url": "https://errors.pydantic.dev/2/v/int_parsing"
}
]
'''
```
"""
func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
schema = handler(source_type)
info_arg = _inspect_validator(self.func, mode='after', type='field')
if info_arg:
func = cast(core_schema.WithInfoValidatorFunction, self.func)
return core_schema.with_info_after_validator_function(func, schema=schema)
else:
func = cast(core_schema.NoInfoValidatorFunction, self.func)
return core_schema.no_info_after_validator_function(func, schema=schema)
@classmethod
def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:
return cls(func=decorator.func)
@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)
class BeforeValidator:
"""!!! abstract "Usage Documentation"
[field *before* validators](../concepts/validators.md#field-before-validator)
A metadata class that indicates that a validation should be applied **before** the inner validation logic.
Attributes:
func: The validator function.
json_schema_input_type: The input type used to generate the appropriate
JSON Schema (in validation mode). The actual input type is `Any`.
Example:
```python
from typing import Annotated
from pydantic import BaseModel, BeforeValidator
MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)]
class Model(BaseModel):
a: MyInt
print(Model(a=1).a)
#> 2
try:
Model(a='a')
except TypeError as e:
print(e)
#> can only concatenate str (not "int") to str
```
"""
func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction
json_schema_input_type: Any = PydanticUndefined
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
schema = handler(source_type)
input_schema = (
None
if self.json_schema_input_type is PydanticUndefined
else handler.generate_schema(self.json_schema_input_type)
)
info_arg = _inspect_validator(self.func, mode='before', type='field')
if info_arg:
func = cast(core_schema.WithInfoValidatorFunction, self.func)
return core_schema.with_info_before_validator_function(
func,
schema=schema,
json_schema_input_schema=input_schema,
)
else:
func = cast(core_schema.NoInfoValidatorFunction, self.func)
return core_schema.no_info_before_validator_function(
func, schema=schema, json_schema_input_schema=input_schema
)
@classmethod
def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:
return cls(
func=decorator.func,
json_schema_input_type=decorator.info.json_schema_input_type,
)
@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)
class PlainValidator:
"""!!! abstract "Usage Documentation"
[field *plain* validators](../concepts/validators.md#field-plain-validator)
A metadata class that indicates that a validation should be applied **instead** of the inner validation logic.
!!! note
Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`.
You can now use the `json_schema_input_type` argument to specify the input type of the function
to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details.
Attributes:
func: The validator function.
json_schema_input_type: The input type used to generate the appropriate
JSON Schema (in validation mode). The actual input type is `Any`.
Example:
```python
from typing import Annotated, Union
from pydantic import BaseModel, PlainValidator
def validate(v: object) -> int:
if not isinstance(v, (int, str)):
raise ValueError(f'Expected int or str, got {type(v)}')
return int(v) + 1
MyInt = Annotated[
int,
PlainValidator(validate, json_schema_input_type=Union[str, int]), # (1)!
]
class Model(BaseModel):
a: MyInt
print(Model(a='1').a)
#> 2
print(Model(a=1).a)
#> 2
```
1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema
generator that in validation mode, the input type for the `a` field can be either a [`str`][] or an [`int`][].
"""
func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction
json_schema_input_type: Any = Any
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
# Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the
# source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper
# serialization schema. To work around this for use cases that will not involve serialization, we simply
# catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema
# and abort any attempts to handle special serialization.
from pydantic import PydanticSchemaGenerationError
try:
schema = handler(source_type)
# TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence',
# schema validation will fail. That's why we use 'type ignore' comments below.
serialization = schema.get(
'serialization',
core_schema.wrap_serializer_function_ser_schema(
function=lambda v, h: h(v),
schema=schema,
return_schema=handler.generate_schema(source_type),
),
)
except PydanticSchemaGenerationError:
serialization = None
input_schema = handler.generate_schema(self.json_schema_input_type)
info_arg = _inspect_validator(self.func, mode='plain', type='field')
if info_arg:
func = cast(core_schema.WithInfoValidatorFunction, self.func)
return core_schema.with_info_plain_validator_function(
func,
serialization=serialization, # pyright: ignore[reportArgumentType]
json_schema_input_schema=input_schema,
)
else:
func = cast(core_schema.NoInfoValidatorFunction, self.func)
return core_schema.no_info_plain_validator_function(
func,
serialization=serialization, # pyright: ignore[reportArgumentType]
json_schema_input_schema=input_schema,
)
@classmethod
def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:
return cls(
func=decorator.func,
json_schema_input_type=decorator.info.json_schema_input_type,
)
@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)
class WrapValidator:
"""!!! abstract "Usage Documentation"
[field *wrap* validators](../concepts/validators.md#field-wrap-validator)
A metadata class that indicates that a validation should be applied **around** the inner validation logic.
Attributes:
func: The validator function.
json_schema_input_type: The input type used to generate the appropriate
JSON Schema (in validation mode). The actual input type is `Any`.
```python
from datetime import datetime
from typing import Annotated
from pydantic import BaseModel, ValidationError, WrapValidator
def validate_timestamp(v, handler):
if v == 'now':
# we don't want to bother with further validation, just return the new value
return datetime.now()
try:
return handler(v)
except ValidationError:
# validation failed, in this case we want to return a default value
return datetime(2000, 1, 1)
MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)]
class Model(BaseModel):
a: MyTimestamp
print(Model(a='now').a)
#> 2032-01-02 03:04:05.000006
print(Model(a='invalid').a)
#> 2000-01-01 00:00:00
```
"""
func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction
json_schema_input_type: Any = PydanticUndefined
def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
schema = handler(source_type)
input_schema = (
None
if self.json_schema_input_type is PydanticUndefined
else handler.generate_schema(self.json_schema_input_type)
)
info_arg = _inspect_validator(self.func, mode='wrap', type='field')
if info_arg:
func = cast(core_schema.WithInfoWrapValidatorFunction, self.func)
return core_schema.with_info_wrap_validator_function(
func,
schema=schema,
json_schema_input_schema=input_schema,
)
else:
func = cast(core_schema.NoInfoWrapValidatorFunction, self.func)
return core_schema.no_info_wrap_validator_function(
func,
schema=schema,
json_schema_input_schema=input_schema,
)
@classmethod
def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:
return cls(
func=decorator.func,
json_schema_input_type=decorator.info.json_schema_input_type,
)
if TYPE_CHECKING:
class _OnlyValueValidatorClsMethod(Protocol):
def __call__(self, cls: Any, value: Any, /) -> Any: ...
class _V2ValidatorClsMethod(Protocol):
def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo[Any], /) -> Any: ...
class _OnlyValueWrapValidatorClsMethod(Protocol):
def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ...
class _V2WrapValidatorClsMethod(Protocol):
def __call__(
self,
cls: Any,
value: Any,
handler: core_schema.ValidatorFunctionWrapHandler,
info: core_schema.ValidationInfo[Any],
/,
) -> Any: ...
_V2Validator = Union[
_V2ValidatorClsMethod,
core_schema.WithInfoValidatorFunction,
_OnlyValueValidatorClsMethod,
core_schema.NoInfoValidatorFunction,
]
_V2WrapValidator = Union[
_V2WrapValidatorClsMethod,
core_schema.WithInfoWrapValidatorFunction,
_OnlyValueWrapValidatorClsMethod,
core_schema.NoInfoWrapValidatorFunction,
]
_PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
_V2BeforeAfterOrPlainValidatorType = TypeVar(
'_V2BeforeAfterOrPlainValidatorType',
bound=Union[_V2Validator, _PartialClsOrStaticMethod],
)
_V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod])
FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain']
@overload
def field_validator(
field: str,
/,
*fields: str,
mode: Literal['wrap'],
check_fields: bool | None = ...,
json_schema_input_type: Any = ...,
) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ...
@overload
def field_validator(
field: str,
/,
*fields: str,
mode: Literal['before', 'plain'],
check_fields: bool | None = ...,
json_schema_input_type: Any = ...,
) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ...
@overload
def field_validator(
field: str,
/,
*fields: str,
mode: Literal['after'] = ...,
check_fields: bool | None = ...,
) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ...
def field_validator( # noqa: D417
field: str,
/,
*fields: str,
mode: FieldValidatorModes = 'after',
check_fields: bool | None = None,
json_schema_input_type: Any = PydanticUndefined,
) -> Callable[[Any], Any]:
"""!!! abstract "Usage Documentation"
[field validators](../concepts/validators.md#field-validators)
Decorate methods on the class indicating that they should be used to validate fields.
Example usage:
```python
from typing import Any
from pydantic import (
BaseModel,
ValidationError,
field_validator,
)
class Model(BaseModel):
a: str
@field_validator('a')
@classmethod
def ensure_foobar(cls, v: Any):
if 'foobar' not in v:
raise ValueError('"foobar" not found in a')
return v
print(repr(Model(a='this is foobar good')))
#> Model(a='this is foobar good')
try:
Model(a='snap')
except ValidationError as exc_info:
print(exc_info)
'''
1 validation error for Model
a
Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str]
'''
```
For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators).
Args:
*fields: The field names the validator should apply to.
mode: Specifies whether to validate the fields before or after validation.
check_fields: Whether to check that the fields actually exist on the model.
json_schema_input_type: The input type of the function. This is only used to generate
the appropriate JSON Schema (in validation mode) and can only specified
when `mode` is either `'before'`, `'plain'` or `'wrap'`.
Raises:
PydanticUserError:
- If the decorator is used without any arguments (at least one field name must be provided).
- If the provided field names are not strings.
- If `json_schema_input_type` is provided with an unsupported `mode`.
- If the decorator is applied to an instance method.
"""
if callable(field) or isinstance(field, classmethod):
raise PydanticUserError(
'The `@field_validator` decorator cannot be used without arguments, at least one field must be provided. '
"For example: `@field_validator('<field_name>', ...)`.",
code='decorator-missing-arguments',
)
if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined:
raise PydanticUserError(
f"`json_schema_input_type` can't be used when mode is set to {mode!r}",
code='validator-input-type',
)
if json_schema_input_type is PydanticUndefined and mode == 'plain':
json_schema_input_type = Any
fields = field, *fields
if not all(isinstance(field, str) for field in fields):
raise PydanticUserError(
'The provided field names to the `@field_validator` decorator should be strings. '
"For example: `@field_validator('<field_name_1>', '<field_name_2>', ...).`",
code='decorator-invalid-fields',
)
def dec(
f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any],
) -> _decorators.PydanticDescriptorProxy[Any]:
if _decorators.is_instance_method_from_sig(f):
raise PydanticUserError(
'The `@field_validator` decorator cannot be applied to instance methods',
code='validator-instance-method',
)
# auto apply the @classmethod decorator
f = _decorators.ensure_classmethod_based_on_signature(f)
dec_info = _decorators.FieldValidatorDecoratorInfo(
fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type
)
return _decorators.PydanticDescriptorProxy(f, dec_info)
return dec
_ModelType = TypeVar('_ModelType')
_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True)
class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]):
"""`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`."""
def __call__( # noqa: D102
self,
value: Any,
outer_location: str | int | None = None,
/,
) -> _ModelTypeCo: # pragma: no cover
...
class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]):
"""A `@model_validator` decorated function signature.
This is used when `mode='wrap'` and the function does not have info argument.
"""
def __call__( # noqa: D102
self,
cls: type[_ModelType],
# this can be a dict, a model instance
# or anything else that gets passed to validate_python
# thus validators _must_ handle all cases
value: Any,
handler: ModelWrapValidatorHandler[_ModelType],
/,
) -> _ModelType: ...
class ModelWrapValidator(Protocol[_ModelType]):
"""A `@model_validator` decorated function signature. This is used when `mode='wrap'`."""
def __call__( # noqa: D102
self,
cls: type[_ModelType],
# this can be a dict, a model instance
# or anything else that gets passed to validate_python
# thus validators _must_ handle all cases
value: Any,
handler: ModelWrapValidatorHandler[_ModelType],
info: core_schema.ValidationInfo,
/,
) -> _ModelType: ...
class FreeModelBeforeValidatorWithoutInfo(Protocol):
"""A `@model_validator` decorated function signature.
This is used when `mode='before'` and the function does not have info argument.
"""
def __call__( # noqa: D102
self,
# this can be a dict, a model instance
# or anything else that gets passed to validate_python
# thus validators _must_ handle all cases
value: Any,
/,
) -> Any: ...
class ModelBeforeValidatorWithoutInfo(Protocol):
"""A `@model_validator` decorated function signature.
This is used when `mode='before'` and the function does not have info argument.
"""
def __call__( # noqa: D102
self,
cls: Any,
# this can be a dict, a model instance
# or anything else that gets passed to validate_python
# thus validators _must_ handle all cases
value: Any,
/,
) -> Any: ...
class FreeModelBeforeValidator(Protocol):
"""A `@model_validator` decorated function signature. This is used when `mode='before'`."""
def __call__( # noqa: D102
self,
# this can be a dict, a model instance
# or anything else that gets passed to validate_python
# thus validators _must_ handle all cases
value: Any,
info: core_schema.ValidationInfo[Any],
/,
) -> Any: ...
class ModelBeforeValidator(Protocol):
"""A `@model_validator` decorated function signature. This is used when `mode='before'`."""
def __call__( # noqa: D102
self,
cls: Any,
# this can be a dict, a model instance
# or anything else that gets passed to validate_python
# thus validators _must_ handle all cases
value: Any,
info: core_schema.ValidationInfo[Any],
/,
) -> Any: ...
ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType]
"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not
have info argument.
"""
ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType]
"""A `@model_validator` decorated function signature. This is used when `mode='after'`."""
_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]]
_AnyModelBeforeValidator = Union[
FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo
]
_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]]
@overload
def model_validator(
*,
mode: Literal['wrap'],
) -> Callable[
[_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
]: ...
@overload
def model_validator(
*,
mode: Literal['before'],
) -> Callable[
[_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
]: ...
@overload
def model_validator(
*,
mode: Literal['after'],
) -> Callable[
[_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
]: ...
def model_validator(
*,
mode: Literal['wrap', 'before', 'after'],
) -> Any:
"""!!! abstract "Usage Documentation"
[Model Validators](../concepts/validators.md#model-validators)
Decorate model methods for validation purposes.
Example usage:
```python
from typing_extensions import Self
from pydantic import BaseModel, ValidationError, model_validator
class Square(BaseModel):
width: float
height: float
@model_validator(mode='after')
def verify_square(self) -> Self:
if self.width != self.height:
raise ValueError('width and height do not match')
return self
s = Square(width=1, height=1)
print(repr(s))
#> Square(width=1.0, height=1.0)
try:
Square(width=1, height=2)
except ValidationError as e:
print(e)
'''
1 validation error for Square
Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict]
'''
```
For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators).
Args:
mode: A required string literal that specifies the validation mode.
It can be one of the following: 'wrap', 'before', or 'after'.
Returns:
A decorator that can be used to decorate a function to be used as a model validator.
"""
def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]:
# auto apply the @classmethod decorator. NOTE: in V3, do not apply the conversion for 'after' validators:
f = _decorators.ensure_classmethod_based_on_signature(f)
if mode == 'after' and isinstance(f, classmethod):
warnings.warn(
category=PydanticDeprecatedSince212,
message=(
"Using `@model_validator` with mode='after' on a classmethod is deprecated. Instead, use an instance method. "
f'See the documentation at https://docs.pydantic.dev/{version_short()}/concepts/validators/#model-after-validator.'
),
stacklevel=2,
)
dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode)
return _decorators.PydanticDescriptorProxy(f, dec_info)
return dec
AnyType = TypeVar('AnyType')
if TYPE_CHECKING:
# If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this
InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence`
else:
@dataclasses.dataclass(**_internal_dataclass.slots_true)
class InstanceOf:
'''Generic type for annotating a type that is an instance of a given class.
Example:
```python
from pydantic import BaseModel, InstanceOf
class Foo:
...
class Bar(BaseModel):
foo: InstanceOf[Foo]
Bar(foo=Foo())
try:
Bar(foo=42)
except ValidationError as e:
print(e)
"""
[
{
│ │ 'type': 'is_instance_of',
│ │ 'loc': ('foo',),
│ │ 'msg': 'Input should be an instance of Foo',
│ │ 'input': 42,
│ │ 'ctx': {'class': 'Foo'},
│ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of'
│ }
]
"""
```
'''
@classmethod
def __class_getitem__(cls, item: AnyType) -> AnyType:
return Annotated[item, cls()]
@classmethod
def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
from pydantic._internal._generate_schema import GENERATE_SCHEMA_ERRORS
# use the generic _origin_ as the second argument to isinstance when appropriate
instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source)
try:
# Try to generate the "standard" schema, which will be used when loading from JSON
original_schema = handler(source)
except GENERATE_SCHEMA_ERRORS:
# If that fails, just produce a schema that can validate from python
return instance_of_schema
else:
# Use the "original" approach to serialization
instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema(
function=lambda v, h: h(v), schema=original_schema
)
return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema)
__hash__ = object.__hash__
if TYPE_CHECKING:
SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str]
else:
@dataclasses.dataclass(**_internal_dataclass.slots_true)
class SkipValidation:
"""If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be
skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`.
This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes,
and know that it is safe to skip validation for one or more of the fields.
Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations
may not have the expected effects. Therefore, when used, this annotation should generally be the final
annotation applied to a type.
"""
def __class_getitem__(cls, item: Any) -> Any:
return Annotated[item, SkipValidation()]
@classmethod
def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
with warnings.catch_warnings():
warnings.simplefilter('ignore', ArbitraryTypeWarning)
original_schema = handler(source)
metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]}
return core_schema.any_schema(
metadata=metadata,
serialization=core_schema.wrap_serializer_function_ser_schema(
function=lambda v, h: h(v), schema=original_schema
),
)
__hash__ = object.__hash__
_FromTypeT = TypeVar('_FromTypeT')
class ValidateAs:
"""A helper class to validate a custom type from a type that is natively supported by Pydantic.
Args:
from_type: The type natively supported by Pydantic to use to perform validation.
instantiation_hook: A callable taking the validated type as an argument, and returning
the populated custom type.
Example:
```python {lint="skip"}
from typing import Annotated
from pydantic import BaseModel, TypeAdapter, ValidateAs
class MyCls:
def __init__(self, a: int) -> None:
self.a = a
def __repr__(self) -> str:
return f"MyCls(a={self.a})"
class Model(BaseModel):
a: int
ta = TypeAdapter(
Annotated[MyCls, ValidateAs(Model, lambda v: MyCls(a=v.a))]
)
print(ta.validate_python({'a': 1}))
#> MyCls(a=1)
```
"""
# TODO: make use of PEP 747
def __init__(self, from_type: type[_FromTypeT], /, instantiation_hook: Callable[[_FromTypeT], Any]) -> None:
self.from_type = from_type
self.instantiation_hook = instantiation_hook
def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
schema = handler(self.from_type)
return core_schema.no_info_after_validator_function(
self.instantiation_hook,
schema=schema,
)

View File

@@ -0,0 +1,5 @@
"""The `generics` module is a backport module from V1."""
from ._migration import getattr_migration
__getattr__ = getattr_migration(__name__)

View File

@@ -0,0 +1,5 @@
"""The `json` module is a backport module from V1."""
from ._migration import getattr_migration
__getattr__ = getattr_migration(__name__)

File diff suppressed because it is too large Load Diff