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

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

7 

8from pydantic.errors import ConfigError 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

9from pydantic.typing import AnyCallable 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

10from pydantic.utils import ROOT_KEY, in_ipython 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

11 

12if TYPE_CHECKING: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

13 from pydantic.typing import AnyClassMethod 

14 

15 

16class Validator: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

17 __slots__ = 'func', 'pre', 'each_item', 'always', 'check_fields', 'skip_on_failure' 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

18 

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

34 

35 

36if TYPE_CHECKING: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

37 from inspect import Signature 

38 

39 from pydantic.config import BaseConfig 

40 from pydantic.fields import ModelField 

41 from pydantic.types import ModelOrDc 

42 

43 ValidatorCallable = Callable[[Optional[ModelOrDc], Any, Dict[str, Any], ModelField, Type[BaseConfig]], Any] 

44 ValidatorsList = List[ValidatorCallable] 

45 ValidatorListDict = Dict[str, List[Validator]] 

46 

47_FUNCS: Set[str] = set() 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

48VALIDATOR_CONFIG_KEY = '__validator_config__' 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

49ROOT_VALIDATOR_CONFIG_KEY = '__root_validator_config__' 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

50 

51 

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 ) 

83 

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

91 

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

103 

104 return dec 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

105 

106 

107@overload 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

108def root_validator(_func: AnyCallable) -> 'AnyClassMethod': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

109 ... 

110 

111 

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 ... 

117 

118 

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

132 

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

139 

140 return dec 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

141 

142 

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

159 

160 

161class ValidatorGroup: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

162 def __init__(self, validators: 'ValidatorListDict') -> None: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

163 self.validators = validators 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

164 self.used_validators = {'*'} 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

165 

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

175 

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 ) 

193 

194 

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

207 

208 

209def extract_root_validators(namespace: Dict[str, Any]) -> Tuple[List[AnyCallable], List[Tuple[bool, AnyCallable]]]: 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

210 from inspect import signature 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

211 

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

232 

233 

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

240 

241 

242def make_generic_validator(validator: AnyCallable) -> 'ValidatorCallable': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

243 """ 

244 Make a generic function which calls a validator with the right arguments. 

245 

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. 

248 

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

253 

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 ] 

266 

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

279 

280 

281def prep_validators(v_funcs: Iterable[AnyCallable]) -> 'ValidatorsList': 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

282 return [make_generic_validator(f) for f in v_funcs if f] 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

283 

284 

285all_kwargs = {'values', 'field', 'config'} 1JKabcdefghijLMklmnopqrstEFGHPQRSTUINOuvwxyzABCD

286 

287 

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

294 

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 ) 

300 

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

320 

321 

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

327 

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 ) 

333 

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

353 

354 

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 }