Coverage for pydantic/functional_validators.py: 98.88%
152 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-20 16:49 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-20 16:49 +0000
1"""This module contains related classes and functions for validation."""
3from __future__ import annotations as _annotations 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
5import dataclasses 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
6import sys 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
7import warnings 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
8from functools import partialmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
9from types import FunctionType 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
10from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
12from pydantic_core import PydanticUndefined, core_schema 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
13from typing_extensions import Self, TypeAlias 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
15from ._internal import _decorators, _generics, _internal_dataclass 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
16from .annotated_handlers import GetCoreSchemaHandler 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
17from .errors import PydanticUserError 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
18from .warnings import ArbitraryTypeWarning 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
20if sys.version_info < (3, 11): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
21 from typing_extensions import Protocol 1GHopnmIJstKLwx
22else:
23 from typing import Protocol 1qrabcdABMuvefghCDNPyzijklEFO
25_inspect_validator = _decorators.inspect_validator 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
28@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
29class AfterValidator: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
30 """!!! abstract "Usage Documentation"
31 [field *after* validators](../concepts/validators.md#field-after-validator)
33 A metadata class that indicates that a validation should be applied **after** the inner validation logic.
35 Attributes:
36 func: The validator function.
38 Example:
39 ```python
40 from typing import Annotated
42 from pydantic import AfterValidator, BaseModel, ValidationError
44 MyInt = Annotated[int, AfterValidator(lambda v: v + 1)]
46 class Model(BaseModel):
47 a: MyInt
49 print(Model(a=1).a)
50 #> 2
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 """
72 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
74 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
75 schema = handler(source_type) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
76 info_arg = _inspect_validator(self.func, 'after') 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
77 if info_arg: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
78 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
79 return core_schema.with_info_after_validator_function(func, schema=schema) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
80 else:
81 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
82 return core_schema.no_info_after_validator_function(func, schema=schema) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
84 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
85 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
86 return cls(func=decorator.func) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
89@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
90class BeforeValidator: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
91 """!!! abstract "Usage Documentation"
92 [field *before* validators](../concepts/validators.md#field-before-validator)
94 A metadata class that indicates that a validation should be applied **before** the inner validation logic.
96 Attributes:
97 func: The validator function.
98 json_schema_input_type: The input type used to generate the appropriate
99 JSON Schema (in validation mode). The actual input type is `Any`.
101 Example:
102 ```python
103 from typing import Annotated
105 from pydantic import BaseModel, BeforeValidator
107 MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)]
109 class Model(BaseModel):
110 a: MyInt
112 print(Model(a=1).a)
113 #> 2
115 try:
116 Model(a='a')
117 except TypeError as e:
118 print(e)
119 #> can only concatenate str (not "int") to str
120 ```
121 """
123 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
124 json_schema_input_type: Any = PydanticUndefined 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
126 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
127 schema = handler(source_type) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
128 input_schema = ( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
129 None
130 if self.json_schema_input_type is PydanticUndefined
131 else handler.generate_schema(self.json_schema_input_type)
132 )
134 info_arg = _inspect_validator(self.func, 'before') 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
135 if info_arg: 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
136 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
137 return core_schema.with_info_before_validator_function( 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
138 func,
139 schema=schema,
140 json_schema_input_schema=input_schema,
141 )
142 else:
143 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
144 return core_schema.no_info_before_validator_function( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
145 func, schema=schema, json_schema_input_schema=input_schema
146 )
148 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
149 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
150 return cls( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
151 func=decorator.func,
152 json_schema_input_type=decorator.info.json_schema_input_type,
153 )
156@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
157class PlainValidator: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
158 """!!! abstract "Usage Documentation"
159 [field *plain* validators](../concepts/validators.md#field-plain-validator)
161 A metadata class that indicates that a validation should be applied **instead** of the inner validation logic.
163 !!! note
164 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 function
166 to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details.
168 Attributes:
169 func: The validator function.
170 json_schema_input_type: The input type used to generate the appropriate
171 JSON Schema (in validation mode). The actual input type is `Any`.
173 Example:
174 ```python
175 from typing import Annotated, Union
177 from pydantic import BaseModel, PlainValidator
179 def validate(v: object) -> int:
180 if not isinstance(v, (int, str)):
181 raise ValueError(f'Expected int or str, go {type(v)}')
183 return int(v) + 1
185 MyInt = Annotated[
186 int,
187 PlainValidator(validate, json_schema_input_type=Union[str, int]), # (1)!
188 ]
190 class Model(BaseModel):
191 a: MyInt
193 print(Model(a='1').a)
194 #> 2
196 print(Model(a=1).a)
197 #> 2
198 ```
200 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema
201 generator that in validation mode, the input type for the `a` field can be either a [`str`][] or an [`int`][].
202 """
204 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
205 json_schema_input_type: Any = Any 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
207 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
208 # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the
209 # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper
210 # serialization schema. To work around this for use cases that will not involve serialization, we simply
211 # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema
212 # and abort any attempts to handle special serialization.
213 from pydantic import PydanticSchemaGenerationError 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
215 try: 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
216 schema = handler(source_type) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
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( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
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: 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
228 serialization = None 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
230 input_schema = handler.generate_schema(self.json_schema_input_type) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
232 info_arg = _inspect_validator(self.func, 'plain') 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
233 if info_arg: 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
234 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
235 return core_schema.with_info_plain_validator_function( 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
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) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
242 return core_schema.no_info_plain_validator_function( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
243 func,
244 serialization=serialization, # pyright: ignore[reportArgumentType]
245 json_schema_input_schema=input_schema,
246 )
248 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
249 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
250 return cls( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
251 func=decorator.func,
252 json_schema_input_type=decorator.info.json_schema_input_type,
253 )
256@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
257class WrapValidator: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
258 """!!! abstract "Usage Documentation"
259 [field *wrap* validators](../concepts/validators.md#field-wrap-validator)
261 A metadata class that indicates that a validation should be applied **around** the inner validation logic.
263 Attributes:
264 func: The validator function.
265 json_schema_input_type: The input type used to generate the appropriate
266 JSON Schema (in validation mode). The actual input type is `Any`.
268 ```python
269 from datetime import datetime
270 from typing import Annotated
272 from pydantic import BaseModel, ValidationError, WrapValidator
274 def validate_timestamp(v, handler):
275 if v == 'now':
276 # we don't want to bother with further validation, just return the new value
277 return datetime.now()
278 try:
279 return handler(v)
280 except ValidationError:
281 # validation failed, in this case we want to return a default value
282 return datetime(2000, 1, 1)
284 MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)]
286 class Model(BaseModel):
287 a: MyTimestamp
289 print(Model(a='now').a)
290 #> 2032-01-02 03:04:05.000006
291 print(Model(a='invalid').a)
292 #> 2000-01-01 00:00:00
293 ```
294 """
296 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
297 json_schema_input_type: Any = PydanticUndefined 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
299 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
300 schema = handler(source_type) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
301 input_schema = ( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
302 None
303 if self.json_schema_input_type is PydanticUndefined
304 else handler.generate_schema(self.json_schema_input_type)
305 )
307 info_arg = _inspect_validator(self.func, 'wrap') 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
308 if info_arg: 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
309 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
310 return core_schema.with_info_wrap_validator_function( 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
311 func,
312 schema=schema,
313 json_schema_input_schema=input_schema,
314 )
315 else:
316 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
317 return core_schema.no_info_wrap_validator_function( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
318 func,
319 schema=schema,
320 json_schema_input_schema=input_schema,
321 )
323 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
324 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
325 return cls( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
326 func=decorator.func,
327 json_schema_input_type=decorator.info.json_schema_input_type,
328 )
331if TYPE_CHECKING: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
333 class _OnlyValueValidatorClsMethod(Protocol):
334 def __call__(self, cls: Any, value: Any, /) -> Any: ...
336 class _V2ValidatorClsMethod(Protocol):
337 def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo[Any], /) -> Any: ...
339 class _OnlyValueWrapValidatorClsMethod(Protocol):
340 def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ...
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: ...
352 _V2Validator = Union[
353 _V2ValidatorClsMethod,
354 core_schema.WithInfoValidatorFunction,
355 _OnlyValueValidatorClsMethod,
356 core_schema.NoInfoValidatorFunction,
357 ]
359 _V2WrapValidator = Union[
360 _V2WrapValidatorClsMethod,
361 core_schema.WithInfoWrapValidatorFunction,
362 _OnlyValueWrapValidatorClsMethod,
363 core_schema.NoInfoWrapValidatorFunction,
364 ]
366 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
368 _V2BeforeAfterOrPlainValidatorType = TypeVar(
369 '_V2BeforeAfterOrPlainValidatorType',
370 bound=Union[_V2Validator, _PartialClsOrStaticMethod],
371 )
372 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod])
374FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
377@overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
378def field_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
379 field: str, 1abcdnmefghPijkl
380 /,
381 *fields: str, 1abcdnmefghPijkl
382 mode: Literal['wrap'], 1abcdnmefghPijkl
383 check_fields: bool | None = ..., 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
384 json_schema_input_type: Any = ..., 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
385) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 1abcdnmefghPijkl
388@overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
389def field_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
390 field: str, 1abcdnmefghPijkl
391 /,
392 *fields: str, 1abcdnmefghPijkl
393 mode: Literal['before', 'plain'], 1abcdnmefghPijkl
394 check_fields: bool | None = ..., 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
395 json_schema_input_type: Any = ..., 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
396) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdnmefghPijkl
399@overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
400def field_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
401 field: str, 1abcdnmefghPijkl
402 /,
403 *fields: str, 1abcdnmefghPijkl
404 mode: Literal['after'] = ..., 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
405 check_fields: bool | None = ..., 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
406) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdnmefghPijkl
409def field_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
410 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)
420 Decorate methods on the class indicating that they should be used to validate fields.
422 Example usage:
423 ```python
424 from typing import Any
426 from pydantic import (
427 BaseModel,
428 ValidationError,
429 field_validator,
430 )
432 class Model(BaseModel):
433 a: str
435 @field_validator('a')
436 @classmethod
437 def ensure_foobar(cls, v: Any):
438 if 'foobar' not in v:
439 raise ValueError('"foobar" not found in a')
440 return v
442 print(repr(Model(a='this is foobar good')))
443 #> Model(a='this is foobar good')
445 try:
446 Model(a='snap')
447 except ValidationError as exc_info:
448 print(exc_info)
449 '''
450 1 validation error for Model
451 a
452 Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str]
453 '''
454 ```
456 For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators).
458 Args:
459 field: The first field the `field_validator` should be called on; this is separate
460 from `fields` to ensure an error is raised if you don't pass at least one.
461 *fields: Additional field(s) the `field_validator` should be called on.
462 mode: Specifies whether to validate the fields before or after validation.
463 check_fields: Whether to check that the fields actually exist on the model.
464 json_schema_input_type: The input type of the function. This is only used to generate
465 the appropriate JSON Schema (in validation mode) and can only specified
466 when `mode` is either `'before'`, `'plain'` or `'wrap'`.
468 Returns:
469 A decorator that can be used to decorate a function to be used as a field_validator.
471 Raises:
472 PydanticUserError:
473 - If `@field_validator` is used bare (with no fields).
474 - If the args passed to `@field_validator` as fields are not strings.
475 - If `@field_validator` applied to instance methods.
476 """
477 if isinstance(field, FunctionType): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
478 raise PydanticUserError( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
479 '`@field_validator` should be used with fields and keyword arguments, not bare. '
480 "E.g. usage should be `@validator('<field_name>', ...)`",
481 code='validator-no-fields',
482 )
484 if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
485 raise PydanticUserError( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
486 f"`json_schema_input_type` can't be used when mode is set to {mode!r}",
487 code='validator-input-type',
488 )
490 if json_schema_input_type is PydanticUndefined and mode == 'plain': 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
491 json_schema_input_type = Any 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
493 fields = field, *fields 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
494 if not all(isinstance(field, str) for field in fields): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
495 raise PydanticUserError( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
496 '`@field_validator` fields should be passed as separate string args. '
497 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
498 code='validator-invalid-fields',
499 )
501 def dec( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
502 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any],
503 ) -> _decorators.PydanticDescriptorProxy[Any]:
504 if _decorators.is_instance_method_from_sig(f): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
505 raise PydanticUserError( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
506 '`@field_validator` cannot be applied to instance methods', code='validator-instance-method'
507 )
509 # auto apply the @classmethod decorator
510 f = _decorators.ensure_classmethod_based_on_signature(f) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
512 dec_info = _decorators.FieldValidatorDecoratorInfo( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
513 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type
514 )
515 return _decorators.PydanticDescriptorProxy(f, dec_info) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
517 return dec 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
520_ModelType = TypeVar('_ModelType') 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
521_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
524class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
525 """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`."""
527 def __call__( # noqa: D102 1GHopqrabcdABMIJstuvefghCDNPKLwxyzijklEFO
528 self,
529 value: Any, 1abcdnmefghPijkl
530 outer_location: str | int | None = None, 1opqrabcdnmstuvefghPwxyzijkl
531 /,
532 ) -> _ModelTypeCo: # pragma: no cover 1abcdnmefghPijkl
533 ...
536class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
537 """A `@model_validator` decorated function signature.
538 This is used when `mode='wrap'` and the function does not have info argument.
539 """
541 def __call__( # noqa: D102 541 ↛ exitline 541 didn't return from function '__call__' because 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
542 self,
543 cls: type[_ModelType],
544 # this can be a dict, a model instance
545 # or anything else that gets passed to validate_python
546 # thus validators _must_ handle all cases
547 value: Any,
548 handler: ModelWrapValidatorHandler[_ModelType],
549 /,
550 ) -> _ModelType: ...
553class ModelWrapValidator(Protocol[_ModelType]): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
554 """A `@model_validator` decorated function signature. This is used when `mode='wrap'`."""
556 def __call__( # noqa: D102 556 ↛ exitline 556 didn't return from function '__call__' because 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
557 self,
558 cls: type[_ModelType],
559 # this can be a dict, a model instance
560 # or anything else that gets passed to validate_python
561 # thus validators _must_ handle all cases
562 value: Any,
563 handler: ModelWrapValidatorHandler[_ModelType],
564 info: core_schema.ValidationInfo,
565 /,
566 ) -> _ModelType: ...
569class FreeModelBeforeValidatorWithoutInfo(Protocol): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
570 """A `@model_validator` decorated function signature. 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
571 This is used when `mode='before'` and the function does not have info argument.
572 """
574 def __call__( # noqa: D102 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
575 self,
576 # this can be a dict, a model instance
577 # or anything else that gets passed to validate_python
578 # thus validators _must_ handle all cases
579 value: Any, 1abcdnmefghPijkl
580 /,
581 ) -> Any: ... 1abcdnmefghPijkl
584class ModelBeforeValidatorWithoutInfo(Protocol): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
585 """A `@model_validator` decorated function signature. 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
586 This is used when `mode='before'` and the function does not have info argument.
587 """
589 def __call__( # noqa: D102 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
590 self,
591 cls: Any, 1abcdnmefghPijkl
592 # this can be a dict, a model instance
593 # or anything else that gets passed to validate_python
594 # thus validators _must_ handle all cases
595 value: Any, 1abcdnmefghPijkl
596 /,
597 ) -> Any: ... 1abcdnmefghPijkl
600class FreeModelBeforeValidator(Protocol): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
601 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
603 def __call__( # noqa: D102 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
604 self,
605 # this can be a dict, a model instance
606 # or anything else that gets passed to validate_python
607 # thus validators _must_ handle all cases
608 value: Any, 1abcdnmefghPijkl
609 info: core_schema.ValidationInfo[Any], 1abcdnmefghPijkl
610 /,
611 ) -> Any: ... 1abcdnmefghPijkl
614class ModelBeforeValidator(Protocol): 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
615 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
617 def __call__( # noqa: D102 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
618 self,
619 cls: Any, 1abcdnmefghPijkl
620 # this can be a dict, a model instance
621 # or anything else that gets passed to validate_python
622 # thus validators _must_ handle all cases
623 value: Any, 1abcdnmefghPijkl
624 info: core_schema.ValidationInfo[Any], 1abcdnmefghPijkl
625 /,
626 ) -> Any: ... 1abcdnmefghPijkl
629ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
630"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not 1opqrabcdABMmstuvefghCDNPwxyzijklEFO
631have info argument.
632"""
634ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType] 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
635"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" 1opqrabcdABMmstuvefghCDNPwxyzijklEFO
637_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
638_AnyModelBeforeValidator = Union[ 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
639 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo
640]
641_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
644@overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
645def model_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
646 *,
647 mode: Literal['wrap'], 1abcdnmefghPijkl
648) -> Callable[ 1abcdnmefghPijkl
649 [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
650]: ...
653@overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
654def model_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
655 *,
656 mode: Literal['before'], 1abcdnmefghPijkl
657) -> Callable[ 1abcdnmefghPijkl
658 [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
659]: ...
662@overload 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
663def model_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
664 *,
665 mode: Literal['after'], 1abcdnmefghPijkl
666) -> Callable[ 1abcdnmefghPijkl
667 [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
668]: ...
671def model_validator( 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
672 *,
673 mode: Literal['wrap', 'before', 'after'],
674) -> Any:
675 """!!! abstract "Usage Documentation"
676 [Model Validators](../concepts/validators.md#model-validators)
678 Decorate model methods for validation purposes.
680 Example usage:
681 ```python
682 from typing_extensions import Self
684 from pydantic import BaseModel, ValidationError, model_validator
686 class Square(BaseModel):
687 width: float
688 height: float
690 @model_validator(mode='after')
691 def verify_square(self) -> Self:
692 if self.width != self.height:
693 raise ValueError('width and height do not match')
694 return self
696 s = Square(width=1, height=1)
697 print(repr(s))
698 #> Square(width=1.0, height=1.0)
700 try:
701 Square(width=1, height=2)
702 except ValidationError as e:
703 print(e)
704 '''
705 1 validation error for Square
706 Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict]
707 '''
708 ```
710 For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators).
712 Args:
713 mode: A required string literal that specifies the validation mode.
714 It can be one of the following: 'wrap', 'before', or 'after'.
716 Returns:
717 A decorator that can be used to decorate a function to be used as a model validator.
718 """
720 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
721 # auto apply the @classmethod decorator (except for *after* validators, which should be instance methods):
722 if mode != 'after': 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
723 f = _decorators.ensure_classmethod_based_on_signature(f) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
724 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
725 return _decorators.PydanticDescriptorProxy(f, dec_info) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
727 return dec 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
730AnyType = TypeVar('AnyType') 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
733if TYPE_CHECKING: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
734 # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this
735 InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence`
737else:
739 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
740 class InstanceOf: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
741 '''Generic type for annotating a type that is an instance of a given class.
743 Example:
744 ```python
745 from pydantic import BaseModel, InstanceOf
747 class Foo:
748 ...
750 class Bar(BaseModel):
751 foo: InstanceOf[Foo]
753 Bar(foo=Foo())
754 try:
755 Bar(foo=42)
756 except ValidationError as e:
757 print(e)
758 """
759 [
760 │ {
761 │ │ 'type': 'is_instance_of',
762 │ │ 'loc': ('foo',),
763 │ │ 'msg': 'Input should be an instance of Foo',
764 │ │ 'input': 42,
765 │ │ 'ctx': {'class': 'Foo'},
766 │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of'
767 │ }
768 ]
769 """
770 ```
771 '''
773 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
774 def __class_getitem__(cls, item: AnyType) -> AnyType: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
775 return Annotated[item, cls()] 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
777 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
778 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
779 from pydantic import PydanticSchemaGenerationError 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
781 # use the generic _origin_ as the second argument to isinstance when appropriate
782 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
784 try: 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
785 # Try to generate the "standard" schema, which will be used when loading from JSON
786 original_schema = handler(source) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
787 except PydanticSchemaGenerationError: 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
788 # If that fails, just produce a schema that can validate from python
789 return instance_of_schema 1GHopqrabcdABnmIJstuvefghCDKLwxyzijklEF
790 else:
791 # Use the "original" approach to serialization
792 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
793 function=lambda v, h: h(v), schema=original_schema
794 )
795 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
797 __hash__ = object.__hash__ 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
800if TYPE_CHECKING: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
801 SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str]
802else:
804 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
805 class SkipValidation: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
806 """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be
807 skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`.
809 This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes,
810 and know that it is safe to skip validation for one or more of the fields.
812 Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations
813 may not have the expected effects. Therefore, when used, this annotation should generally be the final
814 annotation applied to a type.
815 """
817 def __class_getitem__(cls, item: Any) -> Any: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
818 return Annotated[item, SkipValidation()] 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
820 @classmethod 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
821 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO
822 with warnings.catch_warnings(): 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
823 warnings.simplefilter('ignore', ArbitraryTypeWarning) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
824 original_schema = handler(source) 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
825 metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
826 return core_schema.any_schema( 1GHopqrabcdABMnmIJstuvefghCDNKLwxyzijklEFO
827 metadata=metadata,
828 serialization=core_schema.wrap_serializer_function_ser_schema(
829 function=lambda v, h: h(v), schema=original_schema
830 ),
831 )
833 __hash__ = object.__hash__ 1GHopqrabcdABMnmIJstuvefghCDNPKLwxyzijklEFO