Coverage for pydantic/functional_validators.py: 98.84%
148 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-28 10:05 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-28 10:05 +0000
1"""This module contains related classes and functions for validation."""
3from __future__ import annotations as _annotations 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
5import dataclasses 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
6import sys 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
7from functools import partialmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
8from types import FunctionType 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
9from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
11from pydantic_core import PydanticUndefined, core_schema 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
12from pydantic_core import core_schema as _core_schema 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
13from typing_extensions import Self, TypeAlias 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
15from ._internal import _decorators, _generics, _internal_dataclass 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
16from .annotated_handlers import GetCoreSchemaHandler 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
17from .errors import PydanticUserError 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
19if sys.version_info < (3, 11): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
20 from typing_extensions import Protocol 1DErsqpFGvwPNHIzA
21else:
22 from typing import Protocol 1tuabcdexyfghijOJKLMBCklmno
24_inspect_validator = _decorators.inspect_validator 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
27@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
28class AfterValidator: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
29 """!!! abstract "Usage Documentation"
30 [field *after* validators](../concepts/validators.md#field-after-validator)
32 A metadata class that indicates that a validation should be applied **after** the inner validation logic.
34 Attributes:
35 func: The validator function.
37 Example:
38 ```python
39 from typing import Annotated
41 from pydantic import AfterValidator, BaseModel, ValidationError
43 MyInt = Annotated[int, AfterValidator(lambda v: v + 1)]
45 class Model(BaseModel):
46 a: MyInt
48 print(Model(a=1).a)
49 #> 2
51 try:
52 Model(a='a')
53 except ValidationError as e:
54 print(e.json(indent=2))
55 '''
56 [
57 {
58 "type": "int_parsing",
59 "loc": [
60 "a"
61 ],
62 "msg": "Input should be a valid integer, unable to parse string as an integer",
63 "input": "a",
64 "url": "https://errors.pydantic.dev/2/v/int_parsing"
65 }
66 ]
67 '''
68 ```
69 """
71 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
73 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
74 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
75 info_arg = _inspect_validator(self.func, 'after') 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
76 if info_arg: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
77 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
78 return core_schema.with_info_after_validator_function(func, schema=schema) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
79 else:
80 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
81 return core_schema.no_info_after_validator_function(func, schema=schema) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
83 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
84 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
85 return cls(func=decorator.func) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
88@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
89class BeforeValidator: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
90 """!!! abstract "Usage Documentation"
91 [field *before* validators](../concepts/validators.md#field-before-validator)
93 A metadata class that indicates that a validation should be applied **before** the inner validation logic.
95 Attributes:
96 func: The validator function.
97 json_schema_input_type: The input type of the function. This is only used to generate the appropriate
98 JSON Schema (in validation mode).
100 Example:
101 ```python
102 from typing import Annotated
104 from pydantic import BaseModel, BeforeValidator
106 MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)]
108 class Model(BaseModel):
109 a: MyInt
111 print(Model(a=1).a)
112 #> 2
114 try:
115 Model(a='a')
116 except TypeError as e:
117 print(e)
118 #> can only concatenate str (not "int") to str
119 ```
120 """
122 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
123 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
125 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
126 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
127 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
128 None
129 if self.json_schema_input_type is PydanticUndefined
130 else handler.generate_schema(self.json_schema_input_type)
131 )
133 info_arg = _inspect_validator(self.func, 'before') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
134 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
135 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
136 return core_schema.with_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
137 func,
138 schema=schema,
139 json_schema_input_schema=input_schema,
140 )
141 else:
142 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
143 return core_schema.no_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
144 func, schema=schema, json_schema_input_schema=input_schema
145 )
147 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
148 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
149 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
150 func=decorator.func,
151 json_schema_input_type=decorator.info.json_schema_input_type,
152 )
155@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
156class PlainValidator: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
157 """!!! abstract "Usage Documentation"
158 [field *plain* validators](../concepts/validators.md#field-plain-validator)
160 A metadata class that indicates that a validation should be applied **instead** of the inner validation logic.
162 !!! note
163 Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`.
164 You can now use the `json_schema_input_type` argument to specify the input type of the function
165 to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details.
167 Attributes:
168 func: The validator function.
169 json_schema_input_type: The input type of the function. This is only used to generate the appropriate
170 JSON Schema (in validation mode). If not provided, will default to `Any`.
172 Example:
173 ```python
174 from typing import Annotated, Union
176 from pydantic import BaseModel, PlainValidator
178 MyInt = Annotated[
179 int,
180 PlainValidator(
181 lambda v: int(v) + 1, json_schema_input_type=Union[str, int] # (1)!
182 ),
183 ]
185 class Model(BaseModel):
186 a: MyInt
188 print(Model(a='1').a)
189 #> 2
191 print(Model(a=1).a)
192 #> 2
193 ```
195 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema
196 generator that in validation mode, the input type for the `a` field can be either a `str` or an `int`.
197 """
199 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
200 json_schema_input_type: Any = Any 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
202 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
203 # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the
204 # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper
205 # serialization schema. To work around this for use cases that will not involve serialization, we simply
206 # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema
207 # and abort any attempts to handle special serialization.
208 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
210 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
211 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
212 # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence',
213 # schema validation will fail. That's why we use 'type ignore' comments below.
214 serialization = schema.get( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
215 'serialization',
216 core_schema.wrap_serializer_function_ser_schema(
217 function=lambda v, h: h(v),
218 schema=schema,
219 return_schema=handler.generate_schema(source_type),
220 ),
221 )
222 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
223 serialization = None 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
225 input_schema = handler.generate_schema(self.json_schema_input_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
227 info_arg = _inspect_validator(self.func, 'plain') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
228 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
229 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
230 return core_schema.with_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
231 func,
232 serialization=serialization, # pyright: ignore[reportArgumentType]
233 json_schema_input_schema=input_schema,
234 )
235 else:
236 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
237 return core_schema.no_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
238 func,
239 serialization=serialization, # pyright: ignore[reportArgumentType]
240 json_schema_input_schema=input_schema,
241 )
243 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
244 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
245 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
246 func=decorator.func,
247 json_schema_input_type=decorator.info.json_schema_input_type,
248 )
251@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
252class WrapValidator: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
253 """!!! abstract "Usage Documentation"
254 [field *wrap* validators](../concepts/validators.md#field-wrap-validator)
256 A metadata class that indicates that a validation should be applied **around** the inner validation logic.
258 Attributes:
259 func: The validator function.
260 json_schema_input_type: The input type of the function. This is only used to generate the appropriate
261 JSON Schema (in validation mode).
263 ```python
264 from datetime import datetime
265 from typing import Annotated
267 from pydantic import BaseModel, ValidationError, WrapValidator
269 def validate_timestamp(v, handler):
270 if v == 'now':
271 # we don't want to bother with further validation, just return the new value
272 return datetime.now()
273 try:
274 return handler(v)
275 except ValidationError:
276 # validation failed, in this case we want to return a default value
277 return datetime(2000, 1, 1)
279 MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)]
281 class Model(BaseModel):
282 a: MyTimestamp
284 print(Model(a='now').a)
285 #> 2032-01-02 03:04:05.000006
286 print(Model(a='invalid').a)
287 #> 2000-01-01 00:00:00
288 ```
289 """
291 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
292 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
294 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
295 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
296 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
297 None
298 if self.json_schema_input_type is PydanticUndefined
299 else handler.generate_schema(self.json_schema_input_type)
300 )
302 info_arg = _inspect_validator(self.func, 'wrap') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
303 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
304 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
305 return core_schema.with_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
306 func,
307 schema=schema,
308 json_schema_input_schema=input_schema,
309 )
310 else:
311 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
312 return core_schema.no_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
313 func,
314 schema=schema,
315 json_schema_input_schema=input_schema,
316 )
318 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
319 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
320 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
321 func=decorator.func,
322 json_schema_input_type=decorator.info.json_schema_input_type,
323 )
326if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
328 class _OnlyValueValidatorClsMethod(Protocol):
329 def __call__(self, cls: Any, value: Any, /) -> Any: ...
331 class _V2ValidatorClsMethod(Protocol):
332 def __call__(self, cls: Any, value: Any, info: _core_schema.ValidationInfo, /) -> Any: ...
334 class _OnlyValueWrapValidatorClsMethod(Protocol):
335 def __call__(self, cls: Any, value: Any, handler: _core_schema.ValidatorFunctionWrapHandler, /) -> Any: ...
337 class _V2WrapValidatorClsMethod(Protocol):
338 def __call__(
339 self,
340 cls: Any,
341 value: Any,
342 handler: _core_schema.ValidatorFunctionWrapHandler,
343 info: _core_schema.ValidationInfo,
344 /,
345 ) -> Any: ...
347 _V2Validator = Union[
348 _V2ValidatorClsMethod,
349 _core_schema.WithInfoValidatorFunction,
350 _OnlyValueValidatorClsMethod,
351 _core_schema.NoInfoValidatorFunction,
352 ]
354 _V2WrapValidator = Union[
355 _V2WrapValidatorClsMethod,
356 _core_schema.WithInfoWrapValidatorFunction,
357 _OnlyValueWrapValidatorClsMethod,
358 _core_schema.NoInfoWrapValidatorFunction,
359 ]
361 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
363 _V2BeforeAfterOrPlainValidatorType = TypeVar(
364 '_V2BeforeAfterOrPlainValidatorType',
365 bound=Union[_V2Validator, _PartialClsOrStaticMethod],
366 )
367 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod])
369FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
372@overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
373def field_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
374 field: str, 1abcdeqpfghijJKLMklmno
375 /,
376 *fields: str, 1abcdeqpfghijJKLMklmno
377 mode: Literal['wrap'], 1abcdeqpfghijJKLMklmno
378 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
379 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
380) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 1abcdeqpfghijJKLMklmno
383@overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
384def field_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
385 field: str, 1abcdeqpfghijJKLMklmno
386 /,
387 *fields: str, 1abcdeqpfghijJKLMklmno
388 mode: Literal['before', 'plain'], 1abcdeqpfghijJKLMklmno
389 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
390 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
391) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdeqpfghijJKLMklmno
394@overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
395def field_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
396 field: str, 1abcdeqpfghijJKLMklmno
397 /,
398 *fields: str, 1abcdeqpfghijJKLMklmno
399 mode: Literal['after'] = ..., 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
400 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
401) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdeqpfghijJKLMklmno
404def field_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
405 field: str,
406 /,
407 *fields: str,
408 mode: FieldValidatorModes = 'after',
409 check_fields: bool | None = None,
410 json_schema_input_type: Any = PydanticUndefined,
411) -> Callable[[Any], Any]:
412 """!!! abstract "Usage Documentation"
413 [field validators](../concepts/validators.md#field-validators)
415 Decorate methods on the class indicating that they should be used to validate fields.
417 Example usage:
418 ```python
419 from typing import Any
421 from pydantic import (
422 BaseModel,
423 ValidationError,
424 field_validator,
425 )
427 class Model(BaseModel):
428 a: str
430 @field_validator('a')
431 @classmethod
432 def ensure_foobar(cls, v: Any):
433 if 'foobar' not in v:
434 raise ValueError('"foobar" not found in a')
435 return v
437 print(repr(Model(a='this is foobar good')))
438 #> Model(a='this is foobar good')
440 try:
441 Model(a='snap')
442 except ValidationError as exc_info:
443 print(exc_info)
444 '''
445 1 validation error for Model
446 a
447 Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str]
448 '''
449 ```
451 For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators).
453 Args:
454 field: The first field the `field_validator` should be called on; this is separate
455 from `fields` to ensure an error is raised if you don't pass at least one.
456 *fields: Additional field(s) the `field_validator` should be called on.
457 mode: Specifies whether to validate the fields before or after validation.
458 check_fields: Whether to check that the fields actually exist on the model.
459 json_schema_input_type: The input type of the function. This is only used to generate
460 the appropriate JSON Schema (in validation mode) and can only specified
461 when `mode` is either `'before'`, `'plain'` or `'wrap'`.
463 Returns:
464 A decorator that can be used to decorate a function to be used as a field_validator.
466 Raises:
467 PydanticUserError:
468 - If `@field_validator` is used bare (with no fields).
469 - If the args passed to `@field_validator` as fields are not strings.
470 - If `@field_validator` applied to instance methods.
471 """
472 if isinstance(field, FunctionType): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
473 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
474 '`@field_validator` should be used with fields and keyword arguments, not bare. '
475 "E.g. usage should be `@validator('<field_name>', ...)`",
476 code='validator-no-fields',
477 )
479 if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
480 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
481 f"`json_schema_input_type` can't be used when mode is set to {mode!r}",
482 code='validator-input-type',
483 )
485 if json_schema_input_type is PydanticUndefined and mode == 'plain': 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
486 json_schema_input_type = Any 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
488 fields = field, *fields 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
489 if not all(isinstance(field, str) for field in fields): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
490 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
491 '`@field_validator` fields should be passed as separate string args. '
492 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
493 code='validator-invalid-fields',
494 )
496 def dec( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
497 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any],
498 ) -> _decorators.PydanticDescriptorProxy[Any]:
499 if _decorators.is_instance_method_from_sig(f): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
500 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
501 '`@field_validator` cannot be applied to instance methods', code='validator-instance-method'
502 )
504 # auto apply the @classmethod decorator
505 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
507 dec_info = _decorators.FieldValidatorDecoratorInfo( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
508 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type
509 )
510 return _decorators.PydanticDescriptorProxy(f, dec_info) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
512 return dec 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
515_ModelType = TypeVar('_ModelType') 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
516_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
519class ModelWrapValidatorHandler(_core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
520 """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`."""
522 def __call__( # noqa: D102 1DErstuabcdeFGvwxyfghijPNOJKLMHIzABCklmno
523 self,
524 value: Any, 1abcdeqpfghijJKLMklmno
525 outer_location: str | int | None = None, 1rstuabcdeqpvwxyfghijNOJKLMzABCklmno
526 /,
527 ) -> _ModelTypeCo: # pragma: no cover 1abcdeqpfghijJKLMklmno
528 ...
531class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
532 """A `@model_validator` decorated function signature.
533 This is used when `mode='wrap'` and the function does not have info argument.
534 """
536 def __call__( # noqa: D102 536 ↛ exitline 536 didn't return from function '__call__' because 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
537 self,
538 cls: type[_ModelType],
539 # this can be a dict, a model instance
540 # or anything else that gets passed to validate_python
541 # thus validators _must_ handle all cases
542 value: Any,
543 handler: ModelWrapValidatorHandler[_ModelType],
544 /,
545 ) -> _ModelType: ...
548class ModelWrapValidator(Protocol[_ModelType]): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
549 """A `@model_validator` decorated function signature. This is used when `mode='wrap'`."""
551 def __call__( # noqa: D102 551 ↛ exitline 551 didn't return from function '__call__' because 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
552 self,
553 cls: type[_ModelType],
554 # this can be a dict, a model instance
555 # or anything else that gets passed to validate_python
556 # thus validators _must_ handle all cases
557 value: Any,
558 handler: ModelWrapValidatorHandler[_ModelType],
559 info: _core_schema.ValidationInfo,
560 /,
561 ) -> _ModelType: ...
564class FreeModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
565 """A `@model_validator` decorated function signature. 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
566 This is used when `mode='before'` and the function does not have info argument.
567 """
569 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
570 self,
571 # this can be a dict, a model instance
572 # or anything else that gets passed to validate_python
573 # thus validators _must_ handle all cases
574 value: Any, 1abcdeqpfghijJKLMklmno
575 /,
576 ) -> Any: ... 1abcdeqpfghijJKLMklmno
579class ModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
580 """A `@model_validator` decorated function signature. 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
581 This is used when `mode='before'` and the function does not have info argument.
582 """
584 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
585 self,
586 cls: Any, 1abcdeqpfghijJKLMklmno
587 # this can be a dict, a model instance
588 # or anything else that gets passed to validate_python
589 # thus validators _must_ handle all cases
590 value: Any, 1abcdeqpfghijJKLMklmno
591 /,
592 ) -> Any: ... 1abcdeqpfghijJKLMklmno
595class FreeModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
596 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
598 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
599 self,
600 # this can be a dict, a model instance
601 # or anything else that gets passed to validate_python
602 # thus validators _must_ handle all cases
603 value: Any, 1abcdeqpfghijJKLMklmno
604 info: _core_schema.ValidationInfo, 1abcdeqpfghijJKLMklmno
605 /,
606 ) -> Any: ... 1abcdeqpfghijJKLMklmno
609class ModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
610 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
612 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
613 self,
614 cls: Any, 1abcdeqpfghijJKLMklmno
615 # this can be a dict, a model instance
616 # or anything else that gets passed to validate_python
617 # thus validators _must_ handle all cases
618 value: Any, 1abcdeqpfghijJKLMklmno
619 info: _core_schema.ValidationInfo, 1abcdeqpfghijJKLMklmno
620 /,
621 ) -> Any: ... 1abcdeqpfghijJKLMklmno
624ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
625"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not 1rstuabcdepvwxyfghijNOJKLMzABCklmno
626have info argument.
627"""
629ModelAfterValidator = Callable[[_ModelType, _core_schema.ValidationInfo], _ModelType] 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
630"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" 1rstuabcdepvwxyfghijNOJKLMzABCklmno
632_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
633_AnyModelBeforeValidator = Union[ 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
634 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo
635]
636_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
639@overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
640def model_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
641 *,
642 mode: Literal['wrap'], 1abcdeqpfghijJKLMklmno
643) -> Callable[ 1abcdeqpfghijJKLMklmno
644 [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
645]: ...
648@overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
649def model_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
650 *,
651 mode: Literal['before'], 1abcdeqpfghijJKLMklmno
652) -> Callable[ 1abcdeqpfghijJKLMklmno
653 [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
654]: ...
657@overload 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
658def model_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
659 *,
660 mode: Literal['after'], 1abcdeqpfghijJKLMklmno
661) -> Callable[ 1abcdeqpfghijJKLMklmno
662 [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
663]: ...
666def model_validator( 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
667 *,
668 mode: Literal['wrap', 'before', 'after'],
669) -> Any:
670 """!!! abstract "Usage Documentation"
671 [Model Validators](../concepts/validators.md#model-validators)
673 Decorate model methods for validation purposes.
675 Example usage:
676 ```python
677 from typing_extensions import Self
679 from pydantic import BaseModel, ValidationError, model_validator
681 class Square(BaseModel):
682 width: float
683 height: float
685 @model_validator(mode='after')
686 def verify_square(self) -> Self:
687 if self.width != self.height:
688 raise ValueError('width and height do not match')
689 return self
691 s = Square(width=1, height=1)
692 print(repr(s))
693 #> Square(width=1.0, height=1.0)
695 try:
696 Square(width=1, height=2)
697 except ValidationError as e:
698 print(e)
699 '''
700 1 validation error for Square
701 Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict]
702 '''
703 ```
705 For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators).
707 Args:
708 mode: A required string literal that specifies the validation mode.
709 It can be one of the following: 'wrap', 'before', or 'after'.
711 Returns:
712 A decorator that can be used to decorate a function to be used as a model validator.
713 """
715 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
716 # auto apply the @classmethod decorator
717 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
718 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
719 return _decorators.PydanticDescriptorProxy(f, dec_info) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
721 return dec 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
724AnyType = TypeVar('AnyType') 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
727if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
728 # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this
729 InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence`
731else:
733 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
734 class InstanceOf: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
735 '''Generic type for annotating a type that is an instance of a given class.
737 Example:
738 ```python
739 from pydantic import BaseModel, InstanceOf
741 class Foo:
742 ...
744 class Bar(BaseModel):
745 foo: InstanceOf[Foo]
747 Bar(foo=Foo())
748 try:
749 Bar(foo=42)
750 except ValidationError as e:
751 print(e)
752 """
753 [
754 │ {
755 │ │ 'type': 'is_instance_of',
756 │ │ 'loc': ('foo',),
757 │ │ 'msg': 'Input should be an instance of Foo',
758 │ │ 'input': 42,
759 │ │ 'ctx': {'class': 'Foo'},
760 │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of'
761 │ }
762 ]
763 """
764 ```
765 '''
767 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
768 def __class_getitem__(cls, item: AnyType) -> AnyType: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
769 return Annotated[item, cls()] 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
771 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
772 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
773 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
775 # use the generic _origin_ as the second argument to isinstance when appropriate
776 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
778 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
779 # Try to generate the "standard" schema, which will be used when loading from JSON
780 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
781 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
782 # If that fails, just produce a schema that can validate from python
783 return instance_of_schema 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
784 else:
785 # Use the "original" approach to serialization
786 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
787 function=lambda v, h: h(v), schema=original_schema
788 )
789 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
791 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
794if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
795 SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str]
796else:
798 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
799 class SkipValidation: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
800 """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be
801 skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`.
803 This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes,
804 and know that it is safe to skip validation for one or more of the fields.
806 Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations
807 may not have the expected effects. Therefore, when used, this annotation should generally be the final
808 annotation applied to a type.
809 """
811 def __class_getitem__(cls, item: Any) -> Any: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
812 return Annotated[item, SkipValidation()] 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
814 @classmethod 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
815 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno
816 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
817 metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
818 return core_schema.any_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno
819 metadata=metadata,
820 serialization=core_schema.wrap_serializer_function_ser_schema(
821 function=lambda v, h: h(v), schema=original_schema
822 ),
823 )
825 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijPNOJKLMHIzABCklmno