ai-content-maker/.venv/Lib/site-packages/pydantic/deprecated/class_validators.py

266 lines
10 KiB
Python

"""Old `@validator` and `@root_validator` function validators from V1."""
from __future__ import annotations as _annotations
from functools import partial, partialmethod
from types import FunctionType
from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union, overload
from warnings import warn
from typing_extensions import Literal, Protocol, TypeAlias, deprecated
from .._internal import _decorators, _decorators_v1
from ..errors import PydanticUserError
from ..warnings import PydanticDeprecatedSince20
_ALLOW_REUSE_WARNING_MESSAGE = '`allow_reuse` is deprecated and will be ignored; it should no longer be necessary'
if TYPE_CHECKING:
class _OnlyValueValidatorClsMethod(Protocol):
def __call__(self, __cls: Any, __value: Any) -> Any:
...
class _V1ValidatorWithValuesClsMethod(Protocol):
def __call__(self, __cls: Any, __value: Any, values: dict[str, Any]) -> Any:
...
class _V1ValidatorWithValuesKwOnlyClsMethod(Protocol):
def __call__(self, __cls: Any, __value: Any, *, values: dict[str, Any]) -> Any:
...
class _V1ValidatorWithKwargsClsMethod(Protocol):
def __call__(self, __cls: Any, **kwargs: Any) -> Any:
...
class _V1ValidatorWithValuesAndKwargsClsMethod(Protocol):
def __call__(self, __cls: Any, values: dict[str, Any], **kwargs: Any) -> Any:
...
class _V1RootValidatorClsMethod(Protocol):
def __call__(
self, __cls: Any, __values: _decorators_v1.RootValidatorValues
) -> _decorators_v1.RootValidatorValues:
...
V1Validator = Union[
_OnlyValueValidatorClsMethod,
_V1ValidatorWithValuesClsMethod,
_V1ValidatorWithValuesKwOnlyClsMethod,
_V1ValidatorWithKwargsClsMethod,
_V1ValidatorWithValuesAndKwargsClsMethod,
_decorators_v1.V1ValidatorWithValues,
_decorators_v1.V1ValidatorWithValuesKwOnly,
_decorators_v1.V1ValidatorWithKwargs,
_decorators_v1.V1ValidatorWithValuesAndKwargs,
]
V1RootValidator = Union[
_V1RootValidatorClsMethod,
_decorators_v1.V1RootValidatorFunction,
]
_PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]]
# Allow both a V1 (assumed pre=False) or V2 (assumed mode='after') validator
# We lie to type checkers and say we return the same thing we get
# but in reality we return a proxy object that _mostly_ behaves like the wrapped thing
_V1ValidatorType = TypeVar('_V1ValidatorType', V1Validator, _PartialClsOrStaticMethod)
_V1RootValidatorFunctionType = TypeVar(
'_V1RootValidatorFunctionType',
_decorators_v1.V1RootValidatorFunction,
_V1RootValidatorClsMethod,
_PartialClsOrStaticMethod,
)
else:
# See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915
# and https://youtrack.jetbrains.com/issue/PY-51428
DeprecationWarning = PydanticDeprecatedSince20
@deprecated(
'Pydantic V1 style `@validator` validators are deprecated.'
' You should migrate to Pydantic V2 style `@field_validator` validators,'
' see the migration guide for more details',
category=None,
)
def validator(
__field: str,
*fields: str,
pre: bool = False,
each_item: bool = False,
always: bool = False,
check_fields: bool | None = None,
allow_reuse: bool = False,
) -> Callable[[_V1ValidatorType], _V1ValidatorType]:
"""Decorate methods on the class indicating that they should be used to validate fields.
Args:
__field (str): The first field the validator should be called on; this is separate
from `fields` to ensure an error is raised if you don't pass at least one.
*fields (str): Additional field(s) the validator should be called on.
pre (bool, optional): Whether this validator should be called before the standard
validators (else after). Defaults to False.
each_item (bool, optional): For complex objects (sets, lists etc.) whether to validate
individual elements rather than the whole object. Defaults to False.
always (bool, optional): Whether this method and other validators should be called even if
the value is missing. Defaults to False.
check_fields (bool | None, optional): Whether to check that the fields actually exist on the model.
Defaults to None.
allow_reuse (bool, optional): Whether to track and raise an error if another validator refers to
the decorated function. Defaults to False.
Returns:
Callable: A decorator that can be used to decorate a
function to be used as a validator.
"""
warn(
'Pydantic V1 style `@validator` validators are deprecated.'
' You should migrate to Pydantic V2 style `@field_validator` validators,'
' see the migration guide for more details',
DeprecationWarning,
stacklevel=2,
)
if allow_reuse is True: # pragma: no cover
warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning)
fields = tuple((__field, *fields))
if isinstance(fields[0], FunctionType):
raise PydanticUserError(
'`@validator` should be used with fields and keyword arguments, not bare. '
"E.g. usage should be `@validator('<field_name>', ...)`",
code='validator-no-fields',
)
elif not all(isinstance(field, str) for field in fields):
raise PydanticUserError(
'`@validator` fields should be passed as separate string args. '
"E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`",
code='validator-invalid-fields',
)
mode: Literal['before', 'after'] = 'before' if pre is True else 'after'
def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]:
if _decorators.is_instance_method_from_sig(f):
raise PydanticUserError(
'`@validator` cannot be applied to instance methods', code='validator-instance-method'
)
# auto apply the @classmethod decorator
f = _decorators.ensure_classmethod_based_on_signature(f)
wrap = _decorators_v1.make_generic_v1_field_validator
validator_wrapper_info = _decorators.ValidatorDecoratorInfo(
fields=fields,
mode=mode,
each_item=each_item,
always=always,
check_fields=check_fields,
)
return _decorators.PydanticDescriptorProxy(f, validator_wrapper_info, shim=wrap)
return dec # type: ignore[return-value]
@overload
def root_validator(
*,
# if you don't specify `pre` the default is `pre=False`
# which means you need to specify `skip_on_failure=True`
skip_on_failure: Literal[True],
allow_reuse: bool = ...,
) -> Callable[
[_V1RootValidatorFunctionType],
_V1RootValidatorFunctionType,
]:
...
@overload
def root_validator(
*,
# if you specify `pre=True` then you don't need to specify
# `skip_on_failure`, in fact it is not allowed as an argument!
pre: Literal[True],
allow_reuse: bool = ...,
) -> Callable[
[_V1RootValidatorFunctionType],
_V1RootValidatorFunctionType,
]:
...
@overload
def root_validator(
*,
# if you explicitly specify `pre=False` then you
# MUST specify `skip_on_failure=True`
pre: Literal[False],
skip_on_failure: Literal[True],
allow_reuse: bool = ...,
) -> Callable[
[_V1RootValidatorFunctionType],
_V1RootValidatorFunctionType,
]:
...
@deprecated(
'Pydantic V1 style `@root_validator` validators are deprecated.'
' You should migrate to Pydantic V2 style `@model_validator` validators,'
' see the migration guide for more details',
category=None,
)
def root_validator(
*__args,
pre: bool = False,
skip_on_failure: bool = False,
allow_reuse: bool = False,
) -> Any:
"""Decorate methods on a model indicating that they should be used to validate (and perhaps
modify) data either before or after standard model parsing/validation is performed.
Args:
pre (bool, optional): Whether this validator should be called before the standard
validators (else after). Defaults to False.
skip_on_failure (bool, optional): Whether to stop validation and return as soon as a
failure is encountered. Defaults to False.
allow_reuse (bool, optional): Whether to track and raise an error if another validator
refers to the decorated function. Defaults to False.
Returns:
Any: A decorator that can be used to decorate a function to be used as a root_validator.
"""
warn(
'Pydantic V1 style `@root_validator` validators are deprecated.'
' You should migrate to Pydantic V2 style `@model_validator` validators,'
' see the migration guide for more details',
DeprecationWarning,
stacklevel=2,
)
if __args:
# Ensure a nice error is raised if someone attempts to use the bare decorator
return root_validator()(*__args) # type: ignore
if allow_reuse is True: # pragma: no cover
warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning)
mode: Literal['before', 'after'] = 'before' if pre is True else 'after'
if pre is False and skip_on_failure is not True:
raise PydanticUserError(
'If you use `@root_validator` with pre=False (the default) you MUST specify `skip_on_failure=True`.'
' Note that `@root_validator` is deprecated and should be replaced with `@model_validator`.',
code='root-validator-pre-skip',
)
wrap = partial(_decorators_v1.make_v1_generic_root_validator, pre=pre)
def dec(f: Callable[..., Any] | classmethod[Any, Any, Any] | staticmethod[Any, Any]) -> Any:
if _decorators.is_instance_method_from_sig(f):
raise TypeError('`@root_validator` cannot be applied to instance methods')
# auto apply the @classmethod decorator
res = _decorators.ensure_classmethod_based_on_signature(f)
dec_info = _decorators.RootValidatorDecoratorInfo(mode=mode)
return _decorators.PydanticDescriptorProxy(res, dec_info, shim=wrap)
return dec