Coverage for pydantic/functional_validators.py: 98.84%

148 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-20 10: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 pydantic_core import core_schema as _core_schema 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

13from typing_extensions import Self, TypeAlias 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

14 

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

16from .annotated_handlers import GetCoreSchemaHandler 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

17from .errors import PydanticUserError 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

18 

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

20 from typing_extensions import Protocol 1DErsqpFGvwHIzA

21else: 

22 from typing import Protocol 1tuabcdexyfghijJBCklmno

23 

24_inspect_validator = _decorators.inspect_validator 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

25 

26 

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

28class AfterValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

72 

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

74 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

76 if info_arg: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

79 else: 

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

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

82 

83 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

86 

87 

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

89class BeforeValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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 used to generate the appropriate 

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

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

123 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

124 

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

126 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

127 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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') 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

134 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

136 return core_schema.with_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

137 func, 

138 schema=schema, 

139 json_schema_input_schema=input_schema, 

140 ) 

141 else: 

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

143 return core_schema.no_info_before_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

144 func, schema=schema, json_schema_input_schema=input_schema 

145 ) 

146 

147 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

149 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

150 func=decorator.func, 

151 json_schema_input_type=decorator.info.json_schema_input_type, 

152 ) 

153 

154 

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

156class PlainValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

157 """!!! abstract "Usage Documentation" 

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

159 

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

161 

162 !!! note 

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

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

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

166 

167 Attributes: 

168 func: The validator function. 

169 json_schema_input_type: The input type used to generate the appropriate 

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

171 

172 Example: 

173 ```python 

174 from typing import Annotated, Union 

175 

176 from pydantic import BaseModel, PlainValidator 

177 

178 MyInt = Annotated[ 

179 int, 

180 PlainValidator( 

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

182 ), 

183 ] 

184 

185 class Model(BaseModel): 

186 a: MyInt 

187 

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

189 #> 2 

190 

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

192 #> 2 

193 ``` 

194 

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

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

197 """ 

198 

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

200 json_schema_input_type: Any = Any 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

201 

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

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

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

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

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

207 # and abort any attempts to handle special serialization. 

208 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

209 

210 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

211 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

214 serialization = schema.get( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

215 'serialization', 

216 core_schema.wrap_serializer_function_ser_schema( 

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

218 schema=schema, 

219 return_schema=handler.generate_schema(source_type), 

220 ), 

221 ) 

222 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

223 serialization = None 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

224 

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

226 

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

228 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

230 return core_schema.with_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

231 func, 

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

233 json_schema_input_schema=input_schema, 

234 ) 

235 else: 

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

237 return core_schema.no_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

238 func, 

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

240 json_schema_input_schema=input_schema, 

241 ) 

242 

243 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

245 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

246 func=decorator.func, 

247 json_schema_input_type=decorator.info.json_schema_input_type, 

248 ) 

249 

250 

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

252class WrapValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

253 """!!! abstract "Usage Documentation" 

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

255 

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

257 

258 Attributes: 

259 func: The validator function. 

260 json_schema_input_type: The input type used to generate the appropriate 

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

262 

263 ```python 

264 from datetime import datetime 

265 from typing import Annotated 

266 

267 from pydantic import BaseModel, ValidationError, WrapValidator 

268 

269 def validate_timestamp(v, handler): 

270 if v == 'now': 

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

272 return datetime.now() 

273 try: 

274 return handler(v) 

275 except ValidationError: 

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

277 return datetime(2000, 1, 1) 

278 

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

280 

281 class Model(BaseModel): 

282 a: MyTimestamp 

283 

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

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

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

287 #> 2000-01-01 00:00:00 

288 ``` 

289 """ 

290 

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

292 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

293 

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

295 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

296 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

297 None 

298 if self.json_schema_input_type is PydanticUndefined 

299 else handler.generate_schema(self.json_schema_input_type) 

300 ) 

301 

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

303 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

305 return core_schema.with_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

306 func, 

307 schema=schema, 

308 json_schema_input_schema=input_schema, 

309 ) 

310 else: 

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

312 return core_schema.no_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

313 func, 

314 schema=schema, 

315 json_schema_input_schema=input_schema, 

316 ) 

317 

318 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

320 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

321 func=decorator.func, 

322 json_schema_input_type=decorator.info.json_schema_input_type, 

323 ) 

324 

325 

326if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

327 

328 class _OnlyValueValidatorClsMethod(Protocol): 

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

330 

331 class _V2ValidatorClsMethod(Protocol): 

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

333 

334 class _OnlyValueWrapValidatorClsMethod(Protocol): 

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

336 

337 class _V2WrapValidatorClsMethod(Protocol): 

338 def __call__( 

339 self, 

340 cls: Any, 

341 value: Any, 

342 handler: _core_schema.ValidatorFunctionWrapHandler, 

343 info: _core_schema.ValidationInfo, 

344 /, 

345 ) -> Any: ... 

346 

347 _V2Validator = Union[ 

348 _V2ValidatorClsMethod, 

349 _core_schema.WithInfoValidatorFunction, 

350 _OnlyValueValidatorClsMethod, 

351 _core_schema.NoInfoValidatorFunction, 

352 ] 

353 

354 _V2WrapValidator = Union[ 

355 _V2WrapValidatorClsMethod, 

356 _core_schema.WithInfoWrapValidatorFunction, 

357 _OnlyValueWrapValidatorClsMethod, 

358 _core_schema.NoInfoWrapValidatorFunction, 

359 ] 

360 

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

362 

363 _V2BeforeAfterOrPlainValidatorType = TypeVar( 

364 '_V2BeforeAfterOrPlainValidatorType', 

365 bound=Union[_V2Validator, _PartialClsOrStaticMethod], 

366 ) 

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

368 

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

370 

371 

372@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

373def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

374 field: str, 1abcdeqpfghijJklmno

375 /, 

376 *fields: str, 1abcdeqpfghijJklmno

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

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

379 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

381 

382 

383@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

384def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

385 field: str, 1abcdeqpfghijJklmno

386 /, 

387 *fields: str, 1abcdeqpfghijJklmno

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

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

390 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

392 

393 

394@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

395def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

396 field: str, 1abcdeqpfghijJklmno

397 /, 

398 *fields: str, 1abcdeqpfghijJklmno

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

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

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

402 

403 

404def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

405 field: str, 

406 /, 

407 *fields: str, 

408 mode: FieldValidatorModes = 'after', 

409 check_fields: bool | None = None, 

410 json_schema_input_type: Any = PydanticUndefined, 

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

412 """!!! abstract "Usage Documentation" 

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

414 

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

416 

417 Example usage: 

418 ```python 

419 from typing import Any 

420 

421 from pydantic import ( 

422 BaseModel, 

423 ValidationError, 

424 field_validator, 

425 ) 

426 

427 class Model(BaseModel): 

428 a: str 

429 

430 @field_validator('a') 

431 @classmethod 

432 def ensure_foobar(cls, v: Any): 

433 if 'foobar' not in v: 

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

435 return v 

436 

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

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

439 

440 try: 

441 Model(a='snap') 

442 except ValidationError as exc_info: 

443 print(exc_info) 

444 ''' 

445 1 validation error for Model 

446 a 

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

448 ''' 

449 ``` 

450 

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

452 

453 Args: 

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

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

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

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

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

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

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

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

462 

463 Returns: 

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

465 

466 Raises: 

467 PydanticUserError: 

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

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

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

471 """ 

472 if isinstance(field, FunctionType): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

473 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

476 code='validator-no-fields', 

477 ) 

478 

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

480 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

482 code='validator-input-type', 

483 ) 

484 

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

486 json_schema_input_type = Any 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

487 

488 fields = field, *fields 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

490 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

493 code='validator-invalid-fields', 

494 ) 

495 

496 def dec( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

498 ) -> _decorators.PydanticDescriptorProxy[Any]: 

499 if _decorators.is_instance_method_from_sig(f): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

500 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

502 ) 

503 

504 # auto apply the @classmethod decorator 

505 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

506 

507 dec_info = _decorators.FieldValidatorDecoratorInfo( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

508 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type 

509 ) 

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

511 

512 return dec 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

513 

514 

515_ModelType = TypeVar('_ModelType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

517 

518 

519class ModelWrapValidatorHandler(_core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

521 

522 def __call__( # noqa: D102 1DErstuabcdeFGvwxyfghijJHIzABCklmno

523 self, 

524 value: Any, 1abcdeqpfghijJklmno

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

526 /, 

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

528 ... 

529 

530 

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

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

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

534 """ 

535 

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

537 self, 

538 cls: type[_ModelType], 

539 # this can be a dict, a model instance 

540 # or anything else that gets passed to validate_python 

541 # thus validators _must_ handle all cases 

542 value: Any, 

543 handler: ModelWrapValidatorHandler[_ModelType], 

544 /, 

545 ) -> _ModelType: ... 

546 

547 

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

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

550 

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

552 self, 

553 cls: type[_ModelType], 

554 # this can be a dict, a model instance 

555 # or anything else that gets passed to validate_python 

556 # thus validators _must_ handle all cases 

557 value: Any, 

558 handler: ModelWrapValidatorHandler[_ModelType], 

559 info: _core_schema.ValidationInfo, 

560 /, 

561 ) -> _ModelType: ... 

562 

563 

564class FreeModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

567 """ 

568 

569 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

570 self, 

571 # this can be a dict, a model instance 

572 # or anything else that gets passed to validate_python 

573 # thus validators _must_ handle all cases 

574 value: Any, 1abcdeqpfghijJklmno

575 /, 

576 ) -> Any: ... 1abcdeqpfghijJklmno

577 

578 

579class ModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

582 """ 

583 

584 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

585 self, 

586 cls: Any, 1abcdeqpfghijJklmno

587 # this can be a dict, a model instance 

588 # or anything else that gets passed to validate_python 

589 # thus validators _must_ handle all cases 

590 value: Any, 1abcdeqpfghijJklmno

591 /, 

592 ) -> Any: ... 1abcdeqpfghijJklmno

593 

594 

595class FreeModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

597 

598 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

599 self, 

600 # this can be a dict, a model instance 

601 # or anything else that gets passed to validate_python 

602 # thus validators _must_ handle all cases 

603 value: Any, 1abcdeqpfghijJklmno

604 info: _core_schema.ValidationInfo, 1abcdeqpfghijJklmno

605 /, 

606 ) -> Any: ... 1abcdeqpfghijJklmno

607 

608 

609class ModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

611 

612 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

613 self, 

614 cls: Any, 1abcdeqpfghijJklmno

615 # this can be a dict, a model instance 

616 # or anything else that gets passed to validate_python 

617 # thus validators _must_ handle all cases 

618 value: Any, 1abcdeqpfghijJklmno

619 info: _core_schema.ValidationInfo, 1abcdeqpfghijJklmno

620 /, 

621 ) -> Any: ... 1abcdeqpfghijJklmno

622 

623 

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

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

626have info argument. 

627""" 

628 

629ModelAfterValidator = Callable[[_ModelType, _core_schema.ValidationInfo], _ModelType] 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

631 

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

633_AnyModelBeforeValidator = Union[ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

634 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

635] 

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

637 

638 

639@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

640def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

641 *, 

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

643) -> Callable[ 1abcdeqpfghijJklmno

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

645]: ... 

646 

647 

648@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

649def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

650 *, 

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

652) -> Callable[ 1abcdeqpfghijJklmno

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

654]: ... 

655 

656 

657@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

658def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

659 *, 

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

661) -> Callable[ 1abcdeqpfghijJklmno

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

663]: ... 

664 

665 

666def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

667 *, 

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

669) -> Any: 

670 """!!! abstract "Usage Documentation" 

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

672 

673 Decorate model methods for validation purposes. 

674 

675 Example usage: 

676 ```python 

677 from typing_extensions import Self 

678 

679 from pydantic import BaseModel, ValidationError, model_validator 

680 

681 class Square(BaseModel): 

682 width: float 

683 height: float 

684 

685 @model_validator(mode='after') 

686 def verify_square(self) -> Self: 

687 if self.width != self.height: 

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

689 return self 

690 

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

692 print(repr(s)) 

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

694 

695 try: 

696 Square(width=1, height=2) 

697 except ValidationError as e: 

698 print(e) 

699 ''' 

700 1 validation error for Square 

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

702 ''' 

703 ``` 

704 

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

706 

707 Args: 

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

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

710 

711 Returns: 

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

713 """ 

714 

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

716 # auto apply the @classmethod decorator 

717 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

720 

721 return dec 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

722 

723 

724AnyType = TypeVar('AnyType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

725 

726 

727if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

730 

731else: 

732 

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

734 class InstanceOf: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

736 

737 Example: 

738 ```python 

739 from pydantic import BaseModel, InstanceOf 

740 

741 class Foo: 

742 ... 

743 

744 class Bar(BaseModel): 

745 foo: InstanceOf[Foo] 

746 

747 Bar(foo=Foo()) 

748 try: 

749 Bar(foo=42) 

750 except ValidationError as e: 

751 print(e) 

752 """ 

753 [ 

754 │ { 

755 │ │ 'type': 'is_instance_of', 

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

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

758 │ │ 'input': 42, 

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

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

761 │ } 

762 ] 

763 """ 

764 ``` 

765 ''' 

766 

767 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

770 

771 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

773 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

774 

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

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

777 

778 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

780 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

781 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

783 return instance_of_schema 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

784 else: 

785 # Use the "original" approach to serialization 

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

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

788 ) 

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

790 

791 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

792 

793 

794if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

796else: 

797 

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

799 class SkipValidation: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

802 

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

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

805 

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

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

808 annotation applied to a type. 

809 """ 

810 

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

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

813 

814 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

816 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

818 return core_schema.any_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

819 metadata=metadata, 

820 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

822 ), 

823 ) 

824 

825 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno