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

200 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 typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload 

10 

11from pydantic_core import PydanticUndefined, core_schema 

12from typing_extensions import Self, TypeAlias 

13 

14from ._internal import _decorators, _generics, _internal_dataclass 

15from .annotated_handlers import GetCoreSchemaHandler 

16from .errors import PydanticUserError 

17from .version import version_short 

18from .warnings import ArbitraryTypeWarning, PydanticDeprecatedSince212 

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, mode='after', type='field') 

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, mode='before', type='field') 

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, got {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, mode='plain', type='field') 

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, mode='wrap', type='field') 

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( # noqa: D417 

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 *fields: The field names the validator should apply to. 

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

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

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

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

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

465 

466 Raises: 

467 PydanticUserError: 

468 - If the decorator is used without any arguments (at least one field name must be provided). 

469 - If the provided field names are not strings. 

470 - If `json_schema_input_type` is provided with an unsupported `mode`. 

471 - If the decorator is applied to an instance method. 

472 """ 

473 if callable(field) or isinstance(field, classmethod): 

474 raise PydanticUserError( 

475 'The `@field_validator` decorator cannot be used without arguments, at least one field must be provided. ' 

476 "For example: `@field_validator('<field_name>', ...)`.", 

477 code='decorator-missing-arguments', 

478 ) 

479 

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

481 raise PydanticUserError( 

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

483 code='validator-input-type', 

484 ) 

485 

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

487 json_schema_input_type = Any 

488 

489 fields = field, *fields 

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

491 raise PydanticUserError( 

492 'The provided field names to the `@field_validator` decorator should be strings. ' 

493 "For example: `@field_validator('<field_name_1>', '<field_name_2>', ...).`", 

494 code='decorator-invalid-fields', 

495 ) 

496 

497 def dec( 

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

499 ) -> _decorators.PydanticDescriptorProxy[Any]: 

500 if _decorators.is_instance_method_from_sig(f): 

501 raise PydanticUserError( 

502 'The `@field_validator` decorator cannot be applied to instance methods', 

503 code='validator-instance-method', 

504 ) 

505 

506 # auto apply the @classmethod decorator 

507 f = _decorators.ensure_classmethod_based_on_signature(f) 

508 

509 dec_info = _decorators.FieldValidatorDecoratorInfo( 

510 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type 

511 ) 

512 return _decorators.PydanticDescriptorProxy(f, dec_info) 

513 

514 return dec 

515 

516 

517_ModelType = TypeVar('_ModelType') 

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

519 

520 

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

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

523 

524 def __call__( # noqa: D102 

525 self, 

526 value: Any, 

527 outer_location: str | int | None = None, 

528 /, 

529 ) -> _ModelTypeCo: # pragma: no cover 

530 ... 

531 

532 

533class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 

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

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

536 """ 

537 

538 def __call__( # noqa: D102 

539 self, 

540 cls: type[_ModelType], 

541 # this can be a dict, a model instance 

542 # or anything else that gets passed to validate_python 

543 # thus validators _must_ handle all cases 

544 value: Any, 

545 handler: ModelWrapValidatorHandler[_ModelType], 

546 /, 

547 ) -> _ModelType: ... 

548 

549 

550class ModelWrapValidator(Protocol[_ModelType]): 

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

552 

553 def __call__( # noqa: D102 

554 self, 

555 cls: type[_ModelType], 

556 # this can be a dict, a model instance 

557 # or anything else that gets passed to validate_python 

558 # thus validators _must_ handle all cases 

559 value: Any, 

560 handler: ModelWrapValidatorHandler[_ModelType], 

561 info: core_schema.ValidationInfo, 

562 /, 

563 ) -> _ModelType: ... 

564 

565 

566class FreeModelBeforeValidatorWithoutInfo(Protocol): 

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

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

569 """ 

570 

571 def __call__( # noqa: D102 

572 self, 

573 # this can be a dict, a model instance 

574 # or anything else that gets passed to validate_python 

575 # thus validators _must_ handle all cases 

576 value: Any, 

577 /, 

578 ) -> Any: ... 

579 

580 

581class ModelBeforeValidatorWithoutInfo(Protocol): 

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

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

584 """ 

585 

586 def __call__( # noqa: D102 

587 self, 

588 cls: Any, 

589 # this can be a dict, a model instance 

590 # or anything else that gets passed to validate_python 

591 # thus validators _must_ handle all cases 

592 value: Any, 

593 /, 

594 ) -> Any: ... 

595 

596 

597class FreeModelBeforeValidator(Protocol): 

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

599 

600 def __call__( # noqa: D102 

601 self, 

602 # this can be a dict, a model instance 

603 # or anything else that gets passed to validate_python 

604 # thus validators _must_ handle all cases 

605 value: Any, 

606 info: core_schema.ValidationInfo[Any], 

607 /, 

608 ) -> Any: ... 

609 

610 

611class ModelBeforeValidator(Protocol): 

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

613 

614 def __call__( # noqa: D102 

615 self, 

616 cls: Any, 

617 # this can be a dict, a model instance 

618 # or anything else that gets passed to validate_python 

619 # thus validators _must_ handle all cases 

620 value: Any, 

621 info: core_schema.ValidationInfo[Any], 

622 /, 

623 ) -> Any: ... 

624 

625 

626ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] 

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

628have info argument. 

629""" 

630 

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

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

633 

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

635_AnyModelBeforeValidator = Union[ 

636 FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo 

637] 

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

639 

640 

641@overload 

642def model_validator( 

643 *, 

644 mode: Literal['wrap'], 

645) -> Callable[ 

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

647]: ... 

648 

649 

650@overload 

651def model_validator( 

652 *, 

653 mode: Literal['before'], 

654) -> Callable[ 

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

656]: ... 

657 

658 

659@overload 

660def model_validator( 

661 *, 

662 mode: Literal['after'], 

663) -> Callable[ 

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

665]: ... 

666 

667 

668def model_validator( 

669 *, 

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

671) -> Any: 

672 """!!! abstract "Usage Documentation" 

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

674 

675 Decorate model methods for validation purposes. 

676 

677 Example usage: 

678 ```python 

679 from typing_extensions import Self 

680 

681 from pydantic import BaseModel, ValidationError, model_validator 

682 

683 class Square(BaseModel): 

684 width: float 

685 height: float 

686 

687 @model_validator(mode='after') 

688 def verify_square(self) -> Self: 

689 if self.width != self.height: 

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

691 return self 

692 

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

694 print(repr(s)) 

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

696 

697 try: 

698 Square(width=1, height=2) 

699 except ValidationError as e: 

700 print(e) 

701 ''' 

702 1 validation error for Square 

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

704 ''' 

705 ``` 

706 

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

708 

709 Args: 

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

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

712 

713 Returns: 

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

715 """ 

716 

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

718 # auto apply the @classmethod decorator. NOTE: in V3, do not apply the conversion for 'after' validators: 

719 f = _decorators.ensure_classmethod_based_on_signature(f) 

720 if mode == 'after' and isinstance(f, classmethod): 

721 warnings.warn( 

722 category=PydanticDeprecatedSince212, 

723 message=( 

724 "Using `@model_validator` with mode='after' on a classmethod is deprecated. Instead, use an instance method. " 

725 f'See the documentation at https://docs.pydantic.dev/{version_short()}/concepts/validators/#model-after-validator.' 

726 ), 

727 stacklevel=2, 

728 ) 

729 

730 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 

731 return _decorators.PydanticDescriptorProxy(f, dec_info) 

732 

733 return dec 

734 

735 

736AnyType = TypeVar('AnyType') 

737 

738 

739if TYPE_CHECKING: 

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

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

742 

743else: 

744 

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

746 class InstanceOf: 

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

748 

749 Example: 

750 ```python 

751 from pydantic import BaseModel, InstanceOf 

752 

753 class Foo: 

754 ... 

755 

756 class Bar(BaseModel): 

757 foo: InstanceOf[Foo] 

758 

759 Bar(foo=Foo()) 

760 try: 

761 Bar(foo=42) 

762 except ValidationError as e: 

763 print(e) 

764 """ 

765 [ 

766 │ { 

767 │ │ 'type': 'is_instance_of', 

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

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

770 │ │ 'input': 42, 

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

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

773 │ } 

774 ] 

775 """ 

776 ``` 

777 ''' 

778 

779 @classmethod 

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

781 return Annotated[item, cls()] 

782 

783 @classmethod 

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

785 from pydantic._internal._generate_schema import GENERATE_SCHEMA_ERRORS 

786 

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

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

789 

790 try: 

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

792 original_schema = handler(source) 

793 except GENERATE_SCHEMA_ERRORS: 

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

795 return instance_of_schema 

796 else: 

797 # Use the "original" approach to serialization 

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

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

800 ) 

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

802 

803 __hash__ = object.__hash__ 

804 

805 

806if TYPE_CHECKING: 

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

808else: 

809 

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

811 class SkipValidation: 

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

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

814 

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

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

817 

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

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

820 annotation applied to a type. 

821 """ 

822 

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

824 return Annotated[item, SkipValidation()] 

825 

826 @classmethod 

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

828 with warnings.catch_warnings(): 

829 warnings.simplefilter('ignore', ArbitraryTypeWarning) 

830 original_schema = handler(source) 

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

832 return core_schema.any_schema( 

833 metadata=metadata, 

834 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

836 ), 

837 ) 

838 

839 __hash__ = object.__hash__ 

840 

841 

842_FromTypeT = TypeVar('_FromTypeT') 

843 

844 

845class ValidateAs: 

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

847 

848 Args: 

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

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

851 the populated custom type. 

852 

853 Example: 

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

855 from typing import Annotated 

856 

857 from pydantic import BaseModel, TypeAdapter, ValidateAs 

858 

859 class MyCls: 

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

861 self.a = a 

862 

863 def __repr__(self) -> str: 

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

865 

866 class Model(BaseModel): 

867 a: int 

868 

869 

870 ta = TypeAdapter( 

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

872 ) 

873 

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

875 #> MyCls(a=1) 

876 ``` 

877 """ 

878 

879 # TODO: make use of PEP 747 

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

881 self.from_type = from_type 

882 self.instantiation_hook = instantiation_hook 

883 

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

885 schema = handler(self.from_type) 

886 return core_schema.no_info_after_validator_function( 

887 self.instantiation_hook, 

888 schema=schema, 

889 )