Coverage for pydantic/functional_validators.py: 98.28%

127 statements  

« prev     ^ index     » next       coverage.py v7.5.4, created at 2024-07-03 19:29 +0000

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

2 

3from __future__ import annotations as _annotations 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

4 

5import dataclasses 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

6import sys 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

7from functools import partialmethod 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

8from types import FunctionType 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

9from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union, cast, overload 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

10 

11from pydantic_core import core_schema 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

12from pydantic_core import core_schema as _core_schema 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

13from typing_extensions import Annotated, Literal, TypeAlias 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

14 

15from . import GetCoreSchemaHandler as _GetCoreSchemaHandler 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

16from ._internal import _core_metadata, _decorators, _generics, _internal_dataclass 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

17from .annotated_handlers import GetCoreSchemaHandler 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

18from .errors import PydanticUserError 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

19 

20if sys.version_info < (3, 11): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

21 from typing_extensions import Protocol 1ABCDopnmEFGHstUVOPQRSIJKLwx

22else: 

23 from typing import Protocol 1qrabcduvefghTMNyzijkl

24 

25_inspect_validator = _decorators.inspect_validator 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

26 

27 

28@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

29class AfterValidator: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

30 """Usage docs: https://docs.pydantic.dev/2.8/concepts/validators/#annotated-validators 

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 ```py 

39 from typing_extensions 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 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

72 

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

74 schema = handler(source_type) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

76 if info_arg: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

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

79 else: 

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

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

82 

83 

84@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

85class BeforeValidator: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

86 """Usage docs: https://docs.pydantic.dev/2.8/concepts/validators/#annotated-validators 

87 

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

89 

90 Attributes: 

91 func: The validator function. 

92 

93 Example: 

94 ```py 

95 from typing_extensions import Annotated 

96 

97 from pydantic import BaseModel, BeforeValidator 

98 

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

100 

101 class Model(BaseModel): 

102 a: MyInt 

103 

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

105 #> 2 

106 

107 try: 

108 Model(a='a') 

109 except TypeError as e: 

110 print(e) 

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

112 ``` 

113 """ 

114 

115 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

116 

117 def __get_pydantic_core_schema__(self, source_type: Any, handler: _GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

118 schema = handler(source_type) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

119 info_arg = _inspect_validator(self.func, 'before') 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

120 if info_arg: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

121 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

122 return core_schema.with_info_before_validator_function(func, schema=schema, field_name=handler.field_name) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

123 else: 

124 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

125 return core_schema.no_info_before_validator_function(func, schema=schema) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

126 

127 

128@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

129class PlainValidator: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

130 """Usage docs: https://docs.pydantic.dev/2.8/concepts/validators/#annotated-validators 

131 

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

133 

134 Attributes: 

135 func: The validator function. 

136 

137 Example: 

138 ```py 

139 from typing_extensions import Annotated 

140 

141 from pydantic import BaseModel, PlainValidator 

142 

143 MyInt = Annotated[int, PlainValidator(lambda v: int(v) + 1)] 

144 

145 class Model(BaseModel): 

146 a: MyInt 

147 

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

149 #> 2 

150 ``` 

151 """ 

152 

153 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

154 

155 def __get_pydantic_core_schema__(self, source_type: Any, handler: _GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

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

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

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

160 # and abort any attempts to handle special serialization. 

161 from pydantic import PydanticSchemaGenerationError 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

162 

163 try: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

164 schema = handler(source_type) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

165 serialization = core_schema.wrap_serializer_function_ser_schema(function=lambda v, h: h(v), schema=schema) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

166 except PydanticSchemaGenerationError: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

167 serialization = None 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

168 

169 info_arg = _inspect_validator(self.func, 'plain') 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

170 if info_arg: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

171 func = cast(core_schema.WithInfoValidatorFunction, self.func) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

172 return core_schema.with_info_plain_validator_function( 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

173 func, field_name=handler.field_name, serialization=serialization 

174 ) 

175 else: 

176 func = cast(core_schema.NoInfoValidatorFunction, self.func) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

177 return core_schema.no_info_plain_validator_function(func, serialization=serialization) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

178 

179 

180@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

181class WrapValidator: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

182 """Usage docs: https://docs.pydantic.dev/2.8/concepts/validators/#annotated-validators 

183 

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

185 

186 Attributes: 

187 func: The validator function. 

188 

189 ```py 

190 from datetime import datetime 

191 

192 from typing_extensions import Annotated 

193 

194 from pydantic import BaseModel, ValidationError, WrapValidator 

195 

196 def validate_timestamp(v, handler): 

197 if v == 'now': 

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

199 return datetime.now() 

200 try: 

201 return handler(v) 

202 except ValidationError: 

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

204 return datetime(2000, 1, 1) 

205 

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

207 

208 class Model(BaseModel): 

209 a: MyTimestamp 

210 

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

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

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

214 #> 2000-01-01 00:00:00 

215 ``` 

216 """ 

217 

218 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

219 

220 def __get_pydantic_core_schema__(self, source_type: Any, handler: _GetCoreSchemaHandler) -> core_schema.CoreSchema: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

221 schema = handler(source_type) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

222 info_arg = _inspect_validator(self.func, 'wrap') 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

223 if info_arg: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

224 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

225 return core_schema.with_info_wrap_validator_function(func, schema=schema, field_name=handler.field_name) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

226 else: 

227 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

228 return core_schema.no_info_wrap_validator_function(func, schema=schema) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

229 

230 

231if TYPE_CHECKING: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

232 

233 class _OnlyValueValidatorClsMethod(Protocol): 

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

235 

236 class _V2ValidatorClsMethod(Protocol): 

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

238 

239 class _V2WrapValidatorClsMethod(Protocol): 

240 def __call__( 

241 self, 

242 cls: Any, 

243 value: Any, 

244 handler: _core_schema.ValidatorFunctionWrapHandler, 

245 info: _core_schema.ValidationInfo, 

246 /, 

247 ) -> Any: ... 

248 

249 _V2Validator = Union[ 

250 _V2ValidatorClsMethod, 

251 _core_schema.WithInfoValidatorFunction, 

252 _OnlyValueValidatorClsMethod, 

253 _core_schema.NoInfoValidatorFunction, 

254 ] 

255 

256 _V2WrapValidator = Union[ 

257 _V2WrapValidatorClsMethod, 

258 _core_schema.WithInfoWrapValidatorFunction, 

259 ] 

260 

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

262 

263 _V2BeforeAfterOrPlainValidatorType = TypeVar( 

264 '_V2BeforeAfterOrPlainValidatorType', 

265 _V2Validator, 

266 _PartialClsOrStaticMethod, 

267 ) 

268 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', _V2WrapValidator, _PartialClsOrStaticMethod) 

269 

270 

271@overload 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

272def field_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

273 field: str, 1abcdnmefghMNijkl

274 /, 

275 *fields: str, 1abcdnmefghMNijkl

276 mode: Literal['before', 'after', 'plain'] = ..., 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

277 check_fields: bool | None = ..., 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

278) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 1abcdnmefghMNijkl

279 

280 

281@overload 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

282def field_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

283 field: str, 1abcdnmefghMNijkl

284 /, 

285 *fields: str, 1abcdnmefghMNijkl

286 mode: Literal['wrap'], 1abcdnmefghMNijkl

287 check_fields: bool | None = ..., 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

288) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 1abcdnmefghMNijkl

289 

290 

291FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

292 

293 

294def field_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

295 field: str, 

296 /, 

297 *fields: str, 

298 mode: FieldValidatorModes = 'after', 

299 check_fields: bool | None = None, 

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

301 """Usage docs: https://docs.pydantic.dev/2.8/concepts/validators/#field-validators 

302 

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

304 

305 Example usage: 

306 ```py 

307 from typing import Any 

308 

309 from pydantic import ( 

310 BaseModel, 

311 ValidationError, 

312 field_validator, 

313 ) 

314 

315 class Model(BaseModel): 

316 a: str 

317 

318 @field_validator('a') 

319 @classmethod 

320 def ensure_foobar(cls, v: Any): 

321 if 'foobar' not in v: 

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

323 return v 

324 

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

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

327 

328 try: 

329 Model(a='snap') 

330 except ValidationError as exc_info: 

331 print(exc_info) 

332 ''' 

333 1 validation error for Model 

334 a 

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

336 ''' 

337 ``` 

338 

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

340 

341 Args: 

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

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

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

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

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

347 

348 Returns: 

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

350 

351 Raises: 

352 PydanticUserError: 

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

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

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

356 """ 

357 if isinstance(field, FunctionType): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

358 raise PydanticUserError( 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

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

361 code='validator-no-fields', 

362 ) 

363 fields = field, *fields 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

364 if not all(isinstance(field, str) for field in fields): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

365 raise PydanticUserError( 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

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

368 code='validator-invalid-fields', 

369 ) 

370 

371 def dec( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

373 ) -> _decorators.PydanticDescriptorProxy[Any]: 

374 if _decorators.is_instance_method_from_sig(f): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

375 raise PydanticUserError( 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

377 ) 

378 

379 # auto apply the @classmethod decorator 

380 f = _decorators.ensure_classmethod_based_on_signature(f) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

381 

382 dec_info = _decorators.FieldValidatorDecoratorInfo(fields=fields, mode=mode, check_fields=check_fields) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

383 return _decorators.PydanticDescriptorProxy(f, dec_info) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

384 

385 return dec 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

386 

387 

388_ModelType = TypeVar('_ModelType') 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

389_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

390 

391 

392class ModelWrapValidatorHandler(_core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

394 

395 def __call__( # noqa: D102 1ABCDopqrabcdEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

396 self, 

397 value: Any, 1abcdnmefghMNijkl

398 outer_location: str | int | None = None, 1opqrabcdnmstuvefghOPQRSTMNwxyzijkl

399 /, 

400 ) -> _ModelTypeCo: # pragma: no cover 1abcdnmefghMNijkl

401 ... 

402 

403 

404class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

405 """A @model_validator decorated function signature. 

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

407 """ 

408 

409 def __call__( # noqa: D102 409 ↛ exitline 409 didn't jump to the function exit1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

410 self, 

411 cls: type[_ModelType], 

412 # this can be a dict, a model instance 

413 # or anything else that gets passed to validate_python 

414 # thus validators _must_ handle all cases 

415 value: Any, 

416 handler: ModelWrapValidatorHandler[_ModelType], 

417 /, 

418 ) -> _ModelType: ... 

419 

420 

421class ModelWrapValidator(Protocol[_ModelType]): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

423 

424 def __call__( # noqa: D102 424 ↛ exitline 424 didn't jump to the function exit1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

425 self, 

426 cls: type[_ModelType], 

427 # this can be a dict, a model instance 

428 # or anything else that gets passed to validate_python 

429 # thus validators _must_ handle all cases 

430 value: Any, 

431 handler: ModelWrapValidatorHandler[_ModelType], 

432 info: _core_schema.ValidationInfo, 

433 /, 

434 ) -> _ModelType: ... 

435 

436 

437class FreeModelBeforeValidatorWithoutInfo(Protocol): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

438 """A @model_validator decorated function signature. 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

440 """ 

441 

442 def __call__( # noqa: D102 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

443 self, 

444 # this can be a dict, a model instance 

445 # or anything else that gets passed to validate_python 

446 # thus validators _must_ handle all cases 

447 value: Any, 1abcdnmefghMNijkl

448 /, 

449 ) -> Any: ... 1abcdnmefghMNijkl

450 

451 

452class ModelBeforeValidatorWithoutInfo(Protocol): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

453 """A @model_validator decorated function signature. 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

455 """ 

456 

457 def __call__( # noqa: D102 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

458 self, 

459 cls: Any, 1abcdnmefghMNijkl

460 # this can be a dict, a model instance 

461 # or anything else that gets passed to validate_python 

462 # thus validators _must_ handle all cases 

463 value: Any, 1abcdnmefghMNijkl

464 /, 

465 ) -> Any: ... 1abcdnmefghMNijkl

466 

467 

468class FreeModelBeforeValidator(Protocol): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

470 

471 def __call__( # noqa: D102 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

472 self, 

473 # this can be a dict, a model instance 

474 # or anything else that gets passed to validate_python 

475 # thus validators _must_ handle all cases 

476 value: Any, 1abcdnmefghMNijkl

477 info: _core_schema.ValidationInfo, 1abcdnmefghMNijkl

478 /, 

479 ) -> Any: ... 1abcdnmefghMNijkl

480 

481 

482class ModelBeforeValidator(Protocol): 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

484 

485 def __call__( # noqa: D102 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

486 self, 

487 cls: Any, 1abcdnmefghMNijkl

488 # this can be a dict, a model instance 

489 # or anything else that gets passed to validate_python 

490 # thus validators _must_ handle all cases 

491 value: Any, 1abcdnmefghMNijkl

492 info: _core_schema.ValidationInfo, 1abcdnmefghMNijkl

493 /, 

494 ) -> Any: ... 1abcdnmefghMNijkl

495 

496 

497ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

499have info argument. 

500""" 

501 

502ModelAfterValidator = Callable[[_ModelType, _core_schema.ValidationInfo], _ModelType] 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

504 

505_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

506_AnyModeBeforeValidator = Union[ 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

507 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

508] 

509_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

510 

511 

512@overload 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

513def model_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

514 *, 

515 mode: Literal['wrap'], 1abcdnmefghMNijkl

516) -> Callable[ 1abcdnmefghMNijkl

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

518]: ... 

519 

520 

521@overload 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

522def model_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

523 *, 

524 mode: Literal['before'], 1abcdnmefghMNijkl

525) -> Callable[ 1abcdnmefghMNijkl

526 [_AnyModeBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] 

527]: ... 

528 

529 

530@overload 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

531def model_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

532 *, 

533 mode: Literal['after'], 1abcdnmefghMNijkl

534) -> Callable[ 1abcdnmefghMNijkl

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

536]: ... 

537 

538 

539def model_validator( 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

540 *, 

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

542) -> Any: 

543 """Usage docs: https://docs.pydantic.dev/2.8/concepts/validators/#model-validators 

544 

545 Decorate model methods for validation purposes. 

546 

547 Example usage: 

548 ```py 

549 from typing_extensions import Self 

550 

551 from pydantic import BaseModel, ValidationError, model_validator 

552 

553 class Square(BaseModel): 

554 width: float 

555 height: float 

556 

557 @model_validator(mode='after') 

558 def verify_square(self) -> Self: 

559 if self.width != self.height: 

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

561 return self 

562 

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

564 print(repr(s)) 

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

566 

567 try: 

568 Square(width=1, height=2) 

569 except ValidationError as e: 

570 print(e) 

571 ''' 

572 1 validation error for Square 

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

574 ''' 

575 ``` 

576 

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

578 

579 Args: 

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

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

582 

583 Returns: 

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

585 """ 

586 

587 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

588 # auto apply the @classmethod decorator 

589 f = _decorators.ensure_classmethod_based_on_signature(f) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

590 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

591 return _decorators.PydanticDescriptorProxy(f, dec_info) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

592 

593 return dec 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

594 

595 

596AnyType = TypeVar('AnyType') 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

597 

598 

599if TYPE_CHECKING: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

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

602 

603else: 

604 

605 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

606 class InstanceOf: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

608 

609 Example: 

610 ```py 

611 from pydantic import BaseModel, InstanceOf 

612 

613 class Foo: 

614 ... 

615 

616 class Bar(BaseModel): 

617 foo: InstanceOf[Foo] 

618 

619 Bar(foo=Foo()) 

620 try: 

621 Bar(foo=42) 

622 except ValidationError as e: 

623 print(e) 

624 """ 

625 [ 

626 │ { 

627 │ │ 'type': 'is_instance_of', 

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

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

630 │ │ 'input': 42, 

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

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

633 │ } 

634 ] 

635 """ 

636 ``` 

637 ''' 

638 

639 @classmethod 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

640 def __class_getitem__(cls, item: AnyType) -> AnyType: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

641 return Annotated[item, cls()] 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

642 

643 @classmethod 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

645 from pydantic import PydanticSchemaGenerationError 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

646 

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

648 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

649 

650 try: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

652 original_schema = handler(source) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

653 except PydanticSchemaGenerationError: 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

655 return instance_of_schema 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

656 else: 

657 # Use the "original" approach to serialization 

658 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

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

660 ) 

661 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

662 

663 __hash__ = object.__hash__ 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

664 

665 

666if TYPE_CHECKING: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

668else: 

669 

670 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

671 class SkipValidation: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

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

674 

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

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

677 

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

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

680 annotation applied to a type. 

681 """ 

682 

683 def __class_getitem__(cls, item: Any) -> Any: 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

684 return Annotated[item, SkipValidation()] 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

685 

686 @classmethod 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl

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

688 original_schema = handler(source) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

689 metadata = _core_metadata.build_metadata_dict(js_annotation_functions=[lambda _c, h: h(original_schema)]) 1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

690 return core_schema.any_schema( 690 ↛ exitline 690 didn't jump to the function exit1ABCDopqrabcdnmEFGHstuvefghIJKLwxyzijkl

691 metadata=metadata, 

692 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

694 ), 

695 ) 

696 

697 __hash__ = object.__hash__ 1ABCDopqrabcdnmEFGHstuvefghUVOPQRSTMNIJKLwxyzijkl