Coverage for /pythoncovmergedfiles/medio/medio/src/pydantic/pydantic/decorators.py: 36%
167 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-27 07:38 +0000
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-27 07:38 +0000
1"""
2Public methods used as decorators within pydantic models and dataclasses.
3"""
5from __future__ import annotations as _annotations
7from functools import partial, partialmethod
8from types import FunctionType
9from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union, overload
10from warnings import warn
12from pydantic_core import core_schema as _core_schema
13from typing_extensions import Literal, Protocol, TypeAlias
15from ._internal import _decorators, _decorators_v1
16from .errors import PydanticUserError
18_ALLOW_REUSE_WARNING_MESSAGE = '`allow_reuse` is deprecated and will be ignored; it should no longer be necessary'
21if TYPE_CHECKING:
23 class _OnlyValueValidatorClsMethod(Protocol):
24 def __call__(self, __cls: Any, __value: Any) -> Any:
25 ...
27 class _V1ValidatorWithValuesClsMethod(Protocol):
28 def __call__(self, __cls: Any, __value: Any, values: dict[str, Any]) -> Any:
29 ...
31 class _V1ValidatorWithValuesKwOnlyClsMethod(Protocol):
32 def __call__(self, __cls: Any, __value: Any, *, values: dict[str, Any]) -> Any:
33 ...
35 class _V1ValidatorWithKwargsClsMethod(Protocol):
36 def __call__(self, __cls: Any, **kwargs: Any) -> Any:
37 ...
39 class _V1ValidatorWithValuesAndKwargsClsMethod(Protocol):
40 def __call__(self, __cls: Any, values: dict[str, Any], **kwargs: Any) -> Any:
41 ...
43 class _V2ValidatorClsMethod(Protocol):
44 def __call__(self, __cls: Any, __input_value: Any, __info: _core_schema.FieldValidationInfo) -> Any:
45 ...
47 class _V2WrapValidatorClsMethod(Protocol):
48 def __call__(
49 self,
50 __cls: Any,
51 __input_value: Any,
52 __validator: _core_schema.ValidatorFunctionWrapHandler,
53 __info: _core_schema.ValidationInfo,
54 ) -> Any:
55 ...
57 class _V1RootValidatorClsMethod(Protocol):
58 def __call__(
59 self, __cls: Any, __values: _decorators_v1.RootValidatorValues
60 ) -> _decorators_v1.RootValidatorValues:
61 ...
63 V1Validator = Union[
64 _OnlyValueValidatorClsMethod,
65 _V1ValidatorWithValuesClsMethod,
66 _V1ValidatorWithValuesKwOnlyClsMethod,
67 _V1ValidatorWithKwargsClsMethod,
68 _V1ValidatorWithValuesAndKwargsClsMethod,
69 _decorators_v1.V1ValidatorWithValues,
70 _decorators_v1.V1ValidatorWithValuesKwOnly,
71 _decorators_v1.V1ValidatorWithKwargs,
72 _decorators_v1.V1ValidatorWithValuesAndKwargs,
73 ]
75 V2Validator = Union[
76 _V2ValidatorClsMethod,
77 _core_schema.FieldValidatorFunction,
78 _OnlyValueValidatorClsMethod,
79 _core_schema.NoInfoValidatorFunction,
80 ]
82 V2WrapValidator = Union[
83 _V2WrapValidatorClsMethod,
84 _core_schema.GeneralWrapValidatorFunction,
85 _core_schema.FieldWrapValidatorFunction,
86 ]
88 V1RootValidator = Union[
89 _V1RootValidatorClsMethod,
90 _decorators_v1.V1RootValidatorFunction,
91 ]
93 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
95 # Allow both a V1 (assumed pre=False) or V2 (assumed mode='after') validator
96 # We lie to type checkers and say we return the same thing we get
97 # but in reality we return a proxy object that _mostly_ behaves like the wrapped thing
98 _V1ValidatorType = TypeVar('_V1ValidatorType', V1Validator, _PartialClsOrStaticMethod)
99 _V2BeforeAfterOrPlainValidatorType = TypeVar(
100 '_V2BeforeAfterOrPlainValidatorType',
101 V2Validator,
102 _PartialClsOrStaticMethod,
103 )
104 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', V2WrapValidator, _PartialClsOrStaticMethod)
105 _V1RootValidatorFunctionType = TypeVar(
106 '_V1RootValidatorFunctionType',
107 _decorators_v1.V1RootValidatorFunction,
108 _V1RootValidatorClsMethod,
109 _PartialClsOrStaticMethod,
110 )
113def validator(
114 __field: str,
115 *fields: str,
116 pre: bool = False,
117 each_item: bool = False,
118 always: bool = False,
119 check_fields: bool | None = None,
120 allow_reuse: bool = False,
121) -> Callable[[_V1ValidatorType], _V1ValidatorType]:
122 """
123 Decorate methods on the class indicating that they should be used to validate fields.
125 Args:
126 __field (str): The first field the validator should be called on; this is separate
127 from `fields` to ensure an error is raised if you don't pass at least one.
128 *fields (str): Additional field(s) the validator should be called on.
129 pre (bool, optional): Whether or not this validator should be called before the standard
130 validators (else after). Defaults to False.
131 each_item (bool, optional): For complex objects (sets, lists etc.) whether to validate
132 individual elements rather than the whole object. Defaults to False.
133 always (bool, optional): Whether this method and other validators should be called even if
134 the value is missing. Defaults to False.
135 check_fields (bool | None, optional): Whether to check that the fields actually exist on the model.
136 Defaults to None.
137 allow_reuse (bool, optional): Whether to track and raise an error if another validator refers to
138 the decorated function. Defaults to False.
140 Returns:
141 Callable: A decorator that can be used to decorate a
142 function to be used as a validator.
143 """
144 if allow_reuse is True: # pragma: no cover
145 warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning)
146 fields = tuple((__field, *fields))
147 if isinstance(fields[0], FunctionType):
148 raise PydanticUserError(
149 "validators should be used with fields and keyword arguments, not bare. "
150 "E.g. usage should be `@validator('<field_name>', ...)`",
151 code='validator-no-fields',
152 )
153 elif not all(isinstance(field, str) for field in fields):
154 raise PydanticUserError(
155 "validator fields should be passed as separate string args. "
156 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
157 code='validator-invalid-fields',
158 )
160 warn(
161 'Pydantic V1 style `@validator` validators are deprecated.'
162 ' You should migrate to Pydantic V2 style `@field_validator` validators,'
163 ' see the migration guide for more details',
164 DeprecationWarning,
165 stacklevel=2,
166 )
168 mode: Literal['before', 'after'] = 'before' if pre is True else 'after'
170 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]:
171 if _decorators.is_instance_method_from_sig(f):
172 raise PydanticUserError(
173 '`@validator` cannot be applied to instance methods', code='validator-instance-method'
174 )
175 # auto apply the @classmethod decorator
176 f = _decorators.ensure_classmethod_based_on_signature(f)
177 wrap = _decorators_v1.make_generic_v1_field_validator
178 validator_wrapper_info = _decorators.ValidatorDecoratorInfo(
179 fields=fields,
180 mode=mode,
181 each_item=each_item,
182 always=always,
183 check_fields=check_fields,
184 )
185 return _decorators.PydanticDescriptorProxy(f, validator_wrapper_info, shim=wrap)
187 return dec # type: ignore[return-value]
190@overload
191def field_validator(
192 __field: str,
193 *fields: str,
194 mode: Literal['before', 'after', 'plain'] = ...,
195 check_fields: bool | None = ...,
196) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]:
197 ...
200@overload
201def field_validator(
202 __field: str,
203 *fields: str,
204 mode: Literal['wrap'],
205 check_fields: bool | None = ...,
206) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]:
207 ...
210FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain']
213def field_validator(
214 __field: str,
215 *fields: str,
216 mode: FieldValidatorModes = 'after',
217 check_fields: bool | None = None,
218) -> Callable[[Any], Any]:
219 """
220 Decorate methods on the class indicating that they should be used to validate fields.
222 Args:
223 __field (str): The first field the field_validator should be called on; this is separate
224 from `fields` to ensure an error is raised if you don't pass at least one.
225 *fields (tuple): Additional field(s) the field_validator should be called on.
226 mode (FieldValidatorModes): Specifies whether to validate the fields before or after validation.
227 Defaults to 'after'.
228 check_fields (bool | None): If set to True, checks that the fields actually exist on the model.
229 Defaults to None.
231 Returns:
232 Callable: A decorator that can be used to decorate a function to be used as a field_validator.
233 """
234 if isinstance(__field, FunctionType):
235 raise PydanticUserError(
236 'field_validators should be used with fields and keyword arguments, not bare. '
237 "E.g. usage should be `@validator('<field_name>', ...)`",
238 code='validator-no-fields',
239 )
240 fields = __field, *fields
241 if not all(isinstance(field, str) for field in fields):
242 raise PydanticUserError(
243 'field_validator fields should be passed as separate string args. '
244 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
245 code='validator-invalid-fields',
246 )
248 def dec(
249 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any]
250 ) -> _decorators.PydanticDescriptorProxy[Any]:
251 if _decorators.is_instance_method_from_sig(f):
252 raise PydanticUserError(
253 '`@field_validator` cannot be applied to instance methods', code='validator-instance-method'
254 )
256 # auto apply the @classmethod decorator
257 f = _decorators.ensure_classmethod_based_on_signature(f)
259 dec_info = _decorators.FieldValidatorDecoratorInfo(fields=fields, mode=mode, check_fields=check_fields)
260 return _decorators.PydanticDescriptorProxy(f, dec_info)
262 return dec
265@overload
266def root_validator(
267 *,
268 # if you don't specify `pre` the default is `pre=False`
269 # which means you need to specify `skip_on_failure=True`
270 skip_on_failure: Literal[True],
271 allow_reuse: bool = ...,
272) -> Callable[[_V1RootValidatorFunctionType], _V1RootValidatorFunctionType,]:
273 ...
276@overload
277def root_validator(
278 *,
279 # if you specify `pre=True` then you don't need to specify
280 # `skip_on_failure`, in fact it is not allowed as an argument!
281 pre: Literal[True],
282 allow_reuse: bool = ...,
283) -> Callable[[_V1RootValidatorFunctionType], _V1RootValidatorFunctionType,]:
284 ...
287@overload
288def root_validator(
289 *,
290 # if you explicitly specify `pre=False` then you
291 # MUST specify `skip_on_failure=True`
292 pre: Literal[False],
293 skip_on_failure: Literal[True],
294 allow_reuse: bool = ...,
295) -> Callable[[_V1RootValidatorFunctionType], _V1RootValidatorFunctionType,]:
296 ...
299def root_validator(
300 *,
301 pre: bool = False,
302 skip_on_failure: bool = False,
303 allow_reuse: bool = False,
304) -> Any:
305 """
306 Decorate methods on a model indicating that they should be used to validate (and perhaps
307 modify) data either before or after standard model parsing/validation is performed.
309 Args:
310 pre (bool, optional): Whether or not this validator should be called before the standard
311 validators (else after). Defaults to False.
312 skip_on_failure (bool, optional): Whether to stop validation and return as soon as a
313 failure is encountered. Defaults to False.
314 allow_reuse (bool, optional): Whether to track and raise an error if another validator
315 refers to the decorated function. Defaults to False.
317 Returns:
318 Any: A decorator that can be used to decorate a function to be used as a root_validator.
319 """
320 if allow_reuse is True: # pragma: no cover
321 warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning)
322 mode: Literal['before', 'after'] = 'before' if pre is True else 'after'
323 if pre is False and skip_on_failure is not True:
324 raise PydanticUserError(
325 'If you use `@root_validator` with pre=False (the default) you MUST specify `skip_on_failure=True`.',
326 code='root-validator-pre-skip',
327 )
329 wrap = partial(_decorators_v1.make_v1_generic_root_validator, pre=pre)
331 def dec(f: Callable[..., Any] | classmethod[Any, Any, Any] | staticmethod[Any, Any]) -> Any:
332 if _decorators.is_instance_method_from_sig(f):
333 raise TypeError('`@root_validator` cannot be applied to instance methods')
334 # auto apply the @classmethod decorator
335 res = _decorators.ensure_classmethod_based_on_signature(f)
336 dec_info = _decorators.RootValidatorDecoratorInfo(mode=mode)
337 return _decorators.PydanticDescriptorProxy(res, dec_info, shim=wrap)
339 return dec
342if TYPE_CHECKING:
343 _PlainSerializationFunction = Union[_core_schema.SerializerFunction, _PartialClsOrStaticMethod]
345 _WrapSerializationFunction = Union[_core_schema.WrapSerializerFunction, _PartialClsOrStaticMethod]
347 _PlainSerializeMethodType = TypeVar('_PlainSerializeMethodType', bound=_PlainSerializationFunction)
348 _WrapSerializeMethodType = TypeVar('_WrapSerializeMethodType', bound=_WrapSerializationFunction)
351@overload
352def field_serializer(
353 __field: str,
354 *fields: str,
355 json_return_type: _core_schema.JsonReturnTypes | None = ...,
356 when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ...,
357 check_fields: bool | None = ...,
358) -> Callable[[_PlainSerializeMethodType], _PlainSerializeMethodType]:
359 ...
362@overload
363def field_serializer(
364 __field: str,
365 *fields: str,
366 mode: Literal['plain'],
367 json_return_type: _core_schema.JsonReturnTypes | None = ...,
368 when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ...,
369 check_fields: bool | None = ...,
370) -> Callable[[_PlainSerializeMethodType], _PlainSerializeMethodType]:
371 ...
374@overload
375def field_serializer(
376 __field: str,
377 *fields: str,
378 mode: Literal['wrap'],
379 json_return_type: _core_schema.JsonReturnTypes | None = ...,
380 when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ...,
381 check_fields: bool | None = ...,
382) -> Callable[[_WrapSerializeMethodType], _WrapSerializeMethodType]:
383 ...
386def field_serializer(
387 *fields: str,
388 mode: Literal['plain', 'wrap'] = 'plain',
389 json_return_type: _core_schema.JsonReturnTypes | None = None,
390 when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always',
391 check_fields: bool | None = None,
392) -> Callable[[Any], Any]:
393 """
394 Decorate methods on the class indicating that they should be used to serialize fields.
396 Four signatures are supported:
398 - `(self, value: Any, info: FieldSerializationInfo)`
399 - `(self, value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo)`
400 - `(value: Any, info: SerializationInfo)`
401 - `(value: Any, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)`
403 Args:
404 fields (str): Which field(s) the method should be called on.
405 mode (str): `plain` means the function will be called instead of the default serialization logic,
406 `wrap` means the function will be called with an argument to optionally call the
407 default serialization logic.
408 json_return_type (str): The type that the function returns if the serialization mode is JSON.
409 when_used (str): When the function should be called.
410 check_fields (bool): Whether to check that the fields actually exist on the model.
412 Returns:
413 Callable: A decorator that can be used to decorate a function to be used as a field serializer.
414 """
416 def dec(
417 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any]
418 ) -> _decorators.PydanticDescriptorProxy[Any]:
419 dec_info = _decorators.FieldSerializerDecoratorInfo(
420 fields=fields,
421 mode=mode,
422 json_return_type=json_return_type,
423 when_used=when_used,
424 check_fields=check_fields,
425 )
426 return _decorators.PydanticDescriptorProxy(f, dec_info)
428 return dec
431def model_serializer(
432 __f: Callable[..., Any] | None = None,
433 *,
434 mode: Literal['plain', 'wrap'] = 'plain',
435 json_return_type: _core_schema.JsonReturnTypes | None = None,
436) -> Callable[[Any], _decorators.PydanticDescriptorProxy[Any]] | _decorators.PydanticDescriptorProxy[Any]:
437 """
438 Decorate a function which will be called to serialize the model.
440 (`when_used` is not permitted here since it makes no sense.)
442 Args:
443 __f (Callable[..., Any] | None): The function to be decorated.
444 mode (Literal['plain', 'wrap']): The serialization mode. `'plain'` means the function will be called
445 instead of the default serialization logic, `'wrap'` means the function will be called with an argument
446 to optionally call the default serialization logic.
447 json_return_type (_core_schema.JsonReturnTypes | None): The type that the function returns if the
448 serialization mode is JSON.
450 Returns:
451 Callable: A decorator that can be used to decorate a function to be used as a model serializer.
452 """
454 def dec(f: Callable[..., Any]) -> _decorators.PydanticDescriptorProxy[Any]:
455 dec_info = _decorators.ModelSerializerDecoratorInfo(mode=mode, json_return_type=json_return_type)
456 return _decorators.PydanticDescriptorProxy(f, dec_info)
458 if __f is None:
459 return dec
460 else:
461 return dec(__f)
464ModelType = TypeVar('ModelType')
465ModelWrapValidatorHandler = Callable[[Any], ModelType]
468class ModelWrapValidatorWithoutInfo(Protocol):
469 def __call__(
470 self,
471 cls: type[ModelType],
472 # this can be a dict, a model instance
473 # or anything else that gets passed to validate_python
474 # thus validators _must_ handle all cases
475 __value: Any,
476 __handler: Callable[[Any], ModelType],
477 ) -> ModelType:
478 ...
481class ModelWrapValidator(Protocol):
482 def __call__(
483 self,
484 cls: type[ModelType],
485 # this can be a dict, a model instance
486 # or anything else that gets passed to validate_python
487 # thus validators _must_ handle all cases
488 __value: Any,
489 __handler: Callable[[Any], ModelType],
490 __info: _core_schema.ValidationInfo,
491 ) -> ModelType:
492 ...
495class ModelBeforeValidatorWithoutInfo(Protocol):
496 def __call__(
497 self,
498 cls: Any,
499 # this can be a dict, a model instance
500 # or anything else that gets passed to validate_python
501 # thus validators _must_ handle all cases
502 __value: Any,
503 ) -> Any:
504 ...
507class ModelBeforeValidator(Protocol):
508 def __call__(
509 self,
510 cls: Any,
511 # this can be a dict, a model instance
512 # or anything else that gets passed to validate_python
513 # thus validators _must_ handle all cases
514 __value: Any,
515 __info: _core_schema.ValidationInfo,
516 ) -> Any:
517 ...
520class ModelAfterValidatorWithoutInfo(Protocol):
521 @staticmethod
522 def __call__(
523 self: ModelType, # type: ignore
524 ) -> ModelType:
525 ...
528class ModelAfterValidator(Protocol):
529 @staticmethod
530 def __call__(
531 self: ModelType, # type: ignore
532 __info: _core_schema.ValidationInfo,
533 ) -> ModelType:
534 ...
537AnyModelWrapValidator = Union[ModelWrapValidator, ModelWrapValidatorWithoutInfo]
538AnyModeBeforeValidator = Union[ModelBeforeValidator, ModelBeforeValidatorWithoutInfo]
539AnyModeAfterValidator = Union[ModelAfterValidator, ModelAfterValidatorWithoutInfo]
542@overload
543def model_validator(
544 *,
545 mode: Literal['wrap'],
546) -> Callable[[AnyModelWrapValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]]:
547 ...
550@overload
551def model_validator(
552 *,
553 mode: Literal['before'],
554) -> Callable[[AnyModeBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]]:
555 ...
558@overload
559def model_validator(
560 *,
561 mode: Literal['after'],
562) -> Callable[[AnyModeAfterValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo]]:
563 ...
566def model_validator(
567 *,
568 mode: Literal['wrap', 'before', 'after'],
569) -> Any:
570 """
571 Decorate model methods for validation purposes.
573 Args:
574 mode (Literal['wrap', 'before', 'after']): A required string literal that specifies the validation mode.
575 It can be one of the following: 'wrap', 'before', or 'after'.
577 Returns:
578 Any: A decorator that can be used to decorate a function to be used as a model validator.
579 """
581 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]:
582 # auto apply the @classmethod decorator
583 f = _decorators.ensure_classmethod_based_on_signature(f)
584 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode)
585 return _decorators.PydanticDescriptorProxy(f, dec_info)
587 return dec