Coverage for pydantic/functional_validators.py: 98.83%
147 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-04 10:05 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-04 10:05 +0000
1"""This module contains related classes and functions for validation."""
3from __future__ import annotations as _annotations 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
5import dataclasses 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
6import sys 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
7from functools import partialmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
8from types import FunctionType 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
9from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
11from pydantic_core import PydanticUndefined, core_schema 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
12from typing_extensions import Self, TypeAlias 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
14from ._internal import _decorators, _generics, _internal_dataclass 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
15from .annotated_handlers import GetCoreSchemaHandler 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
16from .errors import PydanticUserError 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
18if sys.version_info < (3, 11): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
19 from typing_extensions import Protocol 1DErsqpFGvwHIzA
20else:
21 from typing import Protocol 1tuabcdexyfghijJBCklmno
23_inspect_validator = _decorators.inspect_validator 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
26@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
27class AfterValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
28 """!!! abstract "Usage Documentation"
29 [field *after* validators](../concepts/validators.md#field-after-validator)
31 A metadata class that indicates that a validation should be applied **after** the inner validation logic.
33 Attributes:
34 func: The validator function.
36 Example:
37 ```python
38 from typing import Annotated
40 from pydantic import AfterValidator, BaseModel, ValidationError
42 MyInt = Annotated[int, AfterValidator(lambda v: v + 1)]
44 class Model(BaseModel):
45 a: MyInt
47 print(Model(a=1).a)
48 #> 2
50 try:
51 Model(a='a')
52 except ValidationError as e:
53 print(e.json(indent=2))
54 '''
55 [
56 {
57 "type": "int_parsing",
58 "loc": [
59 "a"
60 ],
61 "msg": "Input should be a valid integer, unable to parse string as an integer",
62 "input": "a",
63 "url": "https://errors.pydantic.dev/2/v/int_parsing"
64 }
65 ]
66 '''
67 ```
68 """
70 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
72 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
73 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
74 info_arg = _inspect_validator(self.func, 'after') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
75 if info_arg: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
76 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
77 return core_schema.with_info_after_validator_function(func, schema=schema) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
78 else:
79 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
80 return core_schema.no_info_after_validator_function(func, schema=schema) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
82 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
83 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
84 return cls(func=decorator.func) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
87@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
88class BeforeValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
89 """!!! abstract "Usage Documentation"
90 [field *before* validators](../concepts/validators.md#field-before-validator)
92 A metadata class that indicates that a validation should be applied **before** the inner validation logic.
94 Attributes:
95 func: The validator function.
96 json_schema_input_type: The input type used to generate the appropriate
97 JSON Schema (in validation mode). The actual input type is `Any`.
99 Example:
100 ```python
101 from typing import Annotated
103 from pydantic import BaseModel, BeforeValidator
105 MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)]
107 class Model(BaseModel):
108 a: MyInt
110 print(Model(a=1).a)
111 #> 2
113 try:
114 Model(a='a')
115 except TypeError as e:
116 print(e)
117 #> can only concatenate str (not "int") to str
118 ```
119 """
121 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
122 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
124 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
125 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
126 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
127 None
128 if self.json_schema_input_type is PydanticUndefined
129 else handler.generate_schema(self.json_schema_input_type)
130 )
132 info_arg = _inspect_validator(self.func, 'before') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
133 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
134 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
135 return core_schema.with_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
136 func,
137 schema=schema,
138 json_schema_input_schema=input_schema,
139 )
140 else:
141 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
142 return core_schema.no_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
143 func, schema=schema, json_schema_input_schema=input_schema
144 )
146 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
147 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
148 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
149 func=decorator.func,
150 json_schema_input_type=decorator.info.json_schema_input_type,
151 )
154@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
155class PlainValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
156 """!!! abstract "Usage Documentation"
157 [field *plain* validators](../concepts/validators.md#field-plain-validator)
159 A metadata class that indicates that a validation should be applied **instead** of the inner validation logic.
161 !!! note
162 Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`.
163 You can now use the `json_schema_input_type` argument to specify the input type of the function
164 to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details.
166 Attributes:
167 func: The validator function.
168 json_schema_input_type: The input type used to generate the appropriate
169 JSON Schema (in validation mode). The actual input type is `Any`.
171 Example:
172 ```python
173 from typing import Annotated, Union
175 from pydantic import BaseModel, PlainValidator
177 MyInt = Annotated[
178 int,
179 PlainValidator(
180 lambda v: int(v) + 1, json_schema_input_type=Union[str, int] # (1)!
181 ),
182 ]
184 class Model(BaseModel):
185 a: MyInt
187 print(Model(a='1').a)
188 #> 2
190 print(Model(a=1).a)
191 #> 2
192 ```
194 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema
195 generator that in validation mode, the input type for the `a` field can be either a `str` or an `int`.
196 """
198 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
199 json_schema_input_type: Any = Any 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
201 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
202 # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the
203 # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper
204 # serialization schema. To work around this for use cases that will not involve serialization, we simply
205 # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema
206 # and abort any attempts to handle special serialization.
207 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
209 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
210 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
211 # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence',
212 # schema validation will fail. That's why we use 'type ignore' comments below.
213 serialization = schema.get( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
214 'serialization',
215 core_schema.wrap_serializer_function_ser_schema(
216 function=lambda v, h: h(v),
217 schema=schema,
218 return_schema=handler.generate_schema(source_type),
219 ),
220 )
221 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
222 serialization = None 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
224 input_schema = handler.generate_schema(self.json_schema_input_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
226 info_arg = _inspect_validator(self.func, 'plain') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
227 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
228 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
229 return core_schema.with_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
230 func,
231 serialization=serialization, # pyright: ignore[reportArgumentType]
232 json_schema_input_schema=input_schema,
233 )
234 else:
235 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
236 return core_schema.no_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
237 func,
238 serialization=serialization, # pyright: ignore[reportArgumentType]
239 json_schema_input_schema=input_schema,
240 )
242 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
243 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
244 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
245 func=decorator.func,
246 json_schema_input_type=decorator.info.json_schema_input_type,
247 )
250@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
251class WrapValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
252 """!!! abstract "Usage Documentation"
253 [field *wrap* validators](../concepts/validators.md#field-wrap-validator)
255 A metadata class that indicates that a validation should be applied **around** the inner validation logic.
257 Attributes:
258 func: The validator function.
259 json_schema_input_type: The input type used to generate the appropriate
260 JSON Schema (in validation mode). The actual input type is `Any`.
262 ```python
263 from datetime import datetime
264 from typing import Annotated
266 from pydantic import BaseModel, ValidationError, WrapValidator
268 def validate_timestamp(v, handler):
269 if v == 'now':
270 # we don't want to bother with further validation, just return the new value
271 return datetime.now()
272 try:
273 return handler(v)
274 except ValidationError:
275 # validation failed, in this case we want to return a default value
276 return datetime(2000, 1, 1)
278 MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)]
280 class Model(BaseModel):
281 a: MyTimestamp
283 print(Model(a='now').a)
284 #> 2032-01-02 03:04:05.000006
285 print(Model(a='invalid').a)
286 #> 2000-01-01 00:00:00
287 ```
288 """
290 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
291 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
293 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
294 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
295 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
296 None
297 if self.json_schema_input_type is PydanticUndefined
298 else handler.generate_schema(self.json_schema_input_type)
299 )
301 info_arg = _inspect_validator(self.func, 'wrap') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
302 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
303 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
304 return core_schema.with_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
305 func,
306 schema=schema,
307 json_schema_input_schema=input_schema,
308 )
309 else:
310 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
311 return core_schema.no_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
312 func,
313 schema=schema,
314 json_schema_input_schema=input_schema,
315 )
317 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
318 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
319 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
320 func=decorator.func,
321 json_schema_input_type=decorator.info.json_schema_input_type,
322 )
325if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
327 class _OnlyValueValidatorClsMethod(Protocol):
328 def __call__(self, cls: Any, value: Any, /) -> Any: ...
330 class _V2ValidatorClsMethod(Protocol):
331 def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo, /) -> Any: ...
333 class _OnlyValueWrapValidatorClsMethod(Protocol):
334 def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ...
336 class _V2WrapValidatorClsMethod(Protocol):
337 def __call__(
338 self,
339 cls: Any,
340 value: Any,
341 handler: core_schema.ValidatorFunctionWrapHandler,
342 info: core_schema.ValidationInfo,
343 /,
344 ) -> Any: ...
346 _V2Validator = Union[
347 _V2ValidatorClsMethod,
348 core_schema.WithInfoValidatorFunction,
349 _OnlyValueValidatorClsMethod,
350 core_schema.NoInfoValidatorFunction,
351 ]
353 _V2WrapValidator = Union[
354 _V2WrapValidatorClsMethod,
355 core_schema.WithInfoWrapValidatorFunction,
356 _OnlyValueWrapValidatorClsMethod,
357 core_schema.NoInfoWrapValidatorFunction,
358 ]
360 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
362 _V2BeforeAfterOrPlainValidatorType = TypeVar(
363 '_V2BeforeAfterOrPlainValidatorType',
364 bound=Union[_V2Validator, _PartialClsOrStaticMethod],
365 )
366 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod])
368FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
371@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
372def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
373 field: str, 1abcdeqpfghijJklmno
374 /,
375 *fields: str, 1abcdeqpfghijJklmno
376 mode: Literal['wrap'], 1abcdeqpfghijJklmno
377 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
378 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
379) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 1abcdeqpfghijJklmno
382@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
383def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
384 field: str, 1abcdeqpfghijJklmno
385 /,
386 *fields: str, 1abcdeqpfghijJklmno
387 mode: Literal['before', 'plain'], 1abcdeqpfghijJklmno
388 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
389 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
390) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdeqpfghijJklmno
393@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
394def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
395 field: str, 1abcdeqpfghijJklmno
396 /,
397 *fields: str, 1abcdeqpfghijJklmno
398 mode: Literal['after'] = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
399 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
400) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdeqpfghijJklmno
403def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
404 field: str,
405 /,
406 *fields: str,
407 mode: FieldValidatorModes = 'after',
408 check_fields: bool | None = None,
409 json_schema_input_type: Any = PydanticUndefined,
410) -> Callable[[Any], Any]:
411 """!!! abstract "Usage Documentation"
412 [field validators](../concepts/validators.md#field-validators)
414 Decorate methods on the class indicating that they should be used to validate fields.
416 Example usage:
417 ```python
418 from typing import Any
420 from pydantic import (
421 BaseModel,
422 ValidationError,
423 field_validator,
424 )
426 class Model(BaseModel):
427 a: str
429 @field_validator('a')
430 @classmethod
431 def ensure_foobar(cls, v: Any):
432 if 'foobar' not in v:
433 raise ValueError('"foobar" not found in a')
434 return v
436 print(repr(Model(a='this is foobar good')))
437 #> Model(a='this is foobar good')
439 try:
440 Model(a='snap')
441 except ValidationError as exc_info:
442 print(exc_info)
443 '''
444 1 validation error for Model
445 a
446 Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str]
447 '''
448 ```
450 For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators).
452 Args:
453 field: The first field the `field_validator` should be called on; this is separate
454 from `fields` to ensure an error is raised if you don't pass at least one.
455 *fields: Additional field(s) the `field_validator` should be called on.
456 mode: Specifies whether to validate the fields before or after validation.
457 check_fields: Whether to check that the fields actually exist on the model.
458 json_schema_input_type: The input type of the function. This is only used to generate
459 the appropriate JSON Schema (in validation mode) and can only specified
460 when `mode` is either `'before'`, `'plain'` or `'wrap'`.
462 Returns:
463 A decorator that can be used to decorate a function to be used as a field_validator.
465 Raises:
466 PydanticUserError:
467 - If `@field_validator` is used bare (with no fields).
468 - If the args passed to `@field_validator` as fields are not strings.
469 - If `@field_validator` applied to instance methods.
470 """
471 if isinstance(field, FunctionType): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
472 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
473 '`@field_validator` should be used with fields and keyword arguments, not bare. '
474 "E.g. usage should be `@validator('<field_name>', ...)`",
475 code='validator-no-fields',
476 )
478 if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
479 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
480 f"`json_schema_input_type` can't be used when mode is set to {mode!r}",
481 code='validator-input-type',
482 )
484 if json_schema_input_type is PydanticUndefined and mode == 'plain': 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
485 json_schema_input_type = Any 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
487 fields = field, *fields 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
488 if not all(isinstance(field, str) for field in fields): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
489 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
490 '`@field_validator` fields should be passed as separate string args. '
491 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
492 code='validator-invalid-fields',
493 )
495 def dec( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
496 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any],
497 ) -> _decorators.PydanticDescriptorProxy[Any]:
498 if _decorators.is_instance_method_from_sig(f): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
499 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
500 '`@field_validator` cannot be applied to instance methods', code='validator-instance-method'
501 )
503 # auto apply the @classmethod decorator
504 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
506 dec_info = _decorators.FieldValidatorDecoratorInfo( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
507 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type
508 )
509 return _decorators.PydanticDescriptorProxy(f, dec_info) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
511 return dec 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
514_ModelType = TypeVar('_ModelType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
515_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
518class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
519 """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`."""
521 def __call__( # noqa: D102 1DErstuabcdeFGvwxyfghijJHIzABCklmno
522 self,
523 value: Any, 1abcdeqpfghijJklmno
524 outer_location: str | int | None = None, 1rstuabcdeqpvwxyfghijJzABCklmno
525 /,
526 ) -> _ModelTypeCo: # pragma: no cover 1abcdeqpfghijJklmno
527 ...
530class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
531 """A `@model_validator` decorated function signature.
532 This is used when `mode='wrap'` and the function does not have info argument.
533 """
535 def __call__( # noqa: D102 535 ↛ exitline 535 didn't return from function '__call__' because 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
536 self,
537 cls: type[_ModelType],
538 # this can be a dict, a model instance
539 # or anything else that gets passed to validate_python
540 # thus validators _must_ handle all cases
541 value: Any,
542 handler: ModelWrapValidatorHandler[_ModelType],
543 /,
544 ) -> _ModelType: ...
547class ModelWrapValidator(Protocol[_ModelType]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
548 """A `@model_validator` decorated function signature. This is used when `mode='wrap'`."""
550 def __call__( # noqa: D102 550 ↛ exitline 550 didn't return from function '__call__' because 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
551 self,
552 cls: type[_ModelType],
553 # this can be a dict, a model instance
554 # or anything else that gets passed to validate_python
555 # thus validators _must_ handle all cases
556 value: Any,
557 handler: ModelWrapValidatorHandler[_ModelType],
558 info: core_schema.ValidationInfo,
559 /,
560 ) -> _ModelType: ...
563class FreeModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
564 """A `@model_validator` decorated function signature. 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
565 This is used when `mode='before'` and the function does not have info argument.
566 """
568 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
569 self,
570 # this can be a dict, a model instance
571 # or anything else that gets passed to validate_python
572 # thus validators _must_ handle all cases
573 value: Any, 1abcdeqpfghijJklmno
574 /,
575 ) -> Any: ... 1abcdeqpfghijJklmno
578class ModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
579 """A `@model_validator` decorated function signature. 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
580 This is used when `mode='before'` and the function does not have info argument.
581 """
583 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
584 self,
585 cls: Any, 1abcdeqpfghijJklmno
586 # this can be a dict, a model instance
587 # or anything else that gets passed to validate_python
588 # thus validators _must_ handle all cases
589 value: Any, 1abcdeqpfghijJklmno
590 /,
591 ) -> Any: ... 1abcdeqpfghijJklmno
594class FreeModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
595 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
597 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
598 self,
599 # this can be a dict, a model instance
600 # or anything else that gets passed to validate_python
601 # thus validators _must_ handle all cases
602 value: Any, 1abcdeqpfghijJklmno
603 info: core_schema.ValidationInfo, 1abcdeqpfghijJklmno
604 /,
605 ) -> Any: ... 1abcdeqpfghijJklmno
608class ModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
609 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
611 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
612 self,
613 cls: Any, 1abcdeqpfghijJklmno
614 # this can be a dict, a model instance
615 # or anything else that gets passed to validate_python
616 # thus validators _must_ handle all cases
617 value: Any, 1abcdeqpfghijJklmno
618 info: core_schema.ValidationInfo, 1abcdeqpfghijJklmno
619 /,
620 ) -> Any: ... 1abcdeqpfghijJklmno
623ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
624"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not 1rstuabcdepvwxyfghijJzABCklmno
625have info argument.
626"""
628ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo], _ModelType] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
629"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" 1rstuabcdepvwxyfghijJzABCklmno
631_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
632_AnyModelBeforeValidator = Union[ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
633 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo
634]
635_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
638@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
639def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
640 *,
641 mode: Literal['wrap'], 1abcdeqpfghijJklmno
642) -> Callable[ 1abcdeqpfghijJklmno
643 [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
644]: ...
647@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
648def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
649 *,
650 mode: Literal['before'], 1abcdeqpfghijJklmno
651) -> Callable[ 1abcdeqpfghijJklmno
652 [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
653]: ...
656@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
657def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
658 *,
659 mode: Literal['after'], 1abcdeqpfghijJklmno
660) -> Callable[ 1abcdeqpfghijJklmno
661 [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
662]: ...
665def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
666 *,
667 mode: Literal['wrap', 'before', 'after'],
668) -> Any:
669 """!!! abstract "Usage Documentation"
670 [Model Validators](../concepts/validators.md#model-validators)
672 Decorate model methods for validation purposes.
674 Example usage:
675 ```python
676 from typing_extensions import Self
678 from pydantic import BaseModel, ValidationError, model_validator
680 class Square(BaseModel):
681 width: float
682 height: float
684 @model_validator(mode='after')
685 def verify_square(self) -> Self:
686 if self.width != self.height:
687 raise ValueError('width and height do not match')
688 return self
690 s = Square(width=1, height=1)
691 print(repr(s))
692 #> Square(width=1.0, height=1.0)
694 try:
695 Square(width=1, height=2)
696 except ValidationError as e:
697 print(e)
698 '''
699 1 validation error for Square
700 Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict]
701 '''
702 ```
704 For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators).
706 Args:
707 mode: A required string literal that specifies the validation mode.
708 It can be one of the following: 'wrap', 'before', or 'after'.
710 Returns:
711 A decorator that can be used to decorate a function to be used as a model validator.
712 """
714 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
715 # auto apply the @classmethod decorator
716 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
717 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
718 return _decorators.PydanticDescriptorProxy(f, dec_info) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
720 return dec 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
723AnyType = TypeVar('AnyType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
726if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
727 # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this
728 InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence`
730else:
732 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
733 class InstanceOf: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
734 '''Generic type for annotating a type that is an instance of a given class.
736 Example:
737 ```python
738 from pydantic import BaseModel, InstanceOf
740 class Foo:
741 ...
743 class Bar(BaseModel):
744 foo: InstanceOf[Foo]
746 Bar(foo=Foo())
747 try:
748 Bar(foo=42)
749 except ValidationError as e:
750 print(e)
751 """
752 [
753 │ {
754 │ │ 'type': 'is_instance_of',
755 │ │ 'loc': ('foo',),
756 │ │ 'msg': 'Input should be an instance of Foo',
757 │ │ 'input': 42,
758 │ │ 'ctx': {'class': 'Foo'},
759 │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of'
760 │ }
761 ]
762 """
763 ```
764 '''
766 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
767 def __class_getitem__(cls, item: AnyType) -> AnyType: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
768 return Annotated[item, cls()] 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
770 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
771 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
772 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
774 # use the generic _origin_ as the second argument to isinstance when appropriate
775 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
777 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
778 # Try to generate the "standard" schema, which will be used when loading from JSON
779 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
780 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
781 # If that fails, just produce a schema that can validate from python
782 return instance_of_schema 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
783 else:
784 # Use the "original" approach to serialization
785 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
786 function=lambda v, h: h(v), schema=original_schema
787 )
788 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
790 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
793if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
794 SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str]
795else:
797 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
798 class SkipValidation: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
799 """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be
800 skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`.
802 This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes,
803 and know that it is safe to skip validation for one or more of the fields.
805 Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations
806 may not have the expected effects. Therefore, when used, this annotation should generally be the final
807 annotation applied to a type.
808 """
810 def __class_getitem__(cls, item: Any) -> Any: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
811 return Annotated[item, SkipValidation()] 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
813 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
814 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno
815 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
816 metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
817 return core_schema.any_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
818 metadata=metadata,
819 serialization=core_schema.wrap_serializer_function_ser_schema(
820 function=lambda v, h: h(v), schema=original_schema
821 ),
822 )
824 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno