Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pydantic/functional_validators.py: 57%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

199 statements  

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

2 

3from __future__ import annotations as _annotations 

4 

5import dataclasses 

6import sys 

7import warnings 

8from functools import partialmethod 

9from types import FunctionType 

10from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 

11 

12from pydantic_core import PydanticUndefined, core_schema 

13from typing_extensions import Self, TypeAlias 

14 

15from ._internal import _decorators, _generics, _internal_dataclass 

16from .annotated_handlers import GetCoreSchemaHandler 

17from .errors import PydanticUserError 

18from .warnings import ArbitraryTypeWarning 

19 

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

21 from typing_extensions import Protocol 

22else: 

23 from typing import Protocol 

24 

25_inspect_validator = _decorators.inspect_validator 

26 

27 

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

29class AfterValidator: 

30 """!!! abstract "Usage Documentation" 

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

32 

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

34 

35 Attributes: 

36 func: The validator function. 

37 

38 Example: 

39 ```python 

40 from typing import Annotated 

41 

42 from pydantic import AfterValidator, BaseModel, ValidationError 

43 

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

45 

46 class Model(BaseModel): 

47 a: MyInt 

48 

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

50 #> 2 

51 

52 try: 

53 Model(a='a') 

54 except ValidationError as e: 

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

56 ''' 

57 [ 

58 { 

59 "type": "int_parsing", 

60 "loc": [ 

61 "a" 

62 ], 

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

64 "input": "a", 

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

66 } 

67 ] 

68 ''' 

69 ``` 

70 """ 

71 

72 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 

73 

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

75 schema = handler(source_type) 

76 info_arg = _inspect_validator(self.func, 'after') 

77 if info_arg: 

78 func = cast(core_schema.WithInfoValidatorFunction, self.func) 

79 return core_schema.with_info_after_validator_function(func, schema=schema) 

80 else: 

81 func = cast(core_schema.NoInfoValidatorFunction, self.func) 

82 return core_schema.no_info_after_validator_function(func, schema=schema) 

83 

84 @classmethod 

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

86 return cls(func=decorator.func) 

87 

88 

89@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 

90class BeforeValidator: 

91 """!!! abstract "Usage Documentation" 

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

93 

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

95 

96 Attributes: 

97 func: The validator function. 

98 json_schema_input_type: The input type used to generate the appropriate 

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

100 

101 Example: 

102 ```python 

103 from typing import Annotated 

104 

105 from pydantic import BaseModel, BeforeValidator 

106 

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

108 

109 class Model(BaseModel): 

110 a: MyInt 

111 

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

113 #> 2 

114 

115 try: 

116 Model(a='a') 

117 except TypeError as e: 

118 print(e) 

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

120 ``` 

121 """ 

122 

123 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 

124 json_schema_input_type: Any = PydanticUndefined 

125 

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

127 schema = handler(source_type) 

128 input_schema = ( 

129 None 

130 if self.json_schema_input_type is PydanticUndefined 

131 else handler.generate_schema(self.json_schema_input_type) 

132 ) 

133 

134 info_arg = _inspect_validator(self.func, 'before') 

135 if info_arg: 

136 func = cast(core_schema.WithInfoValidatorFunction, self.func) 

137 return core_schema.with_info_before_validator_function( 

138 func, 

139 schema=schema, 

140 json_schema_input_schema=input_schema, 

141 ) 

142 else: 

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

144 return core_schema.no_info_before_validator_function( 

145 func, schema=schema, json_schema_input_schema=input_schema 

146 ) 

147 

148 @classmethod 

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

150 return cls( 

151 func=decorator.func, 

152 json_schema_input_type=decorator.info.json_schema_input_type, 

153 ) 

154 

155 

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

157class PlainValidator: 

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

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

160 

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

162 

163 !!! note 

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

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

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

167 

168 Attributes: 

169 func: The validator function. 

170 json_schema_input_type: The input type used to generate the appropriate 

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

172 

173 Example: 

174 ```python 

175 from typing import Annotated, Union 

176 

177 from pydantic import BaseModel, PlainValidator 

178 

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

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

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

182 

183 return int(v) + 1 

184 

185 MyInt = Annotated[ 

186 int, 

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

188 ] 

189 

190 class Model(BaseModel): 

191 a: MyInt 

192 

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

194 #> 2 

195 

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

197 #> 2 

198 ``` 

199 

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

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

202 """ 

203 

204 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 

205 json_schema_input_type: Any = Any 

206 

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

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

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

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

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

212 # and abort any attempts to handle special serialization. 

213 from pydantic import PydanticSchemaGenerationError 

214 

215 try: 

216 schema = handler(source_type) 

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

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

219 serialization = schema.get( 

220 'serialization', 

221 core_schema.wrap_serializer_function_ser_schema( 

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

223 schema=schema, 

224 return_schema=handler.generate_schema(source_type), 

225 ), 

226 ) 

227 except PydanticSchemaGenerationError: 

228 serialization = None 

229 

230 input_schema = handler.generate_schema(self.json_schema_input_type) 

231 

232 info_arg = _inspect_validator(self.func, 'plain') 

233 if info_arg: 

234 func = cast(core_schema.WithInfoValidatorFunction, self.func) 

235 return core_schema.with_info_plain_validator_function( 

236 func, 

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

238 json_schema_input_schema=input_schema, 

239 ) 

240 else: 

241 func = cast(core_schema.NoInfoValidatorFunction, self.func) 

242 return core_schema.no_info_plain_validator_function( 

243 func, 

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

245 json_schema_input_schema=input_schema, 

246 ) 

247 

248 @classmethod 

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

250 return cls( 

251 func=decorator.func, 

252 json_schema_input_type=decorator.info.json_schema_input_type, 

253 ) 

254 

255 

256@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) 

257class WrapValidator: 

258 """!!! abstract "Usage Documentation" 

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

260 

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

262 

263 Attributes: 

264 func: The validator function. 

265 json_schema_input_type: The input type used to generate the appropriate 

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

267 

268 ```python 

269 from datetime import datetime 

270 from typing import Annotated 

271 

272 from pydantic import BaseModel, ValidationError, WrapValidator 

273 

274 def validate_timestamp(v, handler): 

275 if v == 'now': 

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

277 return datetime.now() 

278 try: 

279 return handler(v) 

280 except ValidationError: 

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

282 return datetime(2000, 1, 1) 

283 

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

285 

286 class Model(BaseModel): 

287 a: MyTimestamp 

288 

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

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

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

292 #> 2000-01-01 00:00:00 

293 ``` 

294 """ 

295 

296 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 

297 json_schema_input_type: Any = PydanticUndefined 

298 

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

300 schema = handler(source_type) 

301 input_schema = ( 

302 None 

303 if self.json_schema_input_type is PydanticUndefined 

304 else handler.generate_schema(self.json_schema_input_type) 

305 ) 

306 

307 info_arg = _inspect_validator(self.func, 'wrap') 

308 if info_arg: 

309 func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) 

310 return core_schema.with_info_wrap_validator_function( 

311 func, 

312 schema=schema, 

313 json_schema_input_schema=input_schema, 

314 ) 

315 else: 

316 func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) 

317 return core_schema.no_info_wrap_validator_function( 

318 func, 

319 schema=schema, 

320 json_schema_input_schema=input_schema, 

321 ) 

322 

323 @classmethod 

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

325 return cls( 

326 func=decorator.func, 

327 json_schema_input_type=decorator.info.json_schema_input_type, 

328 ) 

329 

330 

331if TYPE_CHECKING: 

332 

333 class _OnlyValueValidatorClsMethod(Protocol): 

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

335 

336 class _V2ValidatorClsMethod(Protocol): 

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

338 

339 class _OnlyValueWrapValidatorClsMethod(Protocol): 

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

341 

342 class _V2WrapValidatorClsMethod(Protocol): 

343 def __call__( 

344 self, 

345 cls: Any, 

346 value: Any, 

347 handler: core_schema.ValidatorFunctionWrapHandler, 

348 info: core_schema.ValidationInfo[Any], 

349 /, 

350 ) -> Any: ... 

351 

352 _V2Validator = Union[ 

353 _V2ValidatorClsMethod, 

354 core_schema.WithInfoValidatorFunction, 

355 _OnlyValueValidatorClsMethod, 

356 core_schema.NoInfoValidatorFunction, 

357 ] 

358 

359 _V2WrapValidator = Union[ 

360 _V2WrapValidatorClsMethod, 

361 core_schema.WithInfoWrapValidatorFunction, 

362 _OnlyValueWrapValidatorClsMethod, 

363 core_schema.NoInfoWrapValidatorFunction, 

364 ] 

365 

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

367 

368 _V2BeforeAfterOrPlainValidatorType = TypeVar( 

369 '_V2BeforeAfterOrPlainValidatorType', 

370 bound=Union[_V2Validator, _PartialClsOrStaticMethod], 

371 ) 

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

373 

374FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] 

375 

376 

377@overload 

378def field_validator( 

379 field: str, 

380 /, 

381 *fields: str, 

382 mode: Literal['wrap'], 

383 check_fields: bool | None = ..., 

384 json_schema_input_type: Any = ..., 

385) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... 

386 

387 

388@overload 

389def field_validator( 

390 field: str, 

391 /, 

392 *fields: str, 

393 mode: Literal['before', 'plain'], 

394 check_fields: bool | None = ..., 

395 json_schema_input_type: Any = ..., 

396) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 

397 

398 

399@overload 

400def field_validator( 

401 field: str, 

402 /, 

403 *fields: str, 

404 mode: Literal['after'] = ..., 

405 check_fields: bool | None = ..., 

406) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... 

407 

408 

409def field_validator( 

410 field: str, 

411 /, 

412 *fields: str, 

413 mode: FieldValidatorModes = 'after', 

414 check_fields: bool | None = None, 

415 json_schema_input_type: Any = PydanticUndefined, 

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

417 """!!! abstract "Usage Documentation" 

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

419 

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

421 

422 Example usage: 

423 ```python 

424 from typing import Any 

425 

426 from pydantic import ( 

427 BaseModel, 

428 ValidationError, 

429 field_validator, 

430 ) 

431 

432 class Model(BaseModel): 

433 a: str 

434 

435 @field_validator('a') 

436 @classmethod 

437 def ensure_foobar(cls, v: Any): 

438 if 'foobar' not in v: 

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

440 return v 

441 

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

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

444 

445 try: 

446 Model(a='snap') 

447 except ValidationError as exc_info: 

448 print(exc_info) 

449 ''' 

450 1 validation error for Model 

451 a 

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

453 ''' 

454 ``` 

455 

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

457 

458 Args: 

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

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

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

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

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

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

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

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

467 

468 Returns: 

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

470 

471 Raises: 

472 PydanticUserError: 

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

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

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

476 """ 

477 if isinstance(field, FunctionType): 

478 raise PydanticUserError( 

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

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

481 code='validator-no-fields', 

482 ) 

483 

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

485 raise PydanticUserError( 

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

487 code='validator-input-type', 

488 ) 

489 

490 if json_schema_input_type is PydanticUndefined and mode == 'plain': 

491 json_schema_input_type = Any 

492 

493 fields = field, *fields 

494 if not all(isinstance(field, str) for field in fields): 

495 raise PydanticUserError( 

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

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

498 code='validator-invalid-fields', 

499 ) 

500 

501 def dec( 

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

503 ) -> _decorators.PydanticDescriptorProxy[Any]: 

504 if _decorators.is_instance_method_from_sig(f): 

505 raise PydanticUserError( 

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

507 ) 

508 

509 # auto apply the @classmethod decorator 

510 f = _decorators.ensure_classmethod_based_on_signature(f) 

511 

512 dec_info = _decorators.FieldValidatorDecoratorInfo( 

513 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type 

514 ) 

515 return _decorators.PydanticDescriptorProxy(f, dec_info) 

516 

517 return dec 

518 

519 

520_ModelType = TypeVar('_ModelType') 

521_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) 

522 

523 

524class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): 

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

526 

527 def __call__( # noqa: D102 

528 self, 

529 value: Any, 

530 outer_location: str | int | None = None, 

531 /, 

532 ) -> _ModelTypeCo: # pragma: no cover 

533 ... 

534 

535 

536class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 

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

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

539 """ 

540 

541 def __call__( # noqa: D102 

542 self, 

543 cls: type[_ModelType], 

544 # this can be a dict, a model instance 

545 # or anything else that gets passed to validate_python 

546 # thus validators _must_ handle all cases 

547 value: Any, 

548 handler: ModelWrapValidatorHandler[_ModelType], 

549 /, 

550 ) -> _ModelType: ... 

551 

552 

553class ModelWrapValidator(Protocol[_ModelType]): 

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

555 

556 def __call__( # noqa: D102 

557 self, 

558 cls: type[_ModelType], 

559 # this can be a dict, a model instance 

560 # or anything else that gets passed to validate_python 

561 # thus validators _must_ handle all cases 

562 value: Any, 

563 handler: ModelWrapValidatorHandler[_ModelType], 

564 info: core_schema.ValidationInfo, 

565 /, 

566 ) -> _ModelType: ... 

567 

568 

569class FreeModelBeforeValidatorWithoutInfo(Protocol): 

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

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

572 """ 

573 

574 def __call__( # noqa: D102 

575 self, 

576 # this can be a dict, a model instance 

577 # or anything else that gets passed to validate_python 

578 # thus validators _must_ handle all cases 

579 value: Any, 

580 /, 

581 ) -> Any: ... 

582 

583 

584class ModelBeforeValidatorWithoutInfo(Protocol): 

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

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

587 """ 

588 

589 def __call__( # noqa: D102 

590 self, 

591 cls: Any, 

592 # this can be a dict, a model instance 

593 # or anything else that gets passed to validate_python 

594 # thus validators _must_ handle all cases 

595 value: Any, 

596 /, 

597 ) -> Any: ... 

598 

599 

600class FreeModelBeforeValidator(Protocol): 

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

602 

603 def __call__( # noqa: D102 

604 self, 

605 # this can be a dict, a model instance 

606 # or anything else that gets passed to validate_python 

607 # thus validators _must_ handle all cases 

608 value: Any, 

609 info: core_schema.ValidationInfo[Any], 

610 /, 

611 ) -> Any: ... 

612 

613 

614class ModelBeforeValidator(Protocol): 

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

616 

617 def __call__( # noqa: D102 

618 self, 

619 cls: Any, 

620 # this can be a dict, a model instance 

621 # or anything else that gets passed to validate_python 

622 # thus validators _must_ handle all cases 

623 value: Any, 

624 info: core_schema.ValidationInfo[Any], 

625 /, 

626 ) -> Any: ... 

627 

628 

629ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 

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

631have info argument. 

632""" 

633 

634ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType] 

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

636 

637_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] 

638_AnyModelBeforeValidator = Union[ 

639 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

640] 

641_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] 

642 

643 

644@overload 

645def model_validator( 

646 *, 

647 mode: Literal['wrap'], 

648) -> Callable[ 

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

650]: ... 

651 

652 

653@overload 

654def model_validator( 

655 *, 

656 mode: Literal['before'], 

657) -> Callable[ 

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

659]: ... 

660 

661 

662@overload 

663def model_validator( 

664 *, 

665 mode: Literal['after'], 

666) -> Callable[ 

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

668]: ... 

669 

670 

671def model_validator( 

672 *, 

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

674) -> Any: 

675 """!!! abstract "Usage Documentation" 

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

677 

678 Decorate model methods for validation purposes. 

679 

680 Example usage: 

681 ```python 

682 from typing_extensions import Self 

683 

684 from pydantic import BaseModel, ValidationError, model_validator 

685 

686 class Square(BaseModel): 

687 width: float 

688 height: float 

689 

690 @model_validator(mode='after') 

691 def verify_square(self) -> Self: 

692 if self.width != self.height: 

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

694 return self 

695 

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

697 print(repr(s)) 

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

699 

700 try: 

701 Square(width=1, height=2) 

702 except ValidationError as e: 

703 print(e) 

704 ''' 

705 1 validation error for Square 

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

707 ''' 

708 ``` 

709 

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

711 

712 Args: 

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

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

715 

716 Returns: 

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

718 """ 

719 

720 def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: 

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

722 if mode != 'after': 

723 f = _decorators.ensure_classmethod_based_on_signature(f) 

724 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 

725 return _decorators.PydanticDescriptorProxy(f, dec_info) 

726 

727 return dec 

728 

729 

730AnyType = TypeVar('AnyType') 

731 

732 

733if TYPE_CHECKING: 

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

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

736 

737else: 

738 

739 @dataclasses.dataclass(**_internal_dataclass.slots_true) 

740 class InstanceOf: 

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

742 

743 Example: 

744 ```python 

745 from pydantic import BaseModel, InstanceOf 

746 

747 class Foo: 

748 ... 

749 

750 class Bar(BaseModel): 

751 foo: InstanceOf[Foo] 

752 

753 Bar(foo=Foo()) 

754 try: 

755 Bar(foo=42) 

756 except ValidationError as e: 

757 print(e) 

758 """ 

759 [ 

760 │ { 

761 │ │ 'type': 'is_instance_of', 

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

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

764 │ │ 'input': 42, 

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

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

767 │ } 

768 ] 

769 """ 

770 ``` 

771 ''' 

772 

773 @classmethod 

774 def __class_getitem__(cls, item: AnyType) -> AnyType: 

775 return Annotated[item, cls()] 

776 

777 @classmethod 

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

779 from pydantic import PydanticSchemaGenerationError 

780 

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

782 instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) 

783 

784 try: 

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

786 original_schema = handler(source) 

787 except PydanticSchemaGenerationError: 

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

789 return instance_of_schema 

790 else: 

791 # Use the "original" approach to serialization 

792 instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 

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

794 ) 

795 return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) 

796 

797 __hash__ = object.__hash__ 

798 

799 

800if TYPE_CHECKING: 

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

802else: 

803 

804 @dataclasses.dataclass(**_internal_dataclass.slots_true) 

805 class SkipValidation: 

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

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

808 

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

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

811 

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

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

814 annotation applied to a type. 

815 """ 

816 

817 def __class_getitem__(cls, item: Any) -> Any: 

818 return Annotated[item, SkipValidation()] 

819 

820 @classmethod 

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

822 with warnings.catch_warnings(): 

823 warnings.simplefilter('ignore', ArbitraryTypeWarning) 

824 original_schema = handler(source) 

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

826 return core_schema.any_schema( 

827 metadata=metadata, 

828 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

830 ), 

831 ) 

832 

833 __hash__ = object.__hash__ 

834 

835 

836_FromTypeT = TypeVar('_FromTypeT') 

837 

838 

839class ValidateAs: 

840 """A helper class to validate a custom type from a type that is natively supported by Pydantic. 

841 

842 Args: 

843 from_type: The type natively supported by Pydantic to use to perform validation. 

844 instantiation_hook: A callable taking the validated type as an argument, and returning 

845 the populated custom type. 

846 

847 Example: 

848 ```python {lint="skip"} 

849 from typing import Annotated 

850 

851 from pydantic import BaseModel, TypeAdapter, ValidateAs 

852 

853 class MyCls: 

854 def __init__(self, a: int) -> None: 

855 self.a = a 

856 

857 def __repr__(self) -> str: 

858 return f"MyCls(a={self.a})" 

859 

860 class Model(BaseModel): 

861 a: int 

862 

863 

864 ta = TypeAdapter( 

865 Annotated[MyCls, ValidateAs(Model, lambda v: MyCls(a=v.a))] 

866 ) 

867 

868 print(ta.validate_python({'a': 1})) 

869 #> MyCls(a=1) 

870 ``` 

871 """ 

872 

873 # TODO: make use of PEP 747 

874 def __init__(self, from_type: type[_FromTypeT], /, instantiation_hook: Callable[[_FromTypeT], Any]) -> None: 

875 self.from_type = from_type 

876 self.instantiation_hook = instantiation_hook 

877 

878 def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 

879 schema = handler(self.from_type) 

880 return core_schema.no_info_after_validator_function( 

881 self.instantiation_hook, 

882 schema=schema, 

883 )