Coverage for pydantic/functional_validators.py: 98.85%

148 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 08:39 +0000

1"""This module contains related classes and functions for validation.""" 

2 

3from __future__ import annotations as _annotations 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

4 

5import dataclasses 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

6import sys 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

7from functools import partialmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

8from types import FunctionType 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

9from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

10 

11from pydantic_core import PydanticUndefined, core_schema 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

12from typing_extensions import Self, TypeAlias 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

13 

14from ._internal import _decorators, _generics, _internal_dataclass 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

15from .annotated_handlers import GetCoreSchemaHandler 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

16from .errors import PydanticUserError 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

17 

18if sys.version_info < (3, 11): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

19 from typing_extensions import Protocol 1DErsqpFGvwHIzA

20else: 

21 from typing import Protocol 1tuabcdexyfghijJBCklmno

22 

23_inspect_validator = _decorators.inspect_validator 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

24 

25 

26@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

27class AfterValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

28 """!!! abstract "Usage Documentation" 

29 [field *after* validators](../concepts/validators.md#field-after-validator) 

30 

31 A metadata class that indicates that a validation should be applied **after** the inner validation logic. 

32 

33 Attributes: 

34 func: The validator function. 

35 

36 Example: 

37 ```python 

38 from typing import Annotated 

39 

40 from pydantic import AfterValidator, BaseModel, ValidationError 

41 

42 MyInt = Annotated[int, AfterValidator(lambda v: v + 1)] 

43 

44 class Model(BaseModel): 

45 a: MyInt 

46 

47 print(Model(a=1).a) 

48 #> 2 

49 

50 try: 

51 Model(a='a') 

52 except ValidationError as e: 

53 print(e.json(indent=2)) 

54 ''' 

55 [ 

56 { 

57 "type": "int_parsing", 

58 "loc": [ 

59 "a" 

60 ], 

61 "msg": "Input should be a valid integer, unable to parse string as an integer", 

62 "input": "a", 

63 "url": "https://errors.pydantic.dev/2/v/int_parsing" 

64 } 

65 ] 

66 ''' 

67 ``` 

68 """ 

69 

70 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

71 

72 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

73 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

74 info_arg = _inspect_validator(self.func, 'after') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

75 if info_arg: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

76 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

77 return core_schema.with_info_after_validator_function(func, schema=schema) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

78 else: 

79 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

80 return core_schema.no_info_after_validator_function(func, schema=schema) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

81 

82 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

83 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

84 return cls(func=decorator.func) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

85 

86 

87@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

88class BeforeValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

89 """!!! abstract "Usage Documentation" 

90 [field *before* validators](../concepts/validators.md#field-before-validator) 

91 

92 A metadata class that indicates that a validation should be applied **before** the inner validation logic. 

93 

94 Attributes: 

95 func: The validator function. 

96 json_schema_input_type: The input type used to generate the appropriate 

97 JSON Schema (in validation mode). The actual input type is `Any`. 

98 

99 Example: 

100 ```python 

101 from typing import Annotated 

102 

103 from pydantic import BaseModel, BeforeValidator 

104 

105 MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)] 

106 

107 class Model(BaseModel): 

108 a: MyInt 

109 

110 print(Model(a=1).a) 

111 #> 2 

112 

113 try: 

114 Model(a='a') 

115 except TypeError as e: 

116 print(e) 

117 #> can only concatenate str (not "int") to str 

118 ``` 

119 """ 

120 

121 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

122 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

123 

124 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

125 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

126 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

127 None 

128 if self.json_schema_input_type is PydanticUndefined 

129 else handler.generate_schema(self.json_schema_input_type) 

130 ) 

131 

132 info_arg = _inspect_validator(self.func, 'before') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

133 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

134 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

135 return core_schema.with_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

136 func, 

137 schema=schema, 

138 json_schema_input_schema=input_schema, 

139 ) 

140 else: 

141 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

142 return core_schema.no_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

143 func, schema=schema, json_schema_input_schema=input_schema 

144 ) 

145 

146 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

147 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

148 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

149 func=decorator.func, 

150 json_schema_input_type=decorator.info.json_schema_input_type, 

151 ) 

152 

153 

154@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

155class PlainValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

156 """!!! abstract "Usage Documentation" 

157 [field *plain* validators](../concepts/validators.md#field-plain-validator) 

158 

159 A metadata class that indicates that a validation should be applied **instead** of the inner validation logic. 

160 

161 !!! note 

162 Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`. 

163 You can now use the `json_schema_input_type` argument to specify the input type of the function 

164 to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details. 

165 

166 Attributes: 

167 func: The validator function. 

168 json_schema_input_type: The input type used to generate the appropriate 

169 JSON Schema (in validation mode). The actual input type is `Any`. 

170 

171 Example: 

172 ```python 

173 from typing import Annotated, Union 

174 

175 from pydantic import BaseModel, PlainValidator 

176 

177 def validate(v: object) -> int: 

178 if not isinstance(v, (int, str)): 

179 raise ValueError(f'Expected int or str, go {type(v)}') 

180 

181 return int(v) + 1 

182 

183 MyInt = Annotated[ 

184 int, 

185 PlainValidator(validate, json_schema_input_type=Union[str, int]), # (1)! 

186 ] 

187 

188 class Model(BaseModel): 

189 a: MyInt 

190 

191 print(Model(a='1').a) 

192 #> 2 

193 

194 print(Model(a=1).a) 

195 #> 2 

196 ``` 

197 

198 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema 

199 generator that in validation mode, the input type for the `a` field can be either a [`str`][] or an [`int`][]. 

200 """ 

201 

202 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

203 json_schema_input_type: Any = Any 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

204 

205 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

206 # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the 

207 # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper 

208 # serialization schema. To work around this for use cases that will not involve serialization, we simply 

209 # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema 

210 # and abort any attempts to handle special serialization. 

211 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

212 

213 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

214 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

215 # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence', 

216 # schema validation will fail. That's why we use 'type ignore' comments below. 

217 serialization = schema.get( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

218 'serialization', 

219 core_schema.wrap_serializer_function_ser_schema( 

220 function=lambda v, h: h(v), 

221 schema=schema, 

222 return_schema=handler.generate_schema(source_type), 

223 ), 

224 ) 

225 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

226 serialization = None 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

227 

228 input_schema = handler.generate_schema(self.json_schema_input_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

229 

230 info_arg = _inspect_validator(self.func, 'plain') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

231 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

232 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

233 return core_schema.with_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

234 func, 

235 serialization=serialization, # pyright: ignore[reportArgumentType] 

236 json_schema_input_schema=input_schema, 

237 ) 

238 else: 

239 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

240 return core_schema.no_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

241 func, 

242 serialization=serialization, # pyright: ignore[reportArgumentType] 

243 json_schema_input_schema=input_schema, 

244 ) 

245 

246 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

247 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

248 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

249 func=decorator.func, 

250 json_schema_input_type=decorator.info.json_schema_input_type, 

251 ) 

252 

253 

254@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

255class WrapValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

256 """!!! abstract "Usage Documentation" 

257 [field *wrap* validators](../concepts/validators.md#field-wrap-validator) 

258 

259 A metadata class that indicates that a validation should be applied **around** the inner validation logic. 

260 

261 Attributes: 

262 func: The validator function. 

263 json_schema_input_type: The input type used to generate the appropriate 

264 JSON Schema (in validation mode). The actual input type is `Any`. 

265 

266 ```python 

267 from datetime import datetime 

268 from typing import Annotated 

269 

270 from pydantic import BaseModel, ValidationError, WrapValidator 

271 

272 def validate_timestamp(v, handler): 

273 if v == 'now': 

274 # we don't want to bother with further validation, just return the new value 

275 return datetime.now() 

276 try: 

277 return handler(v) 

278 except ValidationError: 

279 # validation failed, in this case we want to return a default value 

280 return datetime(2000, 1, 1) 

281 

282 MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)] 

283 

284 class Model(BaseModel): 

285 a: MyTimestamp 

286 

287 print(Model(a='now').a) 

288 #> 2032-01-02 03:04:05.000006 

289 print(Model(a='invalid').a) 

290 #> 2000-01-01 00:00:00 

291 ``` 

292 """ 

293 

294 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

295 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

296 

297 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

298 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

299 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

300 None 

301 if self.json_schema_input_type is PydanticUndefined 

302 else handler.generate_schema(self.json_schema_input_type) 

303 ) 

304 

305 info_arg = _inspect_validator(self.func, 'wrap') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

306 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

307 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

308 return core_schema.with_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

309 func, 

310 schema=schema, 

311 json_schema_input_schema=input_schema, 

312 ) 

313 else: 

314 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

315 return core_schema.no_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

316 func, 

317 schema=schema, 

318 json_schema_input_schema=input_schema, 

319 ) 

320 

321 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

322 def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

323 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

324 func=decorator.func, 

325 json_schema_input_type=decorator.info.json_schema_input_type, 

326 ) 

327 

328 

329if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

330 

331 class _OnlyValueValidatorClsMethod(Protocol): 

332 def __call__(self, cls: Any, value: Any, /) -> Any: ... 

333 

334 class _V2ValidatorClsMethod(Protocol): 

335 def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo[Any], /) -> Any: ... 

336 

337 class _OnlyValueWrapValidatorClsMethod(Protocol): 

338 def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ... 

339 

340 class _V2WrapValidatorClsMethod(Protocol): 

341 def __call__( 

342 self, 

343 cls: Any, 

344 value: Any, 

345 handler: core_schema.ValidatorFunctionWrapHandler, 

346 info: core_schema.ValidationInfo[Any], 

347 /, 

348 ) -> Any: ... 

349 

350 _V2Validator = Union[ 

351 _V2ValidatorClsMethod, 

352 core_schema.WithInfoValidatorFunction, 

353 _OnlyValueValidatorClsMethod, 

354 core_schema.NoInfoValidatorFunction, 

355 ] 

356 

357 _V2WrapValidator = Union[ 

358 _V2WrapValidatorClsMethod, 

359 core_schema.WithInfoWrapValidatorFunction, 

360 _OnlyValueWrapValidatorClsMethod, 

361 core_schema.NoInfoWrapValidatorFunction, 

362 ] 

363 

364 _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]] 

365 

366 _V2BeforeAfterOrPlainValidatorType = TypeVar( 

367 '_V2BeforeAfterOrPlainValidatorType', 

368 bound=Union[_V2Validator, _PartialClsOrStaticMethod], 

369 ) 

370 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod]) 

371 

372FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

373 

374 

375@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

376def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

377 field: str, 1abcdeqpfghijJklmno

378 /, 

379 *fields: str, 1abcdeqpfghijJklmno

380 mode: Literal['wrap'], 1abcdeqpfghijJklmno

381 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

382 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

383) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 1abcdeqpfghijJklmno

384 

385 

386@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

387def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

388 field: str, 1abcdeqpfghijJklmno

389 /, 

390 *fields: str, 1abcdeqpfghijJklmno

391 mode: Literal['before', 'plain'], 1abcdeqpfghijJklmno

392 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

393 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

394) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdeqpfghijJklmno

395 

396 

397@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

398def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

399 field: str, 1abcdeqpfghijJklmno

400 /, 

401 *fields: str, 1abcdeqpfghijJklmno

402 mode: Literal['after'] = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

403 check_fields: bool | None = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

404) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdeqpfghijJklmno

405 

406 

407def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

408 field: str, 

409 /, 

410 *fields: str, 

411 mode: FieldValidatorModes = 'after', 

412 check_fields: bool | None = None, 

413 json_schema_input_type: Any = PydanticUndefined, 

414) -> Callable[[Any], Any]: 

415 """!!! abstract "Usage Documentation" 

416 [field validators](../concepts/validators.md#field-validators) 

417 

418 Decorate methods on the class indicating that they should be used to validate fields. 

419 

420 Example usage: 

421 ```python 

422 from typing import Any 

423 

424 from pydantic import ( 

425 BaseModel, 

426 ValidationError, 

427 field_validator, 

428 ) 

429 

430 class Model(BaseModel): 

431 a: str 

432 

433 @field_validator('a') 

434 @classmethod 

435 def ensure_foobar(cls, v: Any): 

436 if 'foobar' not in v: 

437 raise ValueError('"foobar" not found in a') 

438 return v 

439 

440 print(repr(Model(a='this is foobar good'))) 

441 #> Model(a='this is foobar good') 

442 

443 try: 

444 Model(a='snap') 

445 except ValidationError as exc_info: 

446 print(exc_info) 

447 ''' 

448 1 validation error for Model 

449 a 

450 Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str] 

451 ''' 

452 ``` 

453 

454 For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators). 

455 

456 Args: 

457 field: The first field the `field_validator` should be called on; this is separate 

458 from `fields` to ensure an error is raised if you don't pass at least one. 

459 *fields: Additional field(s) the `field_validator` should be called on. 

460 mode: Specifies whether to validate the fields before or after validation. 

461 check_fields: Whether to check that the fields actually exist on the model. 

462 json_schema_input_type: The input type of the function. This is only used to generate 

463 the appropriate JSON Schema (in validation mode) and can only specified 

464 when `mode` is either `'before'`, `'plain'` or `'wrap'`. 

465 

466 Returns: 

467 A decorator that can be used to decorate a function to be used as a field_validator. 

468 

469 Raises: 

470 PydanticUserError: 

471 - If `@field_validator` is used bare (with no fields). 

472 - If the args passed to `@field_validator` as fields are not strings. 

473 - If `@field_validator` applied to instance methods. 

474 """ 

475 if isinstance(field, FunctionType): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

476 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

477 '`@field_validator` should be used with fields and keyword arguments, not bare. ' 

478 "E.g. usage should be `@validator('<field_name>', ...)`", 

479 code='validator-no-fields', 

480 ) 

481 

482 if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

483 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

484 f"`json_schema_input_type` can't be used when mode is set to {mode!r}", 

485 code='validator-input-type', 

486 ) 

487 

488 if json_schema_input_type is PydanticUndefined and mode == 'plain': 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

489 json_schema_input_type = Any 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

490 

491 fields = field, *fields 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

492 if not all(isinstance(field, str) for field in fields): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

493 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

494 '`@field_validator` fields should be passed as separate string args. ' 

495 "E.g. usage should be `@validator('<field_name_1>', '<field_name_2>', ...)`", 

496 code='validator-invalid-fields', 

497 ) 

498 

499 def dec( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

500 f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any], 

501 ) -> _decorators.PydanticDescriptorProxy[Any]: 

502 if _decorators.is_instance_method_from_sig(f): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

503 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

504 '`@field_validator` cannot be applied to instance methods', code='validator-instance-method' 

505 ) 

506 

507 # auto apply the @classmethod decorator 

508 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

509 

510 dec_info = _decorators.FieldValidatorDecoratorInfo( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

511 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type 

512 ) 

513 return _decorators.PydanticDescriptorProxy(f, dec_info) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

514 

515 return dec 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

516 

517 

518_ModelType = TypeVar('_ModelType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

519_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

520 

521 

522class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

523 """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`.""" 

524 

525 def __call__( # noqa: D102 1DErstuabcdeFGvwxyfghijJHIzABCklmno

526 self, 

527 value: Any, 1abcdeqpfghijJklmno

528 outer_location: str | int | None = None, 1rstuabcdeqpvwxyfghijJzABCklmno

529 /, 

530 ) -> _ModelTypeCo: # pragma: no cover 1abcdeqpfghijJklmno

531 ... 

532 

533 

534class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

535 """A `@model_validator` decorated function signature. 

536 This is used when `mode='wrap'` and the function does not have info argument. 

537 """ 

538 

539 def __call__( # noqa: D102 539 ↛ exitline 539 didn't return from function '__call__' because 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

540 self, 

541 cls: type[_ModelType], 

542 # this can be a dict, a model instance 

543 # or anything else that gets passed to validate_python 

544 # thus validators _must_ handle all cases 

545 value: Any, 

546 handler: ModelWrapValidatorHandler[_ModelType], 

547 /, 

548 ) -> _ModelType: ... 

549 

550 

551class ModelWrapValidator(Protocol[_ModelType]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

552 """A `@model_validator` decorated function signature. This is used when `mode='wrap'`.""" 

553 

554 def __call__( # noqa: D102 554 ↛ exitline 554 didn't return from function '__call__' because 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

555 self, 

556 cls: type[_ModelType], 

557 # this can be a dict, a model instance 

558 # or anything else that gets passed to validate_python 

559 # thus validators _must_ handle all cases 

560 value: Any, 

561 handler: ModelWrapValidatorHandler[_ModelType], 

562 info: core_schema.ValidationInfo, 

563 /, 

564 ) -> _ModelType: ... 

565 

566 

567class FreeModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

568 """A `@model_validator` decorated function signature. 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

569 This is used when `mode='before'` and the function does not have info argument. 

570 """ 

571 

572 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

573 self, 

574 # this can be a dict, a model instance 

575 # or anything else that gets passed to validate_python 

576 # thus validators _must_ handle all cases 

577 value: Any, 1abcdeqpfghijJklmno

578 /, 

579 ) -> Any: ... 1abcdeqpfghijJklmno

580 

581 

582class ModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

583 """A `@model_validator` decorated function signature. 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

584 This is used when `mode='before'` and the function does not have info argument. 

585 """ 

586 

587 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

588 self, 

589 cls: Any, 1abcdeqpfghijJklmno

590 # this can be a dict, a model instance 

591 # or anything else that gets passed to validate_python 

592 # thus validators _must_ handle all cases 

593 value: Any, 1abcdeqpfghijJklmno

594 /, 

595 ) -> Any: ... 1abcdeqpfghijJklmno

596 

597 

598class FreeModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

599 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

600 

601 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

602 self, 

603 # this can be a dict, a model instance 

604 # or anything else that gets passed to validate_python 

605 # thus validators _must_ handle all cases 

606 value: Any, 1abcdeqpfghijJklmno

607 info: core_schema.ValidationInfo[Any], 1abcdeqpfghijJklmno

608 /, 

609 ) -> Any: ... 1abcdeqpfghijJklmno

610 

611 

612class ModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

613 """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

614 

615 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

616 self, 

617 cls: Any, 1abcdeqpfghijJklmno

618 # this can be a dict, a model instance 

619 # or anything else that gets passed to validate_python 

620 # thus validators _must_ handle all cases 

621 value: Any, 1abcdeqpfghijJklmno

622 info: core_schema.ValidationInfo[Any], 1abcdeqpfghijJklmno

623 /, 

624 ) -> Any: ... 1abcdeqpfghijJklmno

625 

626 

627ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

628"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not 1rstuabcdepvwxyfghijJzABCklmno

629have info argument. 

630""" 

631 

632ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

633"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" 1rstuabcdepvwxyfghijJzABCklmno

634 

635_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

636_AnyModelBeforeValidator = Union[ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

637 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

638] 

639_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

640 

641 

642@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

643def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

644 *, 

645 mode: Literal['wrap'], 1abcdeqpfghijJklmno

646) -> Callable[ 1abcdeqpfghijJklmno

647 [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] 

648]: ... 

649 

650 

651@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

652def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

653 *, 

654 mode: Literal['before'], 1abcdeqpfghijJklmno

655) -> Callable[ 1abcdeqpfghijJklmno

656 [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] 

657]: ... 

658 

659 

660@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

661def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

662 *, 

663 mode: Literal['after'], 1abcdeqpfghijJklmno

664) -> Callable[ 1abcdeqpfghijJklmno

665 [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] 

666]: ... 

667 

668 

669def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

670 *, 

671 mode: Literal['wrap', 'before', 'after'], 

672) -> Any: 

673 """!!! abstract "Usage Documentation" 

674 [Model Validators](../concepts/validators.md#model-validators) 

675 

676 Decorate model methods for validation purposes. 

677 

678 Example usage: 

679 ```python 

680 from typing_extensions import Self 

681 

682 from pydantic import BaseModel, ValidationError, model_validator 

683 

684 class Square(BaseModel): 

685 width: float 

686 height: float 

687 

688 @model_validator(mode='after') 

689 def verify_square(self) -> Self: 

690 if self.width != self.height: 

691 raise ValueError('width and height do not match') 

692 return self 

693 

694 s = Square(width=1, height=1) 

695 print(repr(s)) 

696 #> Square(width=1.0, height=1.0) 

697 

698 try: 

699 Square(width=1, height=2) 

700 except ValidationError as e: 

701 print(e) 

702 ''' 

703 1 validation error for Square 

704 Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict] 

705 ''' 

706 ``` 

707 

708 For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators). 

709 

710 Args: 

711 mode: A required string literal that specifies the validation mode. 

712 It can be one of the following: 'wrap', 'before', or 'after'. 

713 

714 Returns: 

715 A decorator that can be used to decorate a function to be used as a model validator. 

716 """ 

717 

718 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

719 # auto apply the @classmethod decorator (except for *after* validators, which should be instance methods): 

720 if mode != 'after': 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

721 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

722 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

723 return _decorators.PydanticDescriptorProxy(f, dec_info) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

724 

725 return dec 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

726 

727 

728AnyType = TypeVar('AnyType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

729 

730 

731if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

732 # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this 

733 InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence` 

734 

735else: 

736 

737 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

738 class InstanceOf: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

739 '''Generic type for annotating a type that is an instance of a given class. 

740 

741 Example: 

742 ```python 

743 from pydantic import BaseModel, InstanceOf 

744 

745 class Foo: 

746 ... 

747 

748 class Bar(BaseModel): 

749 foo: InstanceOf[Foo] 

750 

751 Bar(foo=Foo()) 

752 try: 

753 Bar(foo=42) 

754 except ValidationError as e: 

755 print(e) 

756 """ 

757 [ 

758 │ { 

759 │ │ 'type': 'is_instance_of', 

760 │ │ 'loc': ('foo',), 

761 │ │ 'msg': 'Input should be an instance of Foo', 

762 │ │ 'input': 42, 

763 │ │ 'ctx': {'class': 'Foo'}, 

764 │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of' 

765 │ } 

766 ] 

767 """ 

768 ``` 

769 ''' 

770 

771 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

772 def __class_getitem__(cls, item: AnyType) -> AnyType: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

773 return Annotated[item, cls()] 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

774 

775 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

776 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

777 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

778 

779 # use the generic _origin_ as the second argument to isinstance when appropriate 

780 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

781 

782 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

783 # Try to generate the "standard" schema, which will be used when loading from JSON 

784 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

785 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

786 # If that fails, just produce a schema that can validate from python 

787 return instance_of_schema 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

788 else: 

789 # Use the "original" approach to serialization 

790 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

791 function=lambda v, h: h(v), schema=original_schema 

792 ) 

793 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

794 

795 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

796 

797 

798if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

799 SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str] 

800else: 

801 

802 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

803 class SkipValidation: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

804 """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be 

805 skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`. 

806 

807 This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes, 

808 and know that it is safe to skip validation for one or more of the fields. 

809 

810 Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations 

811 may not have the expected effects. Therefore, when used, this annotation should generally be the final 

812 annotation applied to a type. 

813 """ 

814 

815 def __class_getitem__(cls, item: Any) -> Any: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

816 return Annotated[item, SkipValidation()] 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

817 

818 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

819 def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

820 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

821 metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

822 return core_schema.any_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

823 metadata=metadata, 

824 serialization=core_schema.wrap_serializer_function_ser_schema( 

825 function=lambda v, h: h(v), schema=original_schema 

826 ), 

827 ) 

828 

829 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno