Coverage for pydantic/functional_validators.py: 98.84%
148 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-13 19:35 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-13 19:35 +0000
1"""This module contains related classes and functions for validation."""
3from __future__ import annotations as _annotations 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
5import dataclasses 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
6import sys 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
7from functools import partialmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
8from types import FunctionType 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
9from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
11from pydantic_core import PydanticUndefined, core_schema 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
12from pydantic_core import core_schema as _core_schema 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
13from typing_extensions import Self, TypeAlias 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
15from ._internal import _decorators, _generics, _internal_dataclass 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
16from .annotated_handlers import GetCoreSchemaHandler 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
17from .errors import PydanticUserError 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
19if sys.version_info < (3, 11): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
20 from typing_extensions import Protocol 1ABopnmCDstMKEFwx
21else:
22 from typing import Protocol 1qrabcduvefghLGHIJyzijkl
24_inspect_validator = _decorators.inspect_validator 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
27@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
28class AfterValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
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 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
73 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
74 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
75 info_arg = _inspect_validator(self.func, 'after') 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
76 if info_arg: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
77 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
78 return core_schema.with_info_after_validator_function(func, schema=schema, field_name=handler.field_name) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
79 else:
80 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
81 return core_schema.no_info_after_validator_function(func, schema=schema) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
83 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
84 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
85 return cls(func=decorator.func) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
88@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
89class BeforeValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
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 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
123 json_schema_input_type: Any = PydanticUndefined 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
125 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
126 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
127 input_schema = ( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
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') 1ABopqrabcdnmCDstuvefghEFwxyzijkl
134 if info_arg: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
135 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
136 return core_schema.with_info_before_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
137 func,
138 schema=schema,
139 field_name=handler.field_name,
140 json_schema_input_schema=input_schema,
141 )
142 else:
143 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
144 return core_schema.no_info_before_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
145 func, schema=schema, json_schema_input_schema=input_schema
146 )
148 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
149 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
150 return cls( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
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) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
157class PlainValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
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 of the function. This is only used to generate the appropriate
171 JSON Schema (in validation mode). If not provided, will default to `Any`.
173 Example:
174 ```python
175 from typing import Annotated, Union
177 from pydantic import BaseModel, PlainValidator
179 MyInt = Annotated[
180 int,
181 PlainValidator(
182 lambda v: int(v) + 1, json_schema_input_type=Union[str, int] # (1)!
183 ),
184 ]
186 class Model(BaseModel):
187 a: MyInt
189 print(Model(a='1').a)
190 #> 2
192 print(Model(a=1).a)
193 #> 2
194 ```
196 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema
197 generator that in validation mode, the input type for the `a` field can be either a `str` or an `int`.
198 """
200 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
201 json_schema_input_type: Any = Any 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
203 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
204 # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the
205 # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper
206 # serialization schema. To work around this for use cases that will not involve serialization, we simply
207 # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema
208 # and abort any attempts to handle special serialization.
209 from pydantic import PydanticSchemaGenerationError 1ABopqrabcdnmCDstuvefghEFwxyzijkl
211 try: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
212 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
213 # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence',
214 # schema validation will fail. That's why we use 'type ignore' comments below.
215 serialization = schema.get( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
216 'serialization',
217 core_schema.wrap_serializer_function_ser_schema(
218 function=lambda v, h: h(v),
219 schema=schema,
220 return_schema=handler.generate_schema(source_type),
221 ),
222 )
223 except PydanticSchemaGenerationError: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
224 serialization = None 1ABopqrabcdnmCDstuvefghEFwxyzijkl
226 input_schema = handler.generate_schema(self.json_schema_input_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
228 info_arg = _inspect_validator(self.func, 'plain') 1ABopqrabcdnmCDstuvefghEFwxyzijkl
229 if info_arg: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
230 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
231 return core_schema.with_info_plain_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
232 func,
233 field_name=handler.field_name,
234 serialization=serialization, # pyright: ignore[reportArgumentType]
235 json_schema_input_schema=input_schema,
236 )
237 else:
238 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
239 return core_schema.no_info_plain_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
240 func,
241 serialization=serialization, # pyright: ignore[reportArgumentType]
242 json_schema_input_schema=input_schema,
243 )
245 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
246 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
247 return cls( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
248 func=decorator.func,
249 json_schema_input_type=decorator.info.json_schema_input_type,
250 )
253@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
254class WrapValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
255 """!!! abstract "Usage Documentation"
256 [field *wrap* validators](../concepts/validators.md#field-wrap-validator)
258 A metadata class that indicates that a validation should be applied **around** the inner validation logic.
260 Attributes:
261 func: The validator function.
262 json_schema_input_type: The input type of the function. This is only used to generate the appropriate
263 JSON Schema (in validation mode).
265 ```python
266 from datetime import datetime
267 from typing import Annotated
269 from pydantic import BaseModel, ValidationError, WrapValidator
271 def validate_timestamp(v, handler):
272 if v == 'now':
273 # we don't want to bother with further validation, just return the new value
274 return datetime.now()
275 try:
276 return handler(v)
277 except ValidationError:
278 # validation failed, in this case we want to return a default value
279 return datetime(2000, 1, 1)
281 MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)]
283 class Model(BaseModel):
284 a: MyTimestamp
286 print(Model(a='now').a)
287 #> 2032-01-02 03:04:05.000006
288 print(Model(a='invalid').a)
289 #> 2000-01-01 00:00:00
290 ```
291 """
293 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
294 json_schema_input_type: Any = PydanticUndefined 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
296 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
297 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
298 input_schema = ( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
299 None
300 if self.json_schema_input_type is PydanticUndefined
301 else handler.generate_schema(self.json_schema_input_type)
302 )
304 info_arg = _inspect_validator(self.func, 'wrap') 1ABopqrabcdnmCDstuvefghEFwxyzijkl
305 if info_arg: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
306 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
307 return core_schema.with_info_wrap_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
308 func,
309 schema=schema,
310 field_name=handler.field_name,
311 json_schema_input_schema=input_schema,
312 )
313 else:
314 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
315 return core_schema.no_info_wrap_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
316 func,
317 schema=schema,
318 json_schema_input_schema=input_schema,
319 )
321 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
322 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
323 return cls( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
324 func=decorator.func,
325 json_schema_input_type=decorator.info.json_schema_input_type,
326 )
329if TYPE_CHECKING: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
331 class _OnlyValueValidatorClsMethod(Protocol):
332 def __call__(self, cls: Any, value: Any, /) -> Any: ...
334 class _V2ValidatorClsMethod(Protocol):
335 def __call__(self, cls: Any, value: Any, info: _core_schema.ValidationInfo, /) -> Any: ...
337 class _OnlyValueWrapValidatorClsMethod(Protocol):
338 def __call__(self, cls: Any, value: Any, handler: _core_schema.ValidatorFunctionWrapHandler, /) -> Any: ...
340 class _V2WrapValidatorClsMethod(Protocol):
341 def __call__(
342 self,
343 cls: Any,
344 value: Any,
345 handler: _core_schema.ValidatorFunctionWrapHandler,
346 info: _core_schema.ValidationInfo,
347 /,
348 ) -> Any: ...
350 _V2Validator = Union[
351 _V2ValidatorClsMethod,
352 _core_schema.WithInfoValidatorFunction,
353 _OnlyValueValidatorClsMethod,
354 _core_schema.NoInfoValidatorFunction,
355 ]
357 _V2WrapValidator = Union[
358 _V2WrapValidatorClsMethod,
359 _core_schema.WithInfoWrapValidatorFunction,
360 _OnlyValueWrapValidatorClsMethod,
361 _core_schema.NoInfoWrapValidatorFunction,
362 ]
364 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
366 _V2BeforeAfterOrPlainValidatorType = TypeVar(
367 '_V2BeforeAfterOrPlainValidatorType',
368 bound=Union[_V2Validator, _PartialClsOrStaticMethod],
369 )
370 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod])
372FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
375@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
376def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
377 field: str, 1abcdnmefghGHIJijkl
378 /,
379 *fields: str, 1abcdnmefghGHIJijkl
380 mode: Literal['wrap'], 1abcdnmefghGHIJijkl
381 check_fields: bool | None = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
382 json_schema_input_type: Any = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
383) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 1abcdnmefghGHIJijkl
386@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
387def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
388 field: str, 1abcdnmefghGHIJijkl
389 /,
390 *fields: str, 1abcdnmefghGHIJijkl
391 mode: Literal['before', 'plain'], 1abcdnmefghGHIJijkl
392 check_fields: bool | None = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
393 json_schema_input_type: Any = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
394) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdnmefghGHIJijkl
397@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
398def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
399 field: str, 1abcdnmefghGHIJijkl
400 /,
401 *fields: str, 1abcdnmefghGHIJijkl
402 mode: Literal['after'] = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
403 check_fields: bool | None = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
404) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdnmefghGHIJijkl
407def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
408 field: str,
409 /,
410 *fields: str,
411 mode: FieldValidatorModes = 'after',
412 check_fields: bool | None = None,
413 json_schema_input_type: Any = PydanticUndefined,
414) -> Callable[[Any], Any]:
415 """!!! abstract "Usage Documentation"
416 [field validators](../concepts/validators.md#field-validators)
418 Decorate methods on the class indicating that they should be used to validate fields.
420 Example usage:
421 ```python
422 from typing import Any
424 from pydantic import (
425 BaseModel,
426 ValidationError,
427 field_validator,
428 )
430 class Model(BaseModel):
431 a: str
433 @field_validator('a')
434 @classmethod
435 def ensure_foobar(cls, v: Any):
436 if 'foobar' not in v:
437 raise ValueError('"foobar" not found in a')
438 return v
440 print(repr(Model(a='this is foobar good')))
441 #> Model(a='this is foobar good')
443 try:
444 Model(a='snap')
445 except ValidationError as exc_info:
446 print(exc_info)
447 '''
448 1 validation error for Model
449 a
450 Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str]
451 '''
452 ```
454 For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators).
456 Args:
457 field: The first field the `field_validator` should be called on; this is separate
458 from `fields` to ensure an error is raised if you don't pass at least one.
459 *fields: Additional field(s) the `field_validator` should be called on.
460 mode: Specifies whether to validate the fields before or after validation.
461 check_fields: Whether to check that the fields actually exist on the model.
462 json_schema_input_type: The input type of the function. This is only used to generate
463 the appropriate JSON Schema (in validation mode) and can only specified
464 when `mode` is either `'before'`, `'plain'` or `'wrap'`.
466 Returns:
467 A decorator that can be used to decorate a function to be used as a field_validator.
469 Raises:
470 PydanticUserError:
471 - If `@field_validator` is used bare (with no fields).
472 - If the args passed to `@field_validator` as fields are not strings.
473 - If `@field_validator` applied to instance methods.
474 """
475 if isinstance(field, FunctionType): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
476 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
477 '`@field_validator` should be used with fields and keyword arguments, not bare. '
478 "E.g. usage should be `@validator('<field_name>', ...)`",
479 code='validator-no-fields',
480 )
482 if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
483 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
484 f"`json_schema_input_type` can't be used when mode is set to {mode!r}",
485 code='validator-input-type',
486 )
488 if json_schema_input_type is PydanticUndefined and mode == 'plain': 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
489 json_schema_input_type = Any 1ABopqrabcdnmCDstuvefghEFwxyzijkl
491 fields = field, *fields 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
492 if not all(isinstance(field, str) for field in fields): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
493 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
494 '`@field_validator` fields should be passed as separate string args. '
495 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
496 code='validator-invalid-fields',
497 )
499 def dec( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
500 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any],
501 ) -> _decorators.PydanticDescriptorProxy[Any]:
502 if _decorators.is_instance_method_from_sig(f): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
503 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
504 '`@field_validator` cannot be applied to instance methods', code='validator-instance-method'
505 )
507 # auto apply the @classmethod decorator
508 f = _decorators.ensure_classmethod_based_on_signature(f) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
510 dec_info = _decorators.FieldValidatorDecoratorInfo( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
511 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type
512 )
513 return _decorators.PydanticDescriptorProxy(f, dec_info) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
515 return dec 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
518_ModelType = TypeVar('_ModelType') 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
519_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
522class ModelWrapValidatorHandler(_core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
523 """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`."""
525 def __call__( # noqa: D102 1ABopqrabcdCDstuvefghMKLGHIJEFwxyzijkl
526 self,
527 value: Any, 1abcdnmefghGHIJijkl
528 outer_location: str | int | None = None, 1opqrabcdnmstuvefghKLGHIJwxyzijkl
529 /,
530 ) -> _ModelTypeCo: # pragma: no cover 1abcdnmefghGHIJijkl
531 ...
534class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
535 """A `@model_validator` decorated function signature.
536 This is used when `mode='wrap'` and the function does not have info argument.
537 """
539 def __call__( # noqa: D102 539 ↛ exitline 539 didn't return from function '__call__' because 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
540 self,
541 cls: type[_ModelType],
542 # this can be a dict, a model instance
543 # or anything else that gets passed to validate_python
544 # thus validators _must_ handle all cases
545 value: Any,
546 handler: ModelWrapValidatorHandler[_ModelType],
547 /,
548 ) -> _ModelType: ...
551class ModelWrapValidator(Protocol[_ModelType]): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
552 """A `@model_validator` decorated function signature. This is used when `mode='wrap'`."""
554 def __call__( # noqa: D102 554 ↛ exitline 554 didn't return from function '__call__' because 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
555 self,
556 cls: type[_ModelType],
557 # this can be a dict, a model instance
558 # or anything else that gets passed to validate_python
559 # thus validators _must_ handle all cases
560 value: Any,
561 handler: ModelWrapValidatorHandler[_ModelType],
562 info: _core_schema.ValidationInfo,
563 /,
564 ) -> _ModelType: ...
567class FreeModelBeforeValidatorWithoutInfo(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
568 """A `@model_validator` decorated function signature. 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
569 This is used when `mode='before'` and the function does not have info argument.
570 """
572 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
573 self,
574 # this can be a dict, a model instance
575 # or anything else that gets passed to validate_python
576 # thus validators _must_ handle all cases
577 value: Any, 1abcdnmefghGHIJijkl
578 /,
579 ) -> Any: ... 1abcdnmefghGHIJijkl
582class ModelBeforeValidatorWithoutInfo(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
583 """A `@model_validator` decorated function signature. 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
584 This is used when `mode='before'` and the function does not have info argument.
585 """
587 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
588 self,
589 cls: Any, 1abcdnmefghGHIJijkl
590 # this can be a dict, a model instance
591 # or anything else that gets passed to validate_python
592 # thus validators _must_ handle all cases
593 value: Any, 1abcdnmefghGHIJijkl
594 /,
595 ) -> Any: ... 1abcdnmefghGHIJijkl
598class FreeModelBeforeValidator(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
599 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
601 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
602 self,
603 # this can be a dict, a model instance
604 # or anything else that gets passed to validate_python
605 # thus validators _must_ handle all cases
606 value: Any, 1abcdnmefghGHIJijkl
607 info: _core_schema.ValidationInfo, 1abcdnmefghGHIJijkl
608 /,
609 ) -> Any: ... 1abcdnmefghGHIJijkl
612class ModelBeforeValidator(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
613 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
615 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
616 self,
617 cls: Any, 1abcdnmefghGHIJijkl
618 # this can be a dict, a model instance
619 # or anything else that gets passed to validate_python
620 # thus validators _must_ handle all cases
621 value: Any, 1abcdnmefghGHIJijkl
622 info: _core_schema.ValidationInfo, 1abcdnmefghGHIJijkl
623 /,
624 ) -> Any: ... 1abcdnmefghGHIJijkl
627ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
628"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not 1opqrabcdmstuvefghKLGHIJwxyzijkl
629have info argument.
630"""
632ModelAfterValidator = Callable[[_ModelType, _core_schema.ValidationInfo], _ModelType] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
633"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" 1opqrabcdmstuvefghKLGHIJwxyzijkl
635_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
636_AnyModelBeforeValidator = Union[ 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
637 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo
638]
639_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
642@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
643def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
644 *,
645 mode: Literal['wrap'], 1abcdnmefghGHIJijkl
646) -> Callable[ 1abcdnmefghGHIJijkl
647 [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
648]: ...
651@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
652def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
653 *,
654 mode: Literal['before'], 1abcdnmefghGHIJijkl
655) -> Callable[ 1abcdnmefghGHIJijkl
656 [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
657]: ...
660@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
661def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
662 *,
663 mode: Literal['after'], 1abcdnmefghGHIJijkl
664) -> Callable[ 1abcdnmefghGHIJijkl
665 [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]
666]: ...
669def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
670 *,
671 mode: Literal['wrap', 'before', 'after'],
672) -> Any:
673 """!!! abstract "Usage Documentation"
674 [Model Validators](../concepts/validators.md#model-validators)
676 Decorate model methods for validation purposes.
678 Example usage:
679 ```python
680 from typing_extensions import Self
682 from pydantic import BaseModel, ValidationError, model_validator
684 class Square(BaseModel):
685 width: float
686 height: float
688 @model_validator(mode='after')
689 def verify_square(self) -> Self:
690 if self.width != self.height:
691 raise ValueError('width and height do not match')
692 return self
694 s = Square(width=1, height=1)
695 print(repr(s))
696 #> Square(width=1.0, height=1.0)
698 try:
699 Square(width=1, height=2)
700 except ValidationError as e:
701 print(e)
702 '''
703 1 validation error for Square
704 Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict]
705 '''
706 ```
708 For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators).
710 Args:
711 mode: A required string literal that specifies the validation mode.
712 It can be one of the following: 'wrap', 'before', or 'after'.
714 Returns:
715 A decorator that can be used to decorate a function to be used as a model validator.
716 """
718 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
719 # auto apply the @classmethod decorator
720 f = _decorators.ensure_classmethod_based_on_signature(f) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
721 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
722 return _decorators.PydanticDescriptorProxy(f, dec_info) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
724 return dec 1ABopqrabcdnmCDstuvefghEFwxyzijkl
727AnyType = TypeVar('AnyType') 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
730if TYPE_CHECKING: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
731 # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this
732 InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence`
734else:
736 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
737 class InstanceOf: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
738 '''Generic type for annotating a type that is an instance of a given class.
740 Example:
741 ```python
742 from pydantic import BaseModel, InstanceOf
744 class Foo:
745 ...
747 class Bar(BaseModel):
748 foo: InstanceOf[Foo]
750 Bar(foo=Foo())
751 try:
752 Bar(foo=42)
753 except ValidationError as e:
754 print(e)
755 """
756 [
757 │ {
758 │ │ 'type': 'is_instance_of',
759 │ │ 'loc': ('foo',),
760 │ │ 'msg': 'Input should be an instance of Foo',
761 │ │ 'input': 42,
762 │ │ 'ctx': {'class': 'Foo'},
763 │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of'
764 │ }
765 ]
766 """
767 ```
768 '''
770 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
771 def __class_getitem__(cls, item: AnyType) -> AnyType: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
772 return Annotated[item, cls()] 1ABopqrabcdnmCDstuvefghEFwxyzijkl
774 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
775 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
776 from pydantic import PydanticSchemaGenerationError 1ABopqrabcdnmCDstuvefghEFwxyzijkl
778 # use the generic _origin_ as the second argument to isinstance when appropriate
779 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
781 try: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
782 # Try to generate the "standard" schema, which will be used when loading from JSON
783 original_schema = handler(source) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
784 except PydanticSchemaGenerationError: 1ABopqrabcdnmCDstuvefghEFwxyzijkl
785 # If that fails, just produce a schema that can validate from python
786 return instance_of_schema 1ABopqrabcdnmCDstuvefghEFwxyzijkl
787 else:
788 # Use the "original" approach to serialization
789 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
790 function=lambda v, h: h(v), schema=original_schema
791 )
792 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
794 __hash__ = object.__hash__ 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
797if TYPE_CHECKING: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
798 SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str]
799else:
801 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
802 class SkipValidation: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
803 """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be
804 skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`.
806 This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes,
807 and know that it is safe to skip validation for one or more of the fields.
809 Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations
810 may not have the expected effects. Therefore, when used, this annotation should generally be the final
811 annotation applied to a type.
812 """
814 def __class_getitem__(cls, item: Any) -> Any: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
815 return Annotated[item, SkipValidation()] 1ABopqrabcdnmCDstuvefghEFwxyzijkl
817 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
818 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl
819 original_schema = handler(source) 1ABopqrabcdnmCDstuvefghEFwxyzijkl
820 metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} 1ABopqrabcdnmCDstuvefghEFwxyzijkl
821 return core_schema.any_schema( 1ABopqrabcdnmCDstuvefghEFwxyzijkl
822 metadata=metadata,
823 serialization=core_schema.wrap_serializer_function_ser_schema(
824 function=lambda v, h: h(v), schema=original_schema
825 ),
826 )
828 __hash__ = object.__hash__ 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl