Coverage for pydantic/functional_validators.py: 98.84%

148 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-13 19:35 +0000

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

2 

3from __future__ import annotations as _annotations 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

4 

5import dataclasses 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

6import sys 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

7from functools import partialmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

8from types import FunctionType 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

10 

11from pydantic_core import PydanticUndefined, core_schema 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

12from pydantic_core import core_schema as _core_schema 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

13from typing_extensions import Self, TypeAlias 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

14 

15from ._internal import _decorators, _generics, _internal_dataclass 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

16from .annotated_handlers import GetCoreSchemaHandler 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

17from .errors import PydanticUserError 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

18 

19if sys.version_info < (3, 11): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

20 from typing_extensions import Protocol 1ABopnmCDstMKEFwx

21else: 

22 from typing import Protocol 1qrabcduvefghLGHIJyzijkl

23 

24_inspect_validator = _decorators.inspect_validator 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

25 

26 

27@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

28class AfterValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

29 """!!! abstract "Usage Documentation" 

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

31 

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

33 

34 Attributes: 

35 func: The validator function. 

36 

37 Example: 

38 ```python 

39 from typing import Annotated 

40 

41 from pydantic import AfterValidator, BaseModel, ValidationError 

42 

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

44 

45 class Model(BaseModel): 

46 a: MyInt 

47 

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

49 #> 2 

50 

51 try: 

52 Model(a='a') 

53 except ValidationError as e: 

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

55 ''' 

56 [ 

57 { 

58 "type": "int_parsing", 

59 "loc": [ 

60 "a" 

61 ], 

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

63 "input": "a", 

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

65 } 

66 ] 

67 ''' 

68 ``` 

69 """ 

70 

71 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

72 

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

74 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

75 info_arg = _inspect_validator(self.func, 'after') 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

76 if info_arg: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

77 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

78 return core_schema.with_info_after_validator_function(func, schema=schema, field_name=handler.field_name) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

79 else: 

80 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

81 return core_schema.no_info_after_validator_function(func, schema=schema) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

82 

83 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

85 return cls(func=decorator.func) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

86 

87 

88@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

89class BeforeValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

90 """!!! abstract "Usage Documentation" 

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

92 

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

94 

95 Attributes: 

96 func: The validator function. 

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

98 JSON Schema (in validation mode). 

99 

100 Example: 

101 ```python 

102 from typing import Annotated 

103 

104 from pydantic import BaseModel, BeforeValidator 

105 

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

107 

108 class Model(BaseModel): 

109 a: MyInt 

110 

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

112 #> 2 

113 

114 try: 

115 Model(a='a') 

116 except TypeError as e: 

117 print(e) 

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

119 ``` 

120 """ 

121 

122 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

123 json_schema_input_type: Any = PydanticUndefined 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

124 

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

126 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

127 input_schema = ( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

128 None 

129 if self.json_schema_input_type is PydanticUndefined 

130 else handler.generate_schema(self.json_schema_input_type) 

131 ) 

132 

133 info_arg = _inspect_validator(self.func, 'before') 1ABopqrabcdnmCDstuvefghEFwxyzijkl

134 if info_arg: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

135 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

136 return core_schema.with_info_before_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

137 func, 

138 schema=schema, 

139 field_name=handler.field_name, 

140 json_schema_input_schema=input_schema, 

141 ) 

142 else: 

143 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

144 return core_schema.no_info_before_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

145 func, schema=schema, json_schema_input_schema=input_schema 

146 ) 

147 

148 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

150 return cls( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

151 func=decorator.func, 

152 json_schema_input_type=decorator.info.json_schema_input_type, 

153 ) 

154 

155 

156@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

157class PlainValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

158 """!!! abstract "Usage Documentation" 

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

160 

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

162 

163 !!! note 

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

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

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

167 

168 Attributes: 

169 func: The validator function. 

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

171 JSON Schema (in validation mode). If not provided, will default to `Any`. 

172 

173 Example: 

174 ```python 

175 from typing import Annotated, Union 

176 

177 from pydantic import BaseModel, PlainValidator 

178 

179 MyInt = Annotated[ 

180 int, 

181 PlainValidator( 

182 lambda v: int(v) + 1, json_schema_input_type=Union[str, int] # (1)! 

183 ), 

184 ] 

185 

186 class Model(BaseModel): 

187 a: MyInt 

188 

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

190 #> 2 

191 

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

193 #> 2 

194 ``` 

195 

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

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

198 """ 

199 

200 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

201 json_schema_input_type: Any = Any 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

202 

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

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

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

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

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

208 # and abort any attempts to handle special serialization. 

209 from pydantic import PydanticSchemaGenerationError 1ABopqrabcdnmCDstuvefghEFwxyzijkl

210 

211 try: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

212 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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

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

215 serialization = schema.get( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

216 'serialization', 

217 core_schema.wrap_serializer_function_ser_schema( 

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

219 schema=schema, 

220 return_schema=handler.generate_schema(source_type), 

221 ), 

222 ) 

223 except PydanticSchemaGenerationError: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

224 serialization = None 1ABopqrabcdnmCDstuvefghEFwxyzijkl

225 

226 input_schema = handler.generate_schema(self.json_schema_input_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

227 

228 info_arg = _inspect_validator(self.func, 'plain') 1ABopqrabcdnmCDstuvefghEFwxyzijkl

229 if info_arg: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

230 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

231 return core_schema.with_info_plain_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

232 func, 

233 field_name=handler.field_name, 

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

235 json_schema_input_schema=input_schema, 

236 ) 

237 else: 

238 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

239 return core_schema.no_info_plain_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

240 func, 

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

242 json_schema_input_schema=input_schema, 

243 ) 

244 

245 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

247 return cls( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

248 func=decorator.func, 

249 json_schema_input_type=decorator.info.json_schema_input_type, 

250 ) 

251 

252 

253@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

254class WrapValidator: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

255 """!!! abstract "Usage Documentation" 

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

257 

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

259 

260 Attributes: 

261 func: The validator function. 

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

263 JSON Schema (in validation mode). 

264 

265 ```python 

266 from datetime import datetime 

267 from typing import Annotated 

268 

269 from pydantic import BaseModel, ValidationError, WrapValidator 

270 

271 def validate_timestamp(v, handler): 

272 if v == 'now': 

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

274 return datetime.now() 

275 try: 

276 return handler(v) 

277 except ValidationError: 

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

279 return datetime(2000, 1, 1) 

280 

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

282 

283 class Model(BaseModel): 

284 a: MyTimestamp 

285 

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

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

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

289 #> 2000-01-01 00:00:00 

290 ``` 

291 """ 

292 

293 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

294 json_schema_input_type: Any = PydanticUndefined 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

295 

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

297 schema = handler(source_type) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

298 input_schema = ( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

299 None 

300 if self.json_schema_input_type is PydanticUndefined 

301 else handler.generate_schema(self.json_schema_input_type) 

302 ) 

303 

304 info_arg = _inspect_validator(self.func, 'wrap') 1ABopqrabcdnmCDstuvefghEFwxyzijkl

305 if info_arg: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

306 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

307 return core_schema.with_info_wrap_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

308 func, 

309 schema=schema, 

310 field_name=handler.field_name, 

311 json_schema_input_schema=input_schema, 

312 ) 

313 else: 

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

315 return core_schema.no_info_wrap_validator_function( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

316 func, 

317 schema=schema, 

318 json_schema_input_schema=input_schema, 

319 ) 

320 

321 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

323 return cls( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

324 func=decorator.func, 

325 json_schema_input_type=decorator.info.json_schema_input_type, 

326 ) 

327 

328 

329if TYPE_CHECKING: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

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, 

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'] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

373 

374 

375@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

376def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

377 field: str, 1abcdnmefghGHIJijkl

378 /, 

379 *fields: str, 1abcdnmefghGHIJijkl

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

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

382 json_schema_input_type: Any = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

384 

385 

386@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

387def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

388 field: str, 1abcdnmefghGHIJijkl

389 /, 

390 *fields: str, 1abcdnmefghGHIJijkl

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

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

393 json_schema_input_type: Any = ..., 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

395 

396 

397@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

398def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

399 field: str, 1abcdnmefghGHIJijkl

400 /, 

401 *fields: str, 1abcdnmefghGHIJijkl

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

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

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

405 

406 

407def field_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

476 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

483 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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': 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

489 json_schema_input_type = Any 1ABopqrabcdnmCDstuvefghEFwxyzijkl

490 

491 fields = field, *fields 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

493 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

501 ) -> _decorators.PydanticDescriptorProxy[Any]: 

502 if _decorators.is_instance_method_from_sig(f): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

503 raise PydanticUserError( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

509 

510 dec_info = _decorators.FieldValidatorDecoratorInfo( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

514 

515 return dec 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

516 

517 

518_ModelType = TypeVar('_ModelType') 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

520 

521 

522class ModelWrapValidatorHandler(_core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

524 

525 def __call__( # noqa: D102 1ABopqrabcdCDstuvefghMKLGHIJEFwxyzijkl

526 self, 

527 value: Any, 1abcdnmefghGHIJijkl

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

529 /, 

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

531 ... 

532 

533 

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

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 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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]): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

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

570 """ 

571 

572 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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, 1abcdnmefghGHIJijkl

578 /, 

579 ) -> Any: ... 1abcdnmefghGHIJijkl

580 

581 

582class ModelBeforeValidatorWithoutInfo(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

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

585 """ 

586 

587 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

588 self, 

589 cls: Any, 1abcdnmefghGHIJijkl

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, 1abcdnmefghGHIJijkl

594 /, 

595 ) -> Any: ... 1abcdnmefghGHIJijkl

596 

597 

598class FreeModelBeforeValidator(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

600 

601 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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, 1abcdnmefghGHIJijkl

607 info: _core_schema.ValidationInfo, 1abcdnmefghGHIJijkl

608 /, 

609 ) -> Any: ... 1abcdnmefghGHIJijkl

610 

611 

612class ModelBeforeValidator(Protocol): 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

614 

615 def __call__( # noqa: D102 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

616 self, 

617 cls: Any, 1abcdnmefghGHIJijkl

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, 1abcdnmefghGHIJijkl

622 info: _core_schema.ValidationInfo, 1abcdnmefghGHIJijkl

623 /, 

624 ) -> Any: ... 1abcdnmefghGHIJijkl

625 

626 

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

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

629have info argument. 

630""" 

631 

632ModelAfterValidator = Callable[[_ModelType, _core_schema.ValidationInfo], _ModelType] 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

634 

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

636_AnyModelBeforeValidator = Union[ 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

637 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

638] 

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

640 

641 

642@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

643def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

644 *, 

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

646) -> Callable[ 1abcdnmefghGHIJijkl

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

648]: ... 

649 

650 

651@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

652def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

653 *, 

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

655) -> Callable[ 1abcdnmefghGHIJijkl

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

657]: ... 

658 

659 

660@overload 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

661def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

662 *, 

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

664) -> Callable[ 1abcdnmefghGHIJijkl

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

666]: ... 

667 

668 

669def model_validator( 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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]: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

719 # auto apply the @classmethod decorator 

720 f = _decorators.ensure_classmethod_based_on_signature(f) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

721 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

722 return _decorators.PydanticDescriptorProxy(f, dec_info) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

723 

724 return dec 1ABopqrabcdnmCDstuvefghEFwxyzijkl

725 

726 

727AnyType = TypeVar('AnyType') 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

728 

729 

730if TYPE_CHECKING: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

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

733 

734else: 

735 

736 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

737 class InstanceOf: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

739 

740 Example: 

741 ```python 

742 from pydantic import BaseModel, InstanceOf 

743 

744 class Foo: 

745 ... 

746 

747 class Bar(BaseModel): 

748 foo: InstanceOf[Foo] 

749 

750 Bar(foo=Foo()) 

751 try: 

752 Bar(foo=42) 

753 except ValidationError as e: 

754 print(e) 

755 """ 

756 [ 

757 │ { 

758 │ │ 'type': 'is_instance_of', 

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

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

761 │ │ 'input': 42, 

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

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

764 │ } 

765 ] 

766 """ 

767 ``` 

768 ''' 

769 

770 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

771 def __class_getitem__(cls, item: AnyType) -> AnyType: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

772 return Annotated[item, cls()] 1ABopqrabcdnmCDstuvefghEFwxyzijkl

773 

774 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

776 from pydantic import PydanticSchemaGenerationError 1ABopqrabcdnmCDstuvefghEFwxyzijkl

777 

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

779 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

780 

781 try: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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

783 original_schema = handler(source) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

784 except PydanticSchemaGenerationError: 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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

786 return instance_of_schema 1ABopqrabcdnmCDstuvefghEFwxyzijkl

787 else: 

788 # Use the "original" approach to serialization 

789 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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

791 ) 

792 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

793 

794 __hash__ = object.__hash__ 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

795 

796 

797if TYPE_CHECKING: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

799else: 

800 

801 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

802 class SkipValidation: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

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

805 

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

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

808 

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

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

811 annotation applied to a type. 

812 """ 

813 

814 def __class_getitem__(cls, item: Any) -> Any: 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

815 return Annotated[item, SkipValidation()] 1ABopqrabcdnmCDstuvefghEFwxyzijkl

816 

817 @classmethod 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl

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

819 original_schema = handler(source) 1ABopqrabcdnmCDstuvefghEFwxyzijkl

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

821 return core_schema.any_schema( 1ABopqrabcdnmCDstuvefghEFwxyzijkl

822 metadata=metadata, 

823 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

825 ), 

826 ) 

827 

828 __hash__ = object.__hash__ 1ABopqrabcdnmCDstuvefghMKLGHIJEFwxyzijkl