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

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

208 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 collections.abc import Callable 

9from functools import partialmethod 

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

11 

12from pydantic_core import PydanticUndefined, core_schema 

13from typing_extensions import Self, TypeForm 

14 

15from ._internal import _decorators, _generics 

16from .annotated_handlers import GetCoreSchemaHandler 

17from .errors import PydanticUserError 

18from .version import version_short 

19from .warnings import ArbitraryTypeWarning, PydanticDeprecatedSince212 

20 

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

22 from typing_extensions import Protocol 

23else: 

24 from typing import Protocol 

25 

26_inspect_validator = _decorators.inspect_validator 

27 

28 

29@dataclasses.dataclass(frozen=True, slots=True) 

30class AfterValidator: 

31 """!!! abstract "Usage Documentation" 

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

33 

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

35 

36 Attributes: 

37 func: The validator function. 

38 

39 Example: 

40 ```python 

41 from typing import Annotated 

42 

43 from pydantic import AfterValidator, BaseModel, ValidationError 

44 

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

46 

47 class Model(BaseModel): 

48 a: MyInt 

49 

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

51 #> 2 

52 

53 try: 

54 Model(a='a') 

55 except ValidationError as e: 

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

57 ''' 

58 [ 

59 { 

60 "type": "int_parsing", 

61 "loc": [ 

62 "a" 

63 ], 

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

65 "input": "a", 

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

67 } 

68 ] 

69 ''' 

70 ``` 

71 """ 

72 

73 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 

74 

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

76 schema = handler(source_type) 

77 info_arg = _inspect_validator(self.func, mode='after', type='field') 

78 if info_arg: 

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

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

81 else: 

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

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

84 

85 @classmethod 

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

87 return cls(func=decorator.func) 

88 

89 

90@dataclasses.dataclass(frozen=True, slots=True) 

91class BeforeValidator: 

92 """!!! abstract "Usage Documentation" 

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

94 

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

96 

97 Attributes: 

98 func: The validator function. 

99 json_schema_input_type: The input type used to generate the appropriate 

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

101 

102 Example: 

103 ```python 

104 from typing import Annotated 

105 

106 from pydantic import BaseModel, BeforeValidator 

107 

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

109 

110 class Model(BaseModel): 

111 a: MyInt 

112 

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

114 #> 2 

115 

116 try: 

117 Model(a='a') 

118 except TypeError as e: 

119 print(e) 

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

121 ``` 

122 """ 

123 

124 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 

125 json_schema_input_type: Any = PydanticUndefined 

126 

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

128 schema = handler(source_type) 

129 input_schema = ( 

130 None 

131 if self.json_schema_input_type is PydanticUndefined 

132 else handler.generate_schema(self.json_schema_input_type) 

133 ) 

134 

135 info_arg = _inspect_validator(self.func, mode='before', type='field') 

136 if info_arg: 

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

138 return core_schema.with_info_before_validator_function( 

139 func, 

140 schema=schema, 

141 json_schema_input_schema=input_schema, 

142 ) 

143 else: 

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

145 return core_schema.no_info_before_validator_function( 

146 func, schema=schema, json_schema_input_schema=input_schema 

147 ) 

148 

149 @classmethod 

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

151 return cls( 

152 func=decorator.func, 

153 json_schema_input_type=decorator.info.json_schema_input_type, 

154 ) 

155 

156 

157@dataclasses.dataclass(frozen=True, slots=True) 

158class PlainValidator: 

159 """!!! abstract "Usage Documentation" 

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

161 

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

163 

164 !!! note 

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

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

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

168 

169 Attributes: 

170 func: The validator function. 

171 json_schema_input_type: The input type used to generate the appropriate 

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

173 

174 Example: 

175 ```python 

176 from typing import Annotated 

177 

178 from pydantic import BaseModel, PlainValidator 

179 

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

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

182 raise ValueError(f'Expected int or str, got {type(v)}') 

183 

184 return int(v) + 1 

185 

186 MyInt = Annotated[ 

187 int, 

188 PlainValidator(validate, json_schema_input_type=str | int), # (1)! 

189 ] 

190 

191 class Model(BaseModel): 

192 a: MyInt 

193 

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

195 #> 2 

196 

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

198 #> 2 

199 ``` 

200 

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

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

203 """ 

204 

205 func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction 

206 json_schema_input_type: Any = Any 

207 

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

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

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

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

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

213 # and abort any attempts to handle special serialization. 

214 from pydantic import PydanticSchemaGenerationError 

215 

216 try: 

217 schema = handler(source_type) 

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

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

220 serialization = schema.get( 

221 'serialization', 

222 core_schema.wrap_serializer_function_ser_schema( 

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

224 schema=schema, 

225 return_schema=handler.generate_schema(source_type), 

226 ), 

227 ) 

228 except PydanticSchemaGenerationError: 

229 serialization = None 

230 

231 input_schema = handler.generate_schema(self.json_schema_input_type) 

232 

233 info_arg = _inspect_validator(self.func, mode='plain', type='field') 

234 if info_arg: 

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

236 return core_schema.with_info_plain_validator_function( 

237 func, 

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

239 json_schema_input_schema=input_schema, 

240 ) 

241 else: 

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

243 return core_schema.no_info_plain_validator_function( 

244 func, 

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

246 json_schema_input_schema=input_schema, 

247 ) 

248 

249 @classmethod 

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

251 return cls( 

252 func=decorator.func, 

253 json_schema_input_type=decorator.info.json_schema_input_type, 

254 ) 

255 

256 

257@dataclasses.dataclass(frozen=True, slots=True) 

258class WrapValidator: 

259 """!!! abstract "Usage Documentation" 

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

261 

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

263 

264 Attributes: 

265 func: The validator function. 

266 json_schema_input_type: The input type used to generate the appropriate 

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

268 

269 ```python 

270 from datetime import datetime 

271 from typing import Annotated 

272 

273 from pydantic import BaseModel, ValidationError, WrapValidator 

274 

275 def validate_timestamp(v, handler): 

276 if v == 'now': 

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

278 return datetime.now() 

279 try: 

280 return handler(v) 

281 except ValidationError: 

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

283 return datetime(2000, 1, 1) 

284 

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

286 

287 class Model(BaseModel): 

288 a: MyTimestamp 

289 

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

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

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

293 #> 2000-01-01 00:00:00 

294 ``` 

295 """ 

296 

297 func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction 

298 json_schema_input_type: Any = PydanticUndefined 

299 

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

301 schema = handler(source_type) 

302 input_schema = ( 

303 None 

304 if self.json_schema_input_type is PydanticUndefined 

305 else handler.generate_schema(self.json_schema_input_type) 

306 ) 

307 

308 info_arg = _inspect_validator(self.func, mode='wrap', type='field') 

309 if info_arg: 

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

311 return core_schema.with_info_wrap_validator_function( 

312 func, 

313 schema=schema, 

314 json_schema_input_schema=input_schema, 

315 ) 

316 else: 

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

318 return core_schema.no_info_wrap_validator_function( 

319 func, 

320 schema=schema, 

321 json_schema_input_schema=input_schema, 

322 ) 

323 

324 @classmethod 

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

326 return cls( 

327 func=decorator.func, 

328 json_schema_input_type=decorator.info.json_schema_input_type, 

329 ) 

330 

331 

332if TYPE_CHECKING: 

333 

334 class _OnlyValueValidatorClsMethod(Protocol): 

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

336 

337 class _V2ValidatorClsMethod(Protocol): 

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

339 

340 class _OnlyValueWrapValidatorClsMethod(Protocol): 

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

342 

343 class _V2WrapValidatorClsMethod(Protocol): 

344 def __call__( 

345 self, 

346 cls: Any, 

347 value: Any, 

348 handler: core_schema.ValidatorFunctionWrapHandler, 

349 info: core_schema.ValidationInfo[Any], 

350 /, 

351 ) -> Any: ... 

352 

353 _V2Validator: TypeAlias = ( 

354 _V2ValidatorClsMethod 

355 | core_schema.WithInfoValidatorFunction 

356 | _OnlyValueValidatorClsMethod 

357 | core_schema.NoInfoValidatorFunction 

358 ) 

359 

360 _V2WrapValidator: TypeAlias = ( 

361 _V2WrapValidatorClsMethod 

362 | core_schema.WithInfoWrapValidatorFunction 

363 | _OnlyValueWrapValidatorClsMethod 

364 | core_schema.NoInfoWrapValidatorFunction 

365 ) 

366 

367 _PartialClsOrStaticMethod: TypeAlias = classmethod[Any, Any, Any] | staticmethod[Any, Any] | partialmethod[Any] 

368 

369 _V2BeforeAfterOrPlainValidatorType = TypeVar( 

370 '_V2BeforeAfterOrPlainValidatorType', 

371 bound=_V2Validator | _PartialClsOrStaticMethod, 

372 ) 

373 _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=_V2WrapValidator | _PartialClsOrStaticMethod) 

374 

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

376 

377 

378@overload 

379def field_validator( 

380 field: str, 

381 /, 

382 *fields: str, 

383 mode: Literal['wrap'], 

384 check_fields: bool | None = ..., 

385 json_schema_input_type: Any = ..., 

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

387 

388 

389@overload 

390def field_validator( 

391 field: str, 

392 /, 

393 *fields: str, 

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

395 check_fields: bool | None = ..., 

396 json_schema_input_type: Any = ..., 

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

398 

399 

400@overload 

401def field_validator( 

402 field: str, 

403 /, 

404 *fields: str, 

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

406 check_fields: bool | None = ..., 

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

408 

409 

410def field_validator( # noqa: D417 

411 field: str, 

412 /, 

413 *fields: str, 

414 mode: FieldValidatorModes = 'after', 

415 check_fields: bool | None = None, 

416 json_schema_input_type: Any = PydanticUndefined, 

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

418 """!!! abstract "Usage Documentation" 

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

420 

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

422 

423 Example usage: 

424 ```python 

425 from typing import Any 

426 

427 from pydantic import ( 

428 BaseModel, 

429 ValidationError, 

430 field_validator, 

431 ) 

432 

433 class Model(BaseModel): 

434 a: str 

435 

436 @field_validator('a') 

437 @classmethod 

438 def ensure_foobar(cls, v: Any): 

439 if 'foobar' not in v: 

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

441 return v 

442 

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

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

445 

446 try: 

447 Model(a='snap') 

448 except ValidationError as exc_info: 

449 print(exc_info) 

450 ''' 

451 1 validation error for Model 

452 a 

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

454 ''' 

455 ``` 

456 

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

458 

459 Errors raised in a field validator become part of the model's 

460 [`ValidationError`][pydantic_core.ValidationError]. In a running application, 

461 [Logfire](../integrations/logfire.md) can record the input each failed validation rejected — see 

462 [Troubleshooting validation errors](../errors/troubleshooting.md). 

463 

464 Args: 

465 *fields: The field names the validator should apply to. 

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

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

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

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

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

471 

472 Raises: 

473 PydanticUserError: 

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

475 - If the provided field names are not strings. 

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

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

478 """ 

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

480 raise PydanticUserError( 

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

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

483 code='decorator-missing-arguments', 

484 ) 

485 

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

487 raise PydanticUserError( 

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

489 code='validator-input-type', 

490 ) 

491 

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

493 json_schema_input_type = Any 

494 

495 fields = field, *fields 

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

497 raise PydanticUserError( 

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

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

500 code='decorator-invalid-fields', 

501 ) 

502 

503 def dec( 

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

505 ) -> _decorators.PydanticDescriptorProxy[Any]: 

506 if _decorators.is_instance_method_from_sig(f): 

507 raise PydanticUserError( 

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

509 code='validator-instance-method', 

510 ) 

511 

512 # auto apply the @classmethod decorator 

513 f = _decorators.ensure_classmethod_based_on_signature(f) 

514 

515 dec_info = _decorators.FieldValidatorDecoratorInfo( 

516 fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type 

517 ) 

518 return _decorators.PydanticDescriptorProxy(f, dec_info) 

519 

520 return dec 

521 

522 

523_ModelType = TypeVar('_ModelType') 

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

525 

526 

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

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

529 

530 def __call__( # noqa: D102 

531 self, 

532 value: Any, 

533 outer_location: str | int | None = None, 

534 /, 

535 ) -> _ModelTypeCo: # pragma: no cover 

536 ... 

537 

538 

539class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): 

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

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

542 """ 

543 

544 def __call__( # noqa: D102 

545 self, 

546 cls: type[_ModelType], 

547 # this can be a dict, a model instance 

548 # or anything else that gets passed to validate_python 

549 # thus validators _must_ handle all cases 

550 value: Any, 

551 handler: ModelWrapValidatorHandler[_ModelType], 

552 /, 

553 ) -> _ModelType: ... 

554 

555 

556class ModelWrapValidator(Protocol[_ModelType]): 

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

558 

559 def __call__( # noqa: D102 

560 self, 

561 cls: type[_ModelType], 

562 # this can be a dict, a model instance 

563 # or anything else that gets passed to validate_python 

564 # thus validators _must_ handle all cases 

565 value: Any, 

566 handler: ModelWrapValidatorHandler[_ModelType], 

567 info: core_schema.ValidationInfo, 

568 /, 

569 ) -> _ModelType: ... 

570 

571 

572class FreeModelBeforeValidatorWithoutInfo(Protocol): 

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

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

575 """ 

576 

577 def __call__( # noqa: D102 

578 self, 

579 # this can be a dict, a model instance 

580 # or anything else that gets passed to validate_python 

581 # thus validators _must_ handle all cases 

582 value: Any, 

583 /, 

584 ) -> Any: ... 

585 

586 

587class ModelBeforeValidatorWithoutInfo(Protocol): 

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

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

590 """ 

591 

592 def __call__( # noqa: D102 

593 self, 

594 cls: Any, 

595 # this can be a dict, a model instance 

596 # or anything else that gets passed to validate_python 

597 # thus validators _must_ handle all cases 

598 value: Any, 

599 /, 

600 ) -> Any: ... 

601 

602 

603class FreeModelBeforeValidator(Protocol): 

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

605 

606 def __call__( # noqa: D102 

607 self, 

608 # this can be a dict, a model instance 

609 # or anything else that gets passed to validate_python 

610 # thus validators _must_ handle all cases 

611 value: Any, 

612 info: core_schema.ValidationInfo[Any], 

613 /, 

614 ) -> Any: ... 

615 

616 

617class ModelBeforeValidator(Protocol): 

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

619 

620 def __call__( # noqa: D102 

621 self, 

622 cls: Any, 

623 # this can be a dict, a model instance 

624 # or anything else that gets passed to validate_python 

625 # thus validators _must_ handle all cases 

626 value: Any, 

627 info: core_schema.ValidationInfo[Any], 

628 /, 

629 ) -> Any: ... 

630 

631 

632ModelAfterValidatorWithoutInfo: TypeAlias = Callable[[_ModelType], _ModelType] 

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

634have info argument. 

635""" 

636 

637ModelAfterValidator: TypeAlias = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType] 

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

639 

640_AnyModelWrapValidator: TypeAlias = ModelWrapValidator[_ModelType] | ModelWrapValidatorWithoutInfo[_ModelType] 

641_AnyModelBeforeValidator: TypeAlias = ( 

642 FreeModelBeforeValidator 

643 | ModelBeforeValidator 

644 | FreeModelBeforeValidatorWithoutInfo 

645 | ModelBeforeValidatorWithoutInfo 

646) 

647_AnyModelAfterValidator: TypeAlias = ModelAfterValidator[_ModelType] | ModelAfterValidatorWithoutInfo[_ModelType] 

648 

649 

650@overload 

651def model_validator( 

652 *, 

653 mode: Literal['wrap'], 

654) -> Callable[ 

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

656]: ... 

657 

658 

659@overload 

660def model_validator( 

661 *, 

662 mode: Literal['before'], 

663) -> Callable[ 

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

665]: ... 

666 

667 

668@overload 

669def model_validator( 

670 *, 

671 mode: Literal['after'], 

672) -> Callable[ 

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

674]: ... 

675 

676 

677def model_validator( 

678 *, 

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

680) -> Any: 

681 """!!! abstract "Usage Documentation" 

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

683 

684 Decorate model methods for validation purposes. 

685 

686 Example usage: 

687 ```python 

688 from typing_extensions import Self 

689 

690 from pydantic import BaseModel, ValidationError, model_validator 

691 

692 class Square(BaseModel): 

693 width: float 

694 height: float 

695 

696 @model_validator(mode='after') 

697 def verify_square(self) -> Self: 

698 if self.width != self.height: 

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

700 return self 

701 

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

703 print(repr(s)) 

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

705 

706 try: 

707 Square(width=1, height=2) 

708 except ValidationError as e: 

709 print(e) 

710 ''' 

711 1 validation error for Square 

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

713 ''' 

714 ``` 

715 

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

717 

718 Cross-field rules like the one above tend to fail on combinations of values you didn't anticipate. 

719 The resulting [`ValidationError`][pydantic_core.ValidationError] includes the input that failed; 

720 [Logfire](../integrations/logfire.md) can retain these failures with their trace context so you can 

721 investigate patterns in a running application (see 

722 [Troubleshooting validation errors](../errors/troubleshooting.md)). 

723 

724 Args: 

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

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

727 

728 Returns: 

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

730 """ 

731 

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

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

734 f = _decorators.ensure_classmethod_based_on_signature(f) 

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

736 warnings.warn( 

737 category=PydanticDeprecatedSince212, 

738 message=( 

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

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

741 ), 

742 stacklevel=2, 

743 ) 

744 

745 dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) 

746 return _decorators.PydanticDescriptorProxy(f, dec_info) 

747 

748 return dec 

749 

750 

751AnyType = TypeVar('AnyType') 

752 

753 

754if TYPE_CHECKING: 

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

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

757 

758else: 

759 

760 @dataclasses.dataclass(slots=True) 

761 class InstanceOf: 

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

763 

764 Example: 

765 ```python 

766 from pydantic import BaseModel, InstanceOf 

767 

768 class Foo: 

769 ... 

770 

771 class Bar(BaseModel): 

772 foo: InstanceOf[Foo] 

773 

774 Bar(foo=Foo()) 

775 try: 

776 Bar(foo=42) 

777 except ValidationError as e: 

778 print(e) 

779 """ 

780 [ 

781 │ { 

782 │ │ 'type': 'is_instance_of', 

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

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

785 │ │ 'input': 42, 

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

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

788 │ } 

789 ] 

790 """ 

791 ``` 

792 ''' 

793 

794 @classmethod 

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

796 return Annotated[item, cls()] 

797 

798 @classmethod 

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

800 # Lazy import to avoid cycle: 

801 from pydantic._internal._generate_schema import GENERATE_SCHEMA_ERRORS 

802 

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

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

805 

806 try: 

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

808 original_schema = handler(source) 

809 except GENERATE_SCHEMA_ERRORS: 

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

811 return instance_of_schema 

812 else: 

813 # Use the "original" approach to serialization 

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

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

816 ) 

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

818 

819 __hash__ = object.__hash__ 

820 

821 

822if TYPE_CHECKING: 

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

824else: 

825 

826 @dataclasses.dataclass(slots=True) 

827 class SkipValidation: 

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

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

830 

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

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

833 

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

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

836 annotation applied to a type. 

837 """ 

838 

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

840 return Annotated[item, SkipValidation()] 

841 

842 @classmethod 

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

844 with warnings.catch_warnings(): 

845 warnings.simplefilter('ignore', ArbitraryTypeWarning) 

846 original_schema = handler(source) 

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

848 return core_schema.any_schema( 

849 metadata=metadata, 

850 serialization=core_schema.wrap_serializer_function_ser_schema( 

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

852 ), 

853 ) 

854 

855 __hash__ = object.__hash__ 

856 

857 

858_FromTypeT = TypeVar('_FromTypeT') 

859 

860 

861class ValidateAs: 

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

863 

864 Args: 

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

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

867 the populated custom type. 

868 

869 Example: 

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

871 from typing import Annotated 

872 

873 from pydantic import BaseModel, TypeAdapter, ValidateAs 

874 

875 class MyCls: 

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

877 self.a = a 

878 

879 def __repr__(self) -> str: 

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

881 

882 class Model(BaseModel): 

883 a: int 

884 

885 

886 ta = TypeAdapter( 

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

888 ) 

889 

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

891 #> MyCls(a=1) 

892 ``` 

893 """ 

894 

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

896 self.from_type = from_type 

897 self.instantiation_hook = instantiation_hook 

898 

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

900 # Lazy import to avoid cycle: 

901 from pydantic._internal._generate_schema import GENERATE_SCHEMA_ERRORS 

902 

903 from_type_schema = handler(self.from_type) 

904 schema = core_schema.no_info_after_validator_function( 

905 self.instantiation_hook, 

906 schema=from_type_schema, 

907 ) 

908 try: 

909 ser_schema = handler(source) 

910 except GENERATE_SCHEMA_ERRORS: 

911 ser_schema = core_schema.any_schema() 

912 

913 # TODO: pydantic-core now accepts an arbitrary core schema for serialization, so the 

914 # wrap serializer workaround below can be replaced with 

915 # `schema['serialization'] = _core_utils.as_ser_schema(ser_schema)`. 

916 # The same workaround is used in other parts of the code base, so grep for similar cases when fixing: 

917 schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( 

918 function=lambda v, h: h(v), schema=ser_schema 

919 ) 

920 return schema