Coverage for pydantic/functional_validators.py: 98.83%

147 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-04 10:05 +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 MyInt = Annotated[ 

178 int, 

179 PlainValidator( 

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

181 ), 

182 ] 

183 

184 class Model(BaseModel): 

185 a: MyInt 

186 

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

188 #> 2 

189 

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

191 #> 2 

192 ``` 

193 

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

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

196 """ 

197 

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

199 json_schema_input_type: Any = Any 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

200 

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

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

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

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

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

206 # and abort any attempts to handle special serialization. 

207 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

208 

209 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

210 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

213 serialization = schema.get( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

214 'serialization', 

215 core_schema.wrap_serializer_function_ser_schema( 

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

217 schema=schema, 

218 return_schema=handler.generate_schema(source_type), 

219 ), 

220 ) 

221 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

222 serialization = None 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

223 

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

225 

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

227 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

229 return core_schema.with_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

230 func, 

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

232 json_schema_input_schema=input_schema, 

233 ) 

234 else: 

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

236 return core_schema.no_info_plain_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

237 func, 

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

239 json_schema_input_schema=input_schema, 

240 ) 

241 

242 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

244 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

245 func=decorator.func, 

246 json_schema_input_type=decorator.info.json_schema_input_type, 

247 ) 

248 

249 

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

251class WrapValidator: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

252 """!!! abstract "Usage Documentation" 

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

254 

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

256 

257 Attributes: 

258 func: The validator function. 

259 json_schema_input_type: The input type used to generate the appropriate 

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

261 

262 ```python 

263 from datetime import datetime 

264 from typing import Annotated 

265 

266 from pydantic import BaseModel, ValidationError, WrapValidator 

267 

268 def validate_timestamp(v, handler): 

269 if v == 'now': 

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

271 return datetime.now() 

272 try: 

273 return handler(v) 

274 except ValidationError: 

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

276 return datetime(2000, 1, 1) 

277 

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

279 

280 class Model(BaseModel): 

281 a: MyTimestamp 

282 

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

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

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

286 #> 2000-01-01 00:00:00 

287 ``` 

288 """ 

289 

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

291 json_schema_input_type: Any = PydanticUndefined 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

292 

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

294 schema = handler(source_type) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

295 input_schema = ( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

296 None 

297 if self.json_schema_input_type is PydanticUndefined 

298 else handler.generate_schema(self.json_schema_input_type) 

299 ) 

300 

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

302 if info_arg: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

304 return core_schema.with_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

305 func, 

306 schema=schema, 

307 json_schema_input_schema=input_schema, 

308 ) 

309 else: 

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

311 return core_schema.no_info_wrap_validator_function( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

312 func, 

313 schema=schema, 

314 json_schema_input_schema=input_schema, 

315 ) 

316 

317 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

319 return cls( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

320 func=decorator.func, 

321 json_schema_input_type=decorator.info.json_schema_input_type, 

322 ) 

323 

324 

325if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

326 

327 class _OnlyValueValidatorClsMethod(Protocol): 

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

329 

330 class _V2ValidatorClsMethod(Protocol): 

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

332 

333 class _OnlyValueWrapValidatorClsMethod(Protocol): 

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

335 

336 class _V2WrapValidatorClsMethod(Protocol): 

337 def __call__( 

338 self, 

339 cls: Any, 

340 value: Any, 

341 handler: core_schema.ValidatorFunctionWrapHandler, 

342 info: core_schema.ValidationInfo, 

343 /, 

344 ) -> Any: ... 

345 

346 _V2Validator = Union[ 

347 _V2ValidatorClsMethod, 

348 core_schema.WithInfoValidatorFunction, 

349 _OnlyValueValidatorClsMethod, 

350 core_schema.NoInfoValidatorFunction, 

351 ] 

352 

353 _V2WrapValidator = Union[ 

354 _V2WrapValidatorClsMethod, 

355 core_schema.WithInfoWrapValidatorFunction, 

356 _OnlyValueWrapValidatorClsMethod, 

357 core_schema.NoInfoWrapValidatorFunction, 

358 ] 

359 

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

361 

362 _V2BeforeAfterOrPlainValidatorType = TypeVar( 

363 '_V2BeforeAfterOrPlainValidatorType', 

364 bound=Union[_V2Validator, _PartialClsOrStaticMethod], 

365 ) 

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

367 

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

369 

370 

371@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

372def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

373 field: str, 1abcdeqpfghijJklmno

374 /, 

375 *fields: str, 1abcdeqpfghijJklmno

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

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

378 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

380 

381 

382@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

383def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

384 field: str, 1abcdeqpfghijJklmno

385 /, 

386 *fields: str, 1abcdeqpfghijJklmno

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

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

389 json_schema_input_type: Any = ..., 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

391 

392 

393@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

394def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

395 field: str, 1abcdeqpfghijJklmno

396 /, 

397 *fields: str, 1abcdeqpfghijJklmno

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

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

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

401 

402 

403def field_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

404 field: str, 

405 /, 

406 *fields: str, 

407 mode: FieldValidatorModes = 'after', 

408 check_fields: bool | None = None, 

409 json_schema_input_type: Any = PydanticUndefined, 

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

411 """!!! abstract "Usage Documentation" 

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

413 

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

415 

416 Example usage: 

417 ```python 

418 from typing import Any 

419 

420 from pydantic import ( 

421 BaseModel, 

422 ValidationError, 

423 field_validator, 

424 ) 

425 

426 class Model(BaseModel): 

427 a: str 

428 

429 @field_validator('a') 

430 @classmethod 

431 def ensure_foobar(cls, v: Any): 

432 if 'foobar' not in v: 

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

434 return v 

435 

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

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

438 

439 try: 

440 Model(a='snap') 

441 except ValidationError as exc_info: 

442 print(exc_info) 

443 ''' 

444 1 validation error for Model 

445 a 

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

447 ''' 

448 ``` 

449 

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

451 

452 Args: 

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

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

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

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

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

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

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

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

461 

462 Returns: 

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

464 

465 Raises: 

466 PydanticUserError: 

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

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

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

470 """ 

471 if isinstance(field, FunctionType): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

472 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

475 code='validator-no-fields', 

476 ) 

477 

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

479 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

481 code='validator-input-type', 

482 ) 

483 

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

485 json_schema_input_type = Any 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

486 

487 fields = field, *fields 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

489 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

492 code='validator-invalid-fields', 

493 ) 

494 

495 def dec( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

497 ) -> _decorators.PydanticDescriptorProxy[Any]: 

498 if _decorators.is_instance_method_from_sig(f): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

499 raise PydanticUserError( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

501 ) 

502 

503 # auto apply the @classmethod decorator 

504 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

505 

506 dec_info = _decorators.FieldValidatorDecoratorInfo( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

507 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type 

508 ) 

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

510 

511 return dec 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

512 

513 

514_ModelType = TypeVar('_ModelType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

516 

517 

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

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

520 

521 def __call__( # noqa: D102 1DErstuabcdeFGvwxyfghijJHIzABCklmno

522 self, 

523 value: Any, 1abcdeqpfghijJklmno

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

525 /, 

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

527 ... 

528 

529 

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

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

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

533 """ 

534 

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

536 self, 

537 cls: type[_ModelType], 

538 # this can be a dict, a model instance 

539 # or anything else that gets passed to validate_python 

540 # thus validators _must_ handle all cases 

541 value: Any, 

542 handler: ModelWrapValidatorHandler[_ModelType], 

543 /, 

544 ) -> _ModelType: ... 

545 

546 

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

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

549 

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

551 self, 

552 cls: type[_ModelType], 

553 # this can be a dict, a model instance 

554 # or anything else that gets passed to validate_python 

555 # thus validators _must_ handle all cases 

556 value: Any, 

557 handler: ModelWrapValidatorHandler[_ModelType], 

558 info: core_schema.ValidationInfo, 

559 /, 

560 ) -> _ModelType: ... 

561 

562 

563class FreeModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

566 """ 

567 

568 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

569 self, 

570 # this can be a dict, a model instance 

571 # or anything else that gets passed to validate_python 

572 # thus validators _must_ handle all cases 

573 value: Any, 1abcdeqpfghijJklmno

574 /, 

575 ) -> Any: ... 1abcdeqpfghijJklmno

576 

577 

578class ModelBeforeValidatorWithoutInfo(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

581 """ 

582 

583 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

584 self, 

585 cls: Any, 1abcdeqpfghijJklmno

586 # this can be a dict, a model instance 

587 # or anything else that gets passed to validate_python 

588 # thus validators _must_ handle all cases 

589 value: Any, 1abcdeqpfghijJklmno

590 /, 

591 ) -> Any: ... 1abcdeqpfghijJklmno

592 

593 

594class FreeModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

596 

597 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

598 self, 

599 # this can be a dict, a model instance 

600 # or anything else that gets passed to validate_python 

601 # thus validators _must_ handle all cases 

602 value: Any, 1abcdeqpfghijJklmno

603 info: core_schema.ValidationInfo, 1abcdeqpfghijJklmno

604 /, 

605 ) -> Any: ... 1abcdeqpfghijJklmno

606 

607 

608class ModelBeforeValidator(Protocol): 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

610 

611 def __call__( # noqa: D102 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

612 self, 

613 cls: Any, 1abcdeqpfghijJklmno

614 # this can be a dict, a model instance 

615 # or anything else that gets passed to validate_python 

616 # thus validators _must_ handle all cases 

617 value: Any, 1abcdeqpfghijJklmno

618 info: core_schema.ValidationInfo, 1abcdeqpfghijJklmno

619 /, 

620 ) -> Any: ... 1abcdeqpfghijJklmno

621 

622 

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

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

625have info argument. 

626""" 

627 

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

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

630 

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

632_AnyModelBeforeValidator = Union[ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

633 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

634] 

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

636 

637 

638@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

639def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

640 *, 

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

642) -> Callable[ 1abcdeqpfghijJklmno

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

644]: ... 

645 

646 

647@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

648def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

649 *, 

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

651) -> Callable[ 1abcdeqpfghijJklmno

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

653]: ... 

654 

655 

656@overload 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

657def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

658 *, 

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

660) -> Callable[ 1abcdeqpfghijJklmno

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

662]: ... 

663 

664 

665def model_validator( 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

666 *, 

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

668) -> Any: 

669 """!!! abstract "Usage Documentation" 

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

671 

672 Decorate model methods for validation purposes. 

673 

674 Example usage: 

675 ```python 

676 from typing_extensions import Self 

677 

678 from pydantic import BaseModel, ValidationError, model_validator 

679 

680 class Square(BaseModel): 

681 width: float 

682 height: float 

683 

684 @model_validator(mode='after') 

685 def verify_square(self) -> Self: 

686 if self.width != self.height: 

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

688 return self 

689 

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

691 print(repr(s)) 

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

693 

694 try: 

695 Square(width=1, height=2) 

696 except ValidationError as e: 

697 print(e) 

698 ''' 

699 1 validation error for Square 

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

701 ''' 

702 ``` 

703 

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

705 

706 Args: 

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

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

709 

710 Returns: 

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

712 """ 

713 

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

715 # auto apply the @classmethod decorator 

716 f = _decorators.ensure_classmethod_based_on_signature(f) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

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

719 

720 return dec 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

721 

722 

723AnyType = TypeVar('AnyType') 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

724 

725 

726if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

729 

730else: 

731 

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

733 class InstanceOf: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

735 

736 Example: 

737 ```python 

738 from pydantic import BaseModel, InstanceOf 

739 

740 class Foo: 

741 ... 

742 

743 class Bar(BaseModel): 

744 foo: InstanceOf[Foo] 

745 

746 Bar(foo=Foo()) 

747 try: 

748 Bar(foo=42) 

749 except ValidationError as e: 

750 print(e) 

751 """ 

752 [ 

753 │ { 

754 │ │ 'type': 'is_instance_of', 

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

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

757 │ │ 'input': 42, 

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

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

760 │ } 

761 ] 

762 """ 

763 ``` 

764 ''' 

765 

766 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

769 

770 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

772 from pydantic import PydanticSchemaGenerationError 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

773 

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

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

776 

777 try: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

779 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

780 except PydanticSchemaGenerationError: 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

782 return instance_of_schema 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

783 else: 

784 # Use the "original" approach to serialization 

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

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

787 ) 

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

789 

790 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

791 

792 

793if TYPE_CHECKING: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

795else: 

796 

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

798 class SkipValidation: 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

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

801 

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

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

804 

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

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

807 annotation applied to a type. 

808 """ 

809 

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

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

812 

813 @classmethod 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno

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

815 original_schema = handler(source) 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

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

817 return core_schema.any_schema( 1DErstuabcdeqpFGvwxyfghijHIzABCklmno

818 metadata=metadata, 

819 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

821 ), 

822 ) 

823 

824 __hash__ = object.__hash__ 1DErstuabcdeqpFGvwxyfghijJHIzABCklmno