Coverage for pydantic/class_validators.py: 100.00%
173 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-15 13:26 +0000
1import warnings 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
2from collections import ChainMap 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
3from functools import partial, partialmethod, wraps 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
4from itertools import chain 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
5from types import FunctionType 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
6from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Type, Union, overload 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
8from pydantic.errors import ConfigError 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
9from pydantic.typing import AnyCallable 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
10from pydantic.utils import ROOT_KEY, in_ipython 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
12if TYPE_CHECKING: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
13 from pydantic.typing import AnyClassMethod
16class Validator: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
17 __slots__ = 'func', 'pre', 'each_item', 'always', 'check_fields', 'skip_on_failure' 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
19 def __init__( 1abcdefghijklmnopqrstEFGHPQRSTUIuvwxyzABCD
20 self,
21 func: AnyCallable,
22 pre: bool = False,
23 each_item: bool = False,
24 always: bool = False,
25 check_fields: bool = False,
26 skip_on_failure: bool = False,
27 ):
28 self.func = func 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
29 self.pre = pre 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
30 self.each_item = each_item 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
31 self.always = always 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
32 self.check_fields = check_fields 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
33 self.skip_on_failure = skip_on_failure 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
36if TYPE_CHECKING: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
37 from inspect import Signature
39 from pydantic.config import BaseConfig
40 from pydantic.fields import ModelField
41 from pydantic.types import ModelOrDc
43 ValidatorCallable = Callable[[Optional[ModelOrDc], Any, Dict[str, Any], ModelField, Type[BaseConfig]], Any]
44 ValidatorsList = List[ValidatorCallable]
45 ValidatorListDict = Dict[str, List[Validator]]
47_FUNCS: Set[str] = set() 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
48VALIDATOR_CONFIG_KEY = '__validator_config__' 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
49ROOT_VALIDATOR_CONFIG_KEY = '__root_validator_config__' 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
52def validator( 1abcdefghijklmnopqrstEFGHPQRSTUIuvwxyzABCD
53 *fields: str,
54 pre: bool = False,
55 each_item: bool = False,
56 always: bool = False,
57 check_fields: bool = True,
58 whole: Optional[bool] = None,
59 allow_reuse: bool = False,
60) -> Callable[[AnyCallable], 'AnyClassMethod']:
61 """
62 Decorate methods on the class indicating that they should be used to validate fields
63 :param fields: which field(s) the method should be called on
64 :param pre: whether or not this validator should be called before the standard validators (else after)
65 :param each_item: for complex objects (sets, lists etc.) whether to validate individual elements rather than the
66 whole object
67 :param always: whether this method and other validators should be called even if the value is missing
68 :param check_fields: whether to check that the fields actually exist on the model
69 :param allow_reuse: whether to track and raise an error if another validator refers to the decorated function
70 """
71 if not fields: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
72 raise ConfigError('validator with no fields specified') 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
73 elif isinstance(fields[0], FunctionType): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
74 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
75 "validators should be used with fields and keyword arguments, not bare. " # noqa: Q000
76 "E.g. usage should be `@validator('<field_name>', ...)`"
77 )
78 elif not all(isinstance(field, str) for field in fields): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
79 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
80 "validator fields should be passed as separate string args. " # noqa: Q000
81 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`"
82 )
84 if whole is not None: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
85 warnings.warn( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
86 'The "whole" keyword argument is deprecated, use "each_item" (inverse meaning, default False) instead',
87 DeprecationWarning,
88 )
89 assert each_item is False, '"each_item" and "whole" conflict, remove "whole"' 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
90 each_item = not whole 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
92 def dec(f: AnyCallable) -> 'AnyClassMethod': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
93 f_cls = _prepare_validator(f, allow_reuse) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
94 setattr( 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
95 f_cls,
96 VALIDATOR_CONFIG_KEY,
97 (
98 fields,
99 Validator(func=f_cls.__func__, pre=pre, each_item=each_item, always=always, check_fields=check_fields),
100 ),
101 )
102 return f_cls 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
104 return dec 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
107@overload 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
108def root_validator(_func: AnyCallable) -> 'AnyClassMethod': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
109 ...
112@overload 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
113def root_validator( 1abcdefghijklmnopqrstEFGHPQRSTUIuvwxyzABCD
114 *, pre: bool = False, allow_reuse: bool = False, skip_on_failure: bool = False 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
115) -> Callable[[AnyCallable], 'AnyClassMethod']: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
116 ...
119def root_validator( 1abcdefghijklmnopqrstEFGHPQRSTUIuvwxyzABCD
120 _func: Optional[AnyCallable] = None, *, pre: bool = False, allow_reuse: bool = False, skip_on_failure: bool = False
121) -> Union['AnyClassMethod', Callable[[AnyCallable], 'AnyClassMethod']]:
122 """
123 Decorate methods on a model indicating that they should be used to validate (and perhaps modify) data either
124 before or after standard model parsing/validation is performed.
125 """
126 if _func: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
127 f_cls = _prepare_validator(_func, allow_reuse) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
128 setattr( 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
129 f_cls, ROOT_VALIDATOR_CONFIG_KEY, Validator(func=f_cls.__func__, pre=pre, skip_on_failure=skip_on_failure)
130 )
131 return f_cls 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
133 def dec(f: AnyCallable) -> 'AnyClassMethod': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
134 f_cls = _prepare_validator(f, allow_reuse) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
135 setattr( 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
136 f_cls, ROOT_VALIDATOR_CONFIG_KEY, Validator(func=f_cls.__func__, pre=pre, skip_on_failure=skip_on_failure)
137 )
138 return f_cls 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
140 return dec 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
143def _prepare_validator(function: AnyCallable, allow_reuse: bool) -> 'AnyClassMethod': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
144 """
145 Avoid validators with duplicated names since without this, validators can be overwritten silently
146 which generally isn't the intended behaviour, don't run in ipython (see #312) or if allow_reuse is False.
147 """
148 f_cls = function if isinstance(function, classmethod) else classmethod(function) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
149 if not in_ipython() and not allow_reuse: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
150 ref = ( 1abcdefghijklmnopqrstPQRSTUuvwxyzABCD
151 getattr(f_cls.__func__, '__module__', '<No __module__>')
152 + '.'
153 + getattr(f_cls.__func__, '__qualname__', f'<No __qualname__: id:{id(f_cls.__func__)}>')
154 )
155 if ref in _FUNCS: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
156 raise ConfigError(f'duplicate validator function "{ref}"; if this is intended, set `allow_reuse=True`') 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
157 _FUNCS.add(ref) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
158 return f_cls 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
161class ValidatorGroup: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
162 def __init__(self, validators: 'ValidatorListDict') -> None: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
163 self.validators = validators 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
164 self.used_validators = {'*'} 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
166 def get_validators(self, name: str) -> Optional[Dict[str, Validator]]: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
167 self.used_validators.add(name) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
168 validators = self.validators.get(name, []) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
169 if name != ROOT_KEY: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
170 validators += self.validators.get('*', []) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
171 if validators: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
172 return {getattr(v.func, '__name__', f'<No __name__: id:{id(v.func)}>'): v for v in validators} 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
173 else:
174 return None 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
176 def check_for_unused(self) -> None: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
177 unused_validators = set( 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
178 chain.from_iterable(
179 (
180 getattr(v.func, '__name__', f'<No __name__: id:{id(v.func)}>')
181 for v in self.validators[f]
182 if v.check_fields
183 )
184 for f in (self.validators.keys() - self.used_validators)
185 )
186 )
187 if unused_validators: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
188 fn = ', '.join(unused_validators) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
189 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
190 f"Validators defined with incorrect fields: {fn} " # noqa: Q000
191 f"(use check_fields=False if you're inheriting from the model and intended this)"
192 )
195def extract_validators(namespace: Dict[str, Any]) -> Dict[str, List[Validator]]: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
196 validators: Dict[str, List[Validator]] = {} 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
197 for var_name, value in namespace.items(): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
198 validator_config = getattr(value, VALIDATOR_CONFIG_KEY, None) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
199 if validator_config: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
200 fields, v = validator_config 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
201 for field in fields: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
202 if field in validators: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
203 validators[field].append(v) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
204 else:
205 validators[field] = [v] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
206 return validators 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
209def extract_root_validators(namespace: Dict[str, Any]) -> Tuple[List[AnyCallable], List[Tuple[bool, AnyCallable]]]: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
210 from inspect import signature 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
212 pre_validators: List[AnyCallable] = [] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
213 post_validators: List[Tuple[bool, AnyCallable]] = [] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
214 for name, value in namespace.items(): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
215 validator_config: Optional[Validator] = getattr(value, ROOT_VALIDATOR_CONFIG_KEY, None) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
216 if validator_config: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
217 sig = signature(validator_config.func) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
218 args = list(sig.parameters.keys()) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
219 if args[0] == 'self': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
220 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
221 f'Invalid signature for root validator {name}: {sig}, "self" not permitted as first argument, '
222 f'should be: (cls, values).'
223 )
224 if len(args) != 2: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
225 raise ConfigError(f'Invalid signature for root validator {name}: {sig}, should be: (cls, values).') 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
226 # check function signature
227 if validator_config.pre: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
228 pre_validators.append(validator_config.func) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
229 else:
230 post_validators.append((validator_config.skip_on_failure, validator_config.func)) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
231 return pre_validators, post_validators 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
234def inherit_validators(base_validators: 'ValidatorListDict', validators: 'ValidatorListDict') -> 'ValidatorListDict': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
235 for field, field_validators in base_validators.items(): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
236 if field not in validators: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
237 validators[field] = [] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
238 validators[field] += field_validators 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
239 return validators 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
242def make_generic_validator(validator: AnyCallable) -> 'ValidatorCallable': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
243 """
244 Make a generic function which calls a validator with the right arguments.
246 Unfortunately other approaches (eg. return a partial of a function that builds the arguments) is slow,
247 hence this laborious way of doing things.
249 It's done like this so validators don't all need **kwargs in their signature, eg. any combination of
250 the arguments "values", "fields" and/or "config" are permitted.
251 """
252 from inspect import signature 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
254 if not isinstance(validator, (partial, partialmethod)): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
255 # This should be the default case, so overhead is reduced
256 sig = signature(validator) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
257 args = list(sig.parameters.keys()) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
258 else:
259 # Fix the generated argument lists of partial methods
260 sig = signature(validator.func) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
261 args = [ 1abcdefghijklmnopqrstEFGHIuvwxyzABCD
262 k
263 for k in signature(validator.func).parameters.keys()
264 if k not in validator.args | validator.keywords.keys()
265 ]
267 first_arg = args.pop(0) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
268 if first_arg == 'self': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
269 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
270 f'Invalid signature for validator {validator}: {sig}, "self" not permitted as first argument, '
271 f'should be: (cls, value, values, config, field), "values", "config" and "field" are all optional.'
272 )
273 elif first_arg == 'cls': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
274 # assume the second argument is value
275 return wraps(validator)(_generic_validator_cls(validator, sig, set(args[1:]))) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
276 else:
277 # assume the first argument was value which has already been removed
278 return wraps(validator)(_generic_validator_basic(validator, sig, set(args))) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
281def prep_validators(v_funcs: Iterable[AnyCallable]) -> 'ValidatorsList': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
282 return [make_generic_validator(f) for f in v_funcs if f] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
285all_kwargs = {'values', 'field', 'config'} 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
288def _generic_validator_cls(validator: AnyCallable, sig: 'Signature', args: Set[str]) -> 'ValidatorCallable': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
289 # assume the first argument is value
290 has_kwargs = False 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
291 if 'kwargs' in args: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
292 has_kwargs = True 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
293 args -= {'kwargs'} 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
295 if not args.issubset(all_kwargs): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
296 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
297 f'Invalid signature for validator {validator}: {sig}, should be: '
298 f'(cls, value, values, config, field), "values", "config" and "field" are all optional.'
299 )
301 if has_kwargs: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
302 return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
303 elif args == set(): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
304 return lambda cls, v, values, field, config: validator(cls, v) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
305 elif args == {'values'}: 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
306 return lambda cls, v, values, field, config: validator(cls, v, values=values) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
307 elif args == {'field'}: 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
308 return lambda cls, v, values, field, config: validator(cls, v, field=field) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
309 elif args == {'config'}: 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
310 return lambda cls, v, values, field, config: validator(cls, v, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
311 elif args == {'values', 'field'}: 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
312 return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
313 elif args == {'values', 'config'}: 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
314 return lambda cls, v, values, field, config: validator(cls, v, values=values, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
315 elif args == {'field', 'config'}: 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
316 return lambda cls, v, values, field, config: validator(cls, v, field=field, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
317 else:
318 # args == {'values', 'field', 'config'}
319 return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
322def _generic_validator_basic(validator: AnyCallable, sig: 'Signature', args: Set[str]) -> 'ValidatorCallable': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
323 has_kwargs = False 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
324 if 'kwargs' in args: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
325 has_kwargs = True 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
326 args -= {'kwargs'} 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
328 if not args.issubset(all_kwargs): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
329 raise ConfigError( 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
330 f'Invalid signature for validator {validator}: {sig}, should be: '
331 f'(value, values, config, field), "values", "config" and "field" are all optional.'
332 )
334 if has_kwargs: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
335 return lambda cls, v, values, field, config: validator(v, values=values, field=field, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
336 elif args == set(): 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
337 return lambda cls, v, values, field, config: validator(v) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
338 elif args == {'values'}: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
339 return lambda cls, v, values, field, config: validator(v, values=values) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
340 elif args == {'field'}: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
341 return lambda cls, v, values, field, config: validator(v, field=field) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
342 elif args == {'config'}: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
343 return lambda cls, v, values, field, config: validator(v, config=config) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
344 elif args == {'values', 'field'}: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
345 return lambda cls, v, values, field, config: validator(v, values=values, field=field) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
346 elif args == {'values', 'config'}: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
347 return lambda cls, v, values, field, config: validator(v, values=values, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
348 elif args == {'field', 'config'}: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
349 return lambda cls, v, values, field, config: validator(v, field=field, config=config) 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
350 else:
351 # args == {'values', 'field', 'config'}
352 return lambda cls, v, values, field, config: validator(v, values=values, field=field, config=config) 1JKabcdefghijLMklmnopqrstEFGHINOuvwxyzABCD
355def gather_all_validators(type_: 'ModelOrDc') -> Dict[str, 'AnyClassMethod']: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
356 all_attributes = ChainMap(*[cls.__dict__ for cls in type_.__mro__]) # type: ignore[arg-type,var-annotated] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
357 return { 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD
358 k: v
359 for k, v in all_attributes.items()
360 if hasattr(v, VALIDATOR_CONFIG_KEY) or hasattr(v, ROOT_VALIDATOR_CONFIG_KEY)
361 }