codekingpro/portable-devtools
115k
1"""This module contains related classes and functions for validation."""2 3from __future__ import annotations as _annotations4 5import dataclasses6import sys7import warnings8from functools import partialmethod9from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload10 11from pydantic_core import PydanticUndefined, core_schema12from typing_extensions import Self, TypeAlias13 14from ._internal import _decorators, _generics, _internal_dataclass15from .annotated_handlers import GetCoreSchemaHandler16from .errors import PydanticUserError17from .version import version_short18from .warnings import ArbitraryTypeWarning, PydanticDeprecatedSince21219 20if sys.version_info < (3, 11):21 from typing_extensions import Protocol22else:23 from typing import Protocol24 25_inspect_validator = _decorators.inspect_validator26 27 28@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)29class AfterValidator:30 """!!! abstract "Usage Documentation"31 [field *after* validators](../concepts/validators.md#field-after-validator)32 33 A metadata class that indicates that a validation should be applied **after** the inner validation logic.34 35 Attributes:36 func: The validator function.37 38 Example:39 ```python40 from typing import Annotated41 42 from pydantic import AfterValidator, BaseModel, ValidationError43 44 MyInt = Annotated[int, AfterValidator(lambda v: v + 1)]45 46 class Model(BaseModel):47 a: MyInt48 49 print(Model(a=1).a)50 #> 251 52 try:53 Model(a='a')54 except ValidationError as e:55 print(e.json(indent=2))56 '''57 [58 {59 "type": "int_parsing",60 "loc": [61 "a"62 ],63 "msg": "Input should be a valid integer, unable to parse string as an integer",64 "input": "a",65 "url": "https://errors.pydantic.dev/2/v/int_parsing"66 }67 ]68 '''69 ```70 """71 72 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction73 74 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:75 schema = handler(source_type)76 info_arg = _inspect_validator(self.func, mode='after', type='field')77 if info_arg:78 func = cast(core_schema.WithInfoValidatorFunction, self.func)79 return core_schema.with_info_after_validator_function(func, schema=schema)80 else:81 func = cast(core_schema.NoInfoValidatorFunction, self.func)82 return core_schema.no_info_after_validator_function(func, schema=schema)83 84 @classmethod85 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:86 return cls(func=decorator.func)87 88 89@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)90class BeforeValidator:91 """!!! abstract "Usage Documentation"92 [field *before* validators](../concepts/validators.md#field-before-validator)93 94 A metadata class that indicates that a validation should be applied **before** the inner validation logic.95 96 Attributes:97 func: The validator function.98 json_schema_input_type: The input type used to generate the appropriate99 JSON Schema (in validation mode). The actual input type is `Any`.100 101 Example:102 ```python103 from typing import Annotated104 105 from pydantic import BaseModel, BeforeValidator106 107 MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)]108 109 class Model(BaseModel):110 a: MyInt111 112 print(Model(a=1).a)113 #> 2114 115 try:116 Model(a='a')117 except TypeError as e:118 print(e)119 #> can only concatenate str (not "int") to str120 ```121 """122 123 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction124 json_schema_input_type: Any = PydanticUndefined125 126 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:127 schema = handler(source_type)128 input_schema = (129 None130 if self.json_schema_input_type is PydanticUndefined131 else handler.generate_schema(self.json_schema_input_type)132 )133 134 info_arg = _inspect_validator(self.func, mode='before', type='field')135 if info_arg:136 func = cast(core_schema.WithInfoValidatorFunction, self.func)137 return core_schema.with_info_before_validator_function(138 func,139 schema=schema,140 json_schema_input_schema=input_schema,141 )142 else:143 func = cast(core_schema.NoInfoValidatorFunction, self.func)144 return core_schema.no_info_before_validator_function(145 func, schema=schema, json_schema_input_schema=input_schema146 )147 148 @classmethod149 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:150 return cls(151 func=decorator.func,152 json_schema_input_type=decorator.info.json_schema_input_type,153 )154 155 156@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)157class PlainValidator:158 """!!! abstract "Usage Documentation"159 [field *plain* validators](../concepts/validators.md#field-plain-validator)160 161 A metadata class that indicates that a validation should be applied **instead** of the inner validation logic.162 163 !!! note164 Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`.165 You can now use the `json_schema_input_type` argument to specify the input type of the function166 to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details.167 168 Attributes:169 func: The validator function.170 json_schema_input_type: The input type used to generate the appropriate171 JSON Schema (in validation mode). The actual input type is `Any`.172 173 Example:174 ```python175 from typing import Annotated, Union176 177 from pydantic import BaseModel, PlainValidator178 179 def validate(v: object) -> int:180 if not isinstance(v, (int, str)):181 raise ValueError(f'Expected int or str, got {type(v)}')182 183 return int(v) + 1184 185 MyInt = Annotated[186 int,187 PlainValidator(validate, json_schema_input_type=Union[str, int]), # (1)!188 ]189 190 class Model(BaseModel):191 a: MyInt192 193 print(Model(a='1').a)194 #> 2195 196 print(Model(a=1).a)197 #> 2198 ```199 200 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema201 generator that in validation mode, the input type for the `a` field can be either a [`str`][] or an [`int`][].202 """203 204 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction205 json_schema_input_type: Any = Any206 207 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:208 # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the209 # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper210 # serialization schema. To work around this for use cases that will not involve serialization, we simply211 # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema212 # and abort any attempts to handle special serialization.213 from pydantic import PydanticSchemaGenerationError214 215 try:216 schema = handler(source_type)217 # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence',218 # schema validation will fail. That's why we use 'type ignore' comments below.219 serialization = schema.get(220 'serialization',221 core_schema.wrap_serializer_function_ser_schema(222 function=lambda v, h: h(v),223 schema=schema,224 return_schema=handler.generate_schema(source_type),225 ),226 )227 except PydanticSchemaGenerationError:228 serialization = None229 230 input_schema = handler.generate_schema(self.json_schema_input_type)231 232 info_arg = _inspect_validator(self.func, mode='plain', type='field')233 if info_arg:234 func = cast(core_schema.WithInfoValidatorFunction, self.func)235 return core_schema.with_info_plain_validator_function(236 func,237 serialization=serialization, # pyright: ignore[reportArgumentType]238 json_schema_input_schema=input_schema,239 )240 else:241 func = cast(core_schema.NoInfoValidatorFunction, self.func)242 return core_schema.no_info_plain_validator_function(243 func,244 serialization=serialization, # pyright: ignore[reportArgumentType]245 json_schema_input_schema=input_schema,246 )247 248 @classmethod249 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:250 return cls(251 func=decorator.func,252 json_schema_input_type=decorator.info.json_schema_input_type,253 )254 255 256@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true)257class WrapValidator:258 """!!! abstract "Usage Documentation"259 [field *wrap* validators](../concepts/validators.md#field-wrap-validator)260 261 A metadata class that indicates that a validation should be applied **around** the inner validation logic.262 263 Attributes:264 func: The validator function.265 json_schema_input_type: The input type used to generate the appropriate266 JSON Schema (in validation mode). The actual input type is `Any`.267 268 ```python269 from datetime import datetime270 from typing import Annotated271 272 from pydantic import BaseModel, ValidationError, WrapValidator273 274 def validate_timestamp(v, handler):275 if v == 'now':276 # we don't want to bother with further validation, just return the new value277 return datetime.now()278 try:279 return handler(v)280 except ValidationError:281 # validation failed, in this case we want to return a default value282 return datetime(2000, 1, 1)283 284 MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)]285 286 class Model(BaseModel):287 a: MyTimestamp288 289 print(Model(a='now').a)290 #> 2032-01-02 03:04:05.000006291 print(Model(a='invalid').a)292 #> 2000-01-01 00:00:00293 ```294 """295 296 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction297 json_schema_input_type: Any = PydanticUndefined298 299 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:300 schema = handler(source_type)301 input_schema = (302 None303 if self.json_schema_input_type is PydanticUndefined304 else handler.generate_schema(self.json_schema_input_type)305 )306 307 info_arg = _inspect_validator(self.func, mode='wrap', type='field')308 if info_arg:309 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func)310 return core_schema.with_info_wrap_validator_function(311 func,312 schema=schema,313 json_schema_input_schema=input_schema,314 )315 else:316 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func)317 return core_schema.no_info_wrap_validator_function(318 func,319 schema=schema,320 json_schema_input_schema=input_schema,321 )322 323 @classmethod324 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self:325 return cls(326 func=decorator.func,327 json_schema_input_type=decorator.info.json_schema_input_type,328 )329 330 331if TYPE_CHECKING:332 333 class _OnlyValueValidatorClsMethod(Protocol):334 def __call__(self, cls: Any, value: Any, /) -> Any: ...335 336 class _V2ValidatorClsMethod(Protocol):337 def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo[Any], /) -> Any: ...338 339 class _OnlyValueWrapValidatorClsMethod(Protocol):340 def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ...341 342 class _V2WrapValidatorClsMethod(Protocol):343 def __call__(344 self,345 cls: Any,346 value: Any,347 handler: core_schema.ValidatorFunctionWrapHandler,348 info: core_schema.ValidationInfo[Any],349 /,350 ) -> Any: ...351 352 _V2Validator = Union[353 _V2ValidatorClsMethod,354 core_schema.WithInfoValidatorFunction,355 _OnlyValueValidatorClsMethod,356 core_schema.NoInfoValidatorFunction,357 ]358 359 _V2WrapValidator = Union[360 _V2WrapValidatorClsMethod,361 core_schema.WithInfoWrapValidatorFunction,362 _OnlyValueWrapValidatorClsMethod,363 core_schema.NoInfoWrapValidatorFunction,364 ]365 366 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]367 368 _V2BeforeAfterOrPlainValidatorType = TypeVar(369 '_V2BeforeAfterOrPlainValidatorType',370 bound=Union[_V2Validator, _PartialClsOrStaticMethod],371 )372 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod])373 374FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain']375 376 377@overload378def field_validator(379 field: str,380 /,381 *fields: str,382 mode: Literal['wrap'],383 check_fields: bool | None = ...,384 json_schema_input_type: Any = ...,385) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ...386 387 388@overload389def field_validator(390 field: str,391 /,392 *fields: str,393 mode: Literal['before', 'plain'],394 check_fields: bool | None = ...,395 json_schema_input_type: Any = ...,396) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ...397 398 399@overload400def field_validator(401 field: str,402 /,403 *fields: str,404 mode: Literal['after'] = ...,405 check_fields: bool | None = ...,406) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ...407 408 409def field_validator( # noqa: D417410 field: str,411 /,412 *fields: str,413 mode: FieldValidatorModes = 'after',414 check_fields: bool | None = None,415 json_schema_input_type: Any = PydanticUndefined,416) -> Callable[[Any], Any]:417 """!!! abstract "Usage Documentation"418 [field validators](../concepts/validators.md#field-validators)419 420 Decorate methods on the class indicating that they should be used to validate fields.421 422 Example usage:423 ```python424 from typing import Any425 426 from pydantic import (427 BaseModel,428 ValidationError,429 field_validator,430 )431 432 class Model(BaseModel):433 a: str434 435 @field_validator('a')436 @classmethod437 def ensure_foobar(cls, v: Any):438 if 'foobar' not in v:439 raise ValueError('"foobar" not found in a')440 return v441 442 print(repr(Model(a='this is foobar good')))443 #> Model(a='this is foobar good')444 445 try:446 Model(a='snap')447 except ValidationError as exc_info:448 print(exc_info)449 '''450 1 validation error for Model451 a452 Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str]453 '''454 ```455 456 For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators).457 458 Args:459 *fields: The field names the validator should apply to.460 mode: Specifies whether to validate the fields before or after validation.461 check_fields: Whether to check that the fields actually exist on the model.462 json_schema_input_type: The input type of the function. This is only used to generate463 the appropriate JSON Schema (in validation mode) and can only specified464 when `mode` is either `'before'`, `'plain'` or `'wrap'`.465 466 Raises:467 PydanticUserError:468 - If the decorator is used without any arguments (at least one field name must be provided).469 - If the provided field names are not strings.470 - If `json_schema_input_type` is provided with an unsupported `mode`.471 - If the decorator is applied to an instance method.472 """473 if callable(field) or isinstance(field, classmethod):474 raise PydanticUserError(475 'The `@field_validator` decorator cannot be used without arguments, at least one field must be provided. '476 "For example: `@field_validator('<field_name>', ...)`.",477 code='decorator-missing-arguments',478 )479 480 if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined:481 raise PydanticUserError(482 f"`json_schema_input_type` can't be used when mode is set to {mode!r}",483 code='validator-input-type',484 )485 486 if json_schema_input_type is PydanticUndefined and mode == 'plain':487 json_schema_input_type = Any488 489 fields = field, *fields490 if not all(isinstance(field, str) for field in fields):491 raise PydanticUserError(492 'The provided field names to the `@field_validator` decorator should be strings. '493 "For example: `@field_validator('<field_name_1>', '<field_name_2>', ...).`",494 code='decorator-invalid-fields',495 )496 497 def dec(498 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any],499 ) -> _decorators.PydanticDescriptorProxy[Any]:500 if _decorators.is_instance_method_from_sig(f):501 raise PydanticUserError(502 'The `@field_validator` decorator cannot be applied to instance methods',503 code='validator-instance-method',504 )505 506 # auto apply the @classmethod decorator507 f = _decorators.ensure_classmethod_based_on_signature(f)508 509 dec_info = _decorators.FieldValidatorDecoratorInfo(510 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type511 )512 return _decorators.PydanticDescriptorProxy(f, dec_info)513 514 return dec515 516 517_ModelType = TypeVar('_ModelType')518_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True)519 520 521class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]):522 """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`."""523 524 def __call__( # noqa: D102525 self,526 value: Any,527 outer_location: str | int | None = None,528 /,529 ) -> _ModelTypeCo: # pragma: no cover530 ...531 532 533class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]):534 """A `@model_validator` decorated function signature.535 This is used when `mode='wrap'` and the function does not have info argument.536 """537 538 def __call__( # noqa: D102539 self,540 cls: type[_ModelType],541 # this can be a dict, a model instance542 # or anything else that gets passed to validate_python543 # thus validators _must_ handle all cases544 value: Any,545 handler: ModelWrapValidatorHandler[_ModelType],546 /,547 ) -> _ModelType: ...548 549 550class ModelWrapValidator(Protocol[_ModelType]):551 """A `@model_validator` decorated function signature. This is used when `mode='wrap'`."""552 553 def __call__( # noqa: D102554 self,555 cls: type[_ModelType],556 # this can be a dict, a model instance557 # or anything else that gets passed to validate_python558 # thus validators _must_ handle all cases559 value: Any,560 handler: ModelWrapValidatorHandler[_ModelType],561 info: core_schema.ValidationInfo,562 /,563 ) -> _ModelType: ...564 565 566class FreeModelBeforeValidatorWithoutInfo(Protocol):567 """A `@model_validator` decorated function signature.568 This is used when `mode='before'` and the function does not have info argument.569 """570 571 def __call__( # noqa: D102572 self,573 # this can be a dict, a model instance574 # or anything else that gets passed to validate_python575 # thus validators _must_ handle all cases576 value: Any,577 /,578 ) -> Any: ...579 580 581class ModelBeforeValidatorWithoutInfo(Protocol):582 """A `@model_validator` decorated function signature.583 This is used when `mode='before'` and the function does not have info argument.584 """585 586 def __call__( # noqa: D102587 self,588 cls: Any,589 # this can be a dict, a model instance590 # or anything else that gets passed to validate_python591 # thus validators _must_ handle all cases592 value: Any,593 /,594 ) -> Any: ...595 596 597class FreeModelBeforeValidator(Protocol):598 """A `@model_validator` decorated function signature. This is used when `mode='before'`."""599 600 def __call__( # noqa: D102601 self,602 # this can be a dict, a model instance603 # or anything else that gets passed to validate_python604 # thus validators _must_ handle all cases605 value: Any,606 info: core_schema.ValidationInfo[Any],607 /,608 ) -> Any: ...609 610 611class ModelBeforeValidator(Protocol):612 """A `@model_validator` decorated function signature. This is used when `mode='before'`."""613 614 def __call__( # noqa: D102615 self,616 cls: Any,617 # this can be a dict, a model instance618 # or anything else that gets passed to validate_python619 # thus validators _must_ handle all cases620 value: Any,621 info: core_schema.ValidationInfo[Any],622 /,623 ) -> Any: ...624 625 626ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType]627"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not628have info argument.629"""630 631ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType]632"""A `@model_validator` decorated function signature. This is used when `mode='after'`."""633 634_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]]635_AnyModelBeforeValidator = Union[636 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo637]638_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]]639 640 641@overload642def model_validator(643 *,644 mode: Literal['wrap'],645) -> Callable[646 [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]647]: ...648 649 650@overload651def model_validator(652 *,653 mode: Literal['before'],654) -> Callable[655 [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]656]: ...657 658 659@overload660def model_validator(661 *,662 mode: Literal['after'],663) -> Callable[664 [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]665]: ...666 667 668def model_validator(669 *,670 mode: Literal['wrap', 'before', 'after'],671) -> Any:672 """!!! abstract "Usage Documentation"673 [Model Validators](../concepts/validators.md#model-validators)674 675 Decorate model methods for validation purposes.676 677 Example usage:678 ```python679 from typing_extensions import Self680 681 from pydantic import BaseModel, ValidationError, model_validator682 683 class Square(BaseModel):684 width: float685 height: float686 687 @model_validator(mode='after')688 def verify_square(self) -> Self:689 if self.width != self.height:690 raise ValueError('width and height do not match')691 return self692 693 s = Square(width=1, height=1)694 print(repr(s))695 #> Square(width=1.0, height=1.0)696 697 try:698 Square(width=1, height=2)699 except ValidationError as e:700 print(e)701 '''702 1 validation error for Square703 Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict]704 '''705 ```706 707 For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators).708 709 Args:710 mode: A required string literal that specifies the validation mode.711 It can be one of the following: 'wrap', 'before', or 'after'.712 713 Returns:714 A decorator that can be used to decorate a function to be used as a model validator.715 """716 717 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]:718 # auto apply the @classmethod decorator. NOTE: in V3, do not apply the conversion for 'after' validators:719 f = _decorators.ensure_classmethod_based_on_signature(f)720 if mode == 'after' and isinstance(f, classmethod):721 warnings.warn(722 category=PydanticDeprecatedSince212,723 message=(724 "Using `@model_validator` with mode='after' on a classmethod is deprecated. Instead, use an instance method. "725 f'See the documentation at https://docs.pydantic.dev/{version_short()}/concepts/validators/#model-after-validator.'726 ),727 stacklevel=2,728 )729 730 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode)731 return _decorators.PydanticDescriptorProxy(f, dec_info)732 733 return dec734 735 736AnyType = TypeVar('AnyType')737 738 739if TYPE_CHECKING:740 # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this741 InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence`742 743else:744 745 @dataclasses.dataclass(**_internal_dataclass.slots_true)746 class InstanceOf:747 '''Generic type for annotating a type that is an instance of a given class.748 749 Example:750 ```python751 from pydantic import BaseModel, InstanceOf752 753 class Foo:754 ...755 756 class Bar(BaseModel):757 foo: InstanceOf[Foo]758 759 Bar(foo=Foo())760 try:761 Bar(foo=42)762 except ValidationError as e:763 print(e)764 """765 [766 │ {767 │ │ 'type': 'is_instance_of',768 │ │ 'loc': ('foo',),769 │ │ 'msg': 'Input should be an instance of Foo',770 │ │ 'input': 42,771 │ │ 'ctx': {'class': 'Foo'},772 │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of'773 │ }774 ]775 """776 ```777 '''778 779 @classmethod780 def __class_getitem__(cls, item: AnyType) -> AnyType:781 return Annotated[item, cls()]782 783 @classmethod784 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:785 from pydantic._internal._generate_schema import GENERATE_SCHEMA_ERRORS786 787 # use the generic _origin_ as the second argument to isinstance when appropriate788 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source)789 790 try:791 # Try to generate the "standard" schema, which will be used when loading from JSON792 original_schema = handler(source)793 except GENERATE_SCHEMA_ERRORS:794 # If that fails, just produce a schema that can validate from python795 return instance_of_schema796 else:797 # Use the "original" approach to serialization798 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema(799 function=lambda v, h: h(v), schema=original_schema800 )801 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema)802 803 __hash__ = object.__hash__804 805 806if TYPE_CHECKING:807 SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str]808else:809 810 @dataclasses.dataclass(**_internal_dataclass.slots_true)811 class SkipValidation:812 """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be813 skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`.814 815 This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes,816 and know that it is safe to skip validation for one or more of the fields.817 818 Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations819 may not have the expected effects. Therefore, when used, this annotation should generally be the final820 annotation applied to a type.821 """822 823 def __class_getitem__(cls, item: Any) -> Any:824 return Annotated[item, SkipValidation()]825 826 @classmethod827 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:828 with warnings.catch_warnings():829 warnings.simplefilter('ignore', ArbitraryTypeWarning)830 original_schema = handler(source)831 metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]}832 return core_schema.any_schema(833 metadata=metadata,834 serialization=core_schema.wrap_serializer_function_ser_schema(835 function=lambda v, h: h(v), schema=original_schema836 ),837 )838 839 __hash__ = object.__hash__840 841 842_FromTypeT = TypeVar('_FromTypeT')843 844 845class ValidateAs:846 """A helper class to validate a custom type from a type that is natively supported by Pydantic.847 848 Args:849 from_type: The type natively supported by Pydantic to use to perform validation.850 instantiation_hook: A callable taking the validated type as an argument, and returning851 the populated custom type.852 853 Example:854 ```python {lint="skip"}855 from typing import Annotated856 857 from pydantic import BaseModel, TypeAdapter, ValidateAs858 859 class MyCls:860 def __init__(self, a: int) -> None:861 self.a = a862 863 def __repr__(self) -> str:864 return f"MyCls(a={self.a})"865 866 class Model(BaseModel):867 a: int868 869 870 ta = TypeAdapter(871 Annotated[MyCls, ValidateAs(Model, lambda v: MyCls(a=v.a))]872 )873 874 print(ta.validate_python({'a': 1}))875 #> MyCls(a=1)876 ```877 """878 879 # TODO: make use of PEP 747880 def __init__(self, from_type: type[_FromTypeT], /, instantiation_hook: Callable[[_FromTypeT], Any]) -> None:881 self.from_type = from_type882 self.instantiation_hook = instantiation_hook883 884 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:885 schema = handler(self.from_type)886 return core_schema.no_info_after_validator_function(887 self.instantiation_hook,888 schema=schema,889 )890 