codekingpro/portable-devtools
114k
1"""Old `@validator` and `@root_validator` function validators from V1."""2 3from __future__ import annotations as _annotations4 5from functools import partial, partialmethod6from types import FunctionType7from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar, Union, overload8from warnings import warn9 10from typing_extensions import Protocol, TypeAlias, deprecated11 12from .._internal import _decorators, _decorators_v113from ..errors import PydanticUserError14from ..warnings import PydanticDeprecatedSince2015 16_ALLOW_REUSE_WARNING_MESSAGE = '`allow_reuse` is deprecated and will be ignored; it should no longer be necessary'17 18 19if TYPE_CHECKING:20 21 class _OnlyValueValidatorClsMethod(Protocol):22 def __call__(self, __cls: Any, __value: Any) -> Any: ...23 24 class _V1ValidatorWithValuesClsMethod(Protocol):25 def __call__(self, __cls: Any, __value: Any, values: dict[str, Any]) -> Any: ...26 27 class _V1ValidatorWithValuesKwOnlyClsMethod(Protocol):28 def __call__(self, __cls: Any, __value: Any, *, values: dict[str, Any]) -> Any: ...29 30 class _V1ValidatorWithKwargsClsMethod(Protocol):31 def __call__(self, __cls: Any, **kwargs: Any) -> Any: ...32 33 class _V1ValidatorWithValuesAndKwargsClsMethod(Protocol):34 def __call__(self, __cls: Any, values: dict[str, Any], **kwargs: Any) -> Any: ...35 36 class _V1RootValidatorClsMethod(Protocol):37 def __call__(38 self, __cls: Any, __values: _decorators_v1.RootValidatorValues39 ) -> _decorators_v1.RootValidatorValues: ...40 41 V1Validator = Union[42 _OnlyValueValidatorClsMethod,43 _V1ValidatorWithValuesClsMethod,44 _V1ValidatorWithValuesKwOnlyClsMethod,45 _V1ValidatorWithKwargsClsMethod,46 _V1ValidatorWithValuesAndKwargsClsMethod,47 _decorators_v1.V1ValidatorWithValues,48 _decorators_v1.V1ValidatorWithValuesKwOnly,49 _decorators_v1.V1ValidatorWithKwargs,50 _decorators_v1.V1ValidatorWithValuesAndKwargs,51 ]52 53 V1RootValidator = Union[54 _V1RootValidatorClsMethod,55 _decorators_v1.V1RootValidatorFunction,56 ]57 58 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]59 60 # Allow both a V1 (assumed pre=False) or V2 (assumed mode='after') validator61 # We lie to type checkers and say we return the same thing we get62 # but in reality we return a proxy object that _mostly_ behaves like the wrapped thing63 _V1ValidatorType = TypeVar('_V1ValidatorType', V1Validator, _PartialClsOrStaticMethod)64 _V1RootValidatorFunctionType = TypeVar(65 '_V1RootValidatorFunctionType',66 _decorators_v1.V1RootValidatorFunction,67 _V1RootValidatorClsMethod,68 _PartialClsOrStaticMethod,69 )70else:71 # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-2191572 # and https://youtrack.jetbrains.com/issue/PY-5142873 DeprecationWarning = PydanticDeprecatedSince2074 75 76@deprecated(77 'Pydantic V1 style `@validator` validators are deprecated.'78 ' You should migrate to Pydantic V2 style `@field_validator` validators,'79 ' see the migration guide for more details',80 category=None,81)82def validator(83 __field: str,84 *fields: str,85 pre: bool = False,86 each_item: bool = False,87 always: bool = False,88 check_fields: bool | None = None,89 allow_reuse: bool = False,90) -> Callable[[_V1ValidatorType], _V1ValidatorType]:91 """Decorate methods on the class indicating that they should be used to validate fields.92 93 Args:94 __field (str): The first field the validator should be called on; this is separate95 from `fields` to ensure an error is raised if you don't pass at least one.96 *fields (str): Additional field(s) the validator should be called on.97 pre (bool, optional): Whether this validator should be called before the standard98 validators (else after). Defaults to False.99 each_item (bool, optional): For complex objects (sets, lists etc.) whether to validate100 individual elements rather than the whole object. Defaults to False.101 always (bool, optional): Whether this method and other validators should be called even if102 the value is missing. Defaults to False.103 check_fields (bool | None, optional): Whether to check that the fields actually exist on the model.104 Defaults to None.105 allow_reuse (bool, optional): Whether to track and raise an error if another validator refers to106 the decorated function. Defaults to False.107 108 Returns:109 Callable: A decorator that can be used to decorate a110 function to be used as a validator.111 """112 warn(113 'Pydantic V1 style `@validator` validators are deprecated.'114 ' You should migrate to Pydantic V2 style `@field_validator` validators,'115 ' see the migration guide for more details',116 DeprecationWarning,117 stacklevel=2,118 )119 120 if allow_reuse is True: # pragma: no cover121 warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning, stacklevel=2)122 fields = __field, *fields123 if isinstance(fields[0], FunctionType):124 raise PydanticUserError(125 '`@validator` should be used with fields and keyword arguments, not bare. '126 "E.g. usage should be `@validator('<field_name>', ...)`",127 code='decorator-missing-arguments',128 )129 elif not all(isinstance(field, str) for field in fields):130 raise PydanticUserError(131 '`@validator` fields should be passed as separate string args. '132 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",133 code='decorator-invalid-fields',134 )135 136 mode: Literal['before', 'after'] = 'before' if pre is True else 'after'137 138 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]:139 if _decorators.is_instance_method_from_sig(f):140 raise PydanticUserError(141 '`@validator` cannot be applied to instance methods', code='validator-instance-method'142 )143 # auto apply the @classmethod decorator144 f = _decorators.ensure_classmethod_based_on_signature(f)145 wrap = _decorators_v1.make_generic_v1_field_validator146 validator_wrapper_info = _decorators.ValidatorDecoratorInfo(147 fields=fields,148 mode=mode,149 each_item=each_item,150 always=always,151 check_fields=check_fields,152 )153 return _decorators.PydanticDescriptorProxy(f, validator_wrapper_info, shim=wrap)154 155 return dec # type: ignore[return-value]156 157 158@overload159def root_validator(160 *,161 # if you don't specify `pre` the default is `pre=False`162 # which means you need to specify `skip_on_failure=True`163 skip_on_failure: Literal[True],164 allow_reuse: bool = ...,165) -> Callable[166 [_V1RootValidatorFunctionType],167 _V1RootValidatorFunctionType,168]: ...169 170 171@overload172def root_validator(173 *,174 # if you specify `pre=True` then you don't need to specify175 # `skip_on_failure`, in fact it is not allowed as an argument!176 pre: Literal[True],177 allow_reuse: bool = ...,178) -> Callable[179 [_V1RootValidatorFunctionType],180 _V1RootValidatorFunctionType,181]: ...182 183 184@overload185def root_validator(186 *,187 # if you explicitly specify `pre=False` then you188 # MUST specify `skip_on_failure=True`189 pre: Literal[False],190 skip_on_failure: Literal[True],191 allow_reuse: bool = ...,192) -> Callable[193 [_V1RootValidatorFunctionType],194 _V1RootValidatorFunctionType,195]: ...196 197 198@deprecated(199 'Pydantic V1 style `@root_validator` validators are deprecated.'200 ' You should migrate to Pydantic V2 style `@model_validator` validators,'201 ' see the migration guide for more details',202 category=None,203)204def root_validator(205 *__args,206 pre: bool = False,207 skip_on_failure: bool = False,208 allow_reuse: bool = False,209) -> Any:210 """Decorate methods on a model indicating that they should be used to validate (and perhaps211 modify) data either before or after standard model parsing/validation is performed.212 213 Args:214 pre (bool, optional): Whether this validator should be called before the standard215 validators (else after). Defaults to False.216 skip_on_failure (bool, optional): Whether to stop validation and return as soon as a217 failure is encountered. Defaults to False.218 allow_reuse (bool, optional): Whether to track and raise an error if another validator219 refers to the decorated function. Defaults to False.220 221 Returns:222 Any: A decorator that can be used to decorate a function to be used as a root_validator.223 """224 warn(225 'Pydantic V1 style `@root_validator` validators are deprecated.'226 ' You should migrate to Pydantic V2 style `@model_validator` validators,'227 ' see the migration guide for more details',228 DeprecationWarning,229 stacklevel=2,230 )231 232 if __args:233 # Ensure a nice error is raised if someone attempts to use the bare decorator234 return root_validator()(*__args) # type: ignore235 236 if allow_reuse is True: # pragma: no cover237 warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning, stacklevel=2)238 mode: Literal['before', 'after'] = 'before' if pre is True else 'after'239 if pre is False and skip_on_failure is not True:240 raise PydanticUserError(241 'If you use `@root_validator` with pre=False (the default) you MUST specify `skip_on_failure=True`.'242 ' Note that `@root_validator` is deprecated and should be replaced with `@model_validator`.',243 code='root-validator-pre-skip',244 )245 246 wrap = partial(_decorators_v1.make_v1_generic_root_validator, pre=pre)247 248 def dec(f: Callable[..., Any] | classmethod[Any, Any, Any] | staticmethod[Any, Any]) -> Any:249 if _decorators.is_instance_method_from_sig(f):250 raise TypeError('`@root_validator` cannot be applied to instance methods')251 # auto apply the @classmethod decorator252 res = _decorators.ensure_classmethod_based_on_signature(f)253 dec_info = _decorators.RootValidatorDecoratorInfo(mode=mode)254 return _decorators.PydanticDescriptorProxy(res, dec_info, shim=wrap)255 256 return dec257 