| """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 types import FunctionType |
| 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, go {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: |
| |
| |
| |
| |
| |
| from pydantic import PydanticSchemaGenerationError |
|
|
| try: |
| schema = handler(source_type) |
| |
| |
| 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, |
| 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, |
| 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( |
| 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: |
| field: The first field the `field_validator` should be called on; this is separate |
| from `fields` to ensure an error is raised if you don't pass at least one. |
| *fields: Additional field(s) the `field_validator` should be called on. |
| 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'`. |
| |
| Returns: |
| A decorator that can be used to decorate a function to be used as a field_validator. |
| |
| Raises: |
| PydanticUserError: |
| - If `@field_validator` is used bare (with no fields). |
| - If the args passed to `@field_validator` as fields are not strings. |
| - If `@field_validator` applied to instance methods. |
| """ |
| if isinstance(field, FunctionType): |
| raise PydanticUserError( |
| '`@field_validator` should be used with fields and keyword arguments, not bare. ' |
| "E.g. usage should be `@validator('<field_name>', ...)`", |
| code='validator-no-fields', |
| ) |
|
|
| 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( |
| '`@field_validator` fields should be passed as separate string args. ' |
| "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`", |
| code='validator-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( |
| '`@field_validator` cannot be applied to instance methods', code='validator-instance-method' |
| ) |
|
|
| |
| 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__( |
| self, |
| value: Any, |
| outer_location: str | int | None = None, |
| /, |
| ) -> _ModelTypeCo: |
| ... |
|
|
|
|
| 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__( |
| self, |
| cls: type[_ModelType], |
| |
| |
| |
| value: Any, |
| handler: ModelWrapValidatorHandler[_ModelType], |
| /, |
| ) -> _ModelType: ... |
|
|
|
|
| class ModelWrapValidator(Protocol[_ModelType]): |
| """A `@model_validator` decorated function signature. This is used when `mode='wrap'`.""" |
|
|
| def __call__( |
| self, |
| cls: type[_ModelType], |
| |
| |
| |
| 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__( |
| self, |
| |
| |
| |
| 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__( |
| self, |
| cls: Any, |
| |
| |
| |
| value: Any, |
| /, |
| ) -> Any: ... |
|
|
|
|
| class FreeModelBeforeValidator(Protocol): |
| """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" |
|
|
| def __call__( |
| self, |
| |
| |
| |
| 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__( |
| self, |
| cls: Any, |
| |
| |
| |
| 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]: |
| |
| 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: |
| |
| InstanceOf = Annotated[AnyType, ...] |
|
|
| 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 import PydanticSchemaGenerationError |
|
|
| |
| instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) |
|
|
| try: |
| |
| original_schema = handler(source) |
| except PydanticSchemaGenerationError: |
| |
| return instance_of_schema |
| else: |
| |
| 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, ...] |
| 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) |
| ``` |
| """ |
|
|
| |
| 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, |
| ) |
|
|