Coverage for pydantic/types.py: 97.48%

653 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-02 16:20 +0000

1"""The types module contains custom types used by pydantic.""" 

2 

3from __future__ import annotations as _annotations 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

4 

5import base64 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

6import dataclasses as _dataclasses 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

7import re 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

8from collections.abc import Hashable, Iterator 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

9from datetime import date, datetime 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

10from decimal import Decimal 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

11from enum import Enum 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

12from pathlib import Path 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

13from re import Pattern 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

14from types import ModuleType 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

15from typing import ( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

16 TYPE_CHECKING, 

17 Annotated, 

18 Any, 

19 Callable, 

20 ClassVar, 

21 Generic, 

22 Literal, 

23 TypeVar, 

24 Union, 

25 cast, 

26) 

27from uuid import UUID 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

28 

29import annotated_types 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

30from annotated_types import BaseMetadata, MaxLen, MinLen 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

31from pydantic_core import CoreSchema, PydanticCustomError, SchemaSerializer, core_schema 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

32from typing_extensions import Protocol, TypeAlias, TypeAliasType, deprecated, get_args, get_origin 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

33from typing_inspection.introspection import is_union_origin 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

34 

35from ._internal import _fields, _internal_dataclass, _utils, _validators 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

36from ._migration import getattr_migration 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

37from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

38from .errors import PydanticUserError 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

39from .json_schema import JsonSchemaValue 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

40from .warnings import PydanticDeprecatedSince20 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

41 

42if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

43 from ._internal._core_metadata import CoreMetadata 

44 

45__all__ = ( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

46 'Strict', 

47 'StrictStr', 

48 'SocketPath', 

49 'conbytes', 

50 'conlist', 

51 'conset', 

52 'confrozenset', 

53 'constr', 

54 'ImportString', 

55 'conint', 

56 'PositiveInt', 

57 'NegativeInt', 

58 'NonNegativeInt', 

59 'NonPositiveInt', 

60 'confloat', 

61 'PositiveFloat', 

62 'NegativeFloat', 

63 'NonNegativeFloat', 

64 'NonPositiveFloat', 

65 'FiniteFloat', 

66 'condecimal', 

67 'UUID1', 

68 'UUID3', 

69 'UUID4', 

70 'UUID5', 

71 'UUID6', 

72 'UUID7', 

73 'UUID8', 

74 'FilePath', 

75 'DirectoryPath', 

76 'NewPath', 

77 'Json', 

78 'Secret', 

79 'SecretStr', 

80 'SecretBytes', 

81 'StrictBool', 

82 'StrictBytes', 

83 'StrictInt', 

84 'StrictFloat', 

85 'PaymentCardNumber', 

86 'ByteSize', 

87 'PastDate', 

88 'FutureDate', 

89 'PastDatetime', 

90 'FutureDatetime', 

91 'condate', 

92 'AwareDatetime', 

93 'NaiveDatetime', 

94 'AllowInfNan', 

95 'EncoderProtocol', 

96 'EncodedBytes', 

97 'EncodedStr', 

98 'Base64Encoder', 

99 'Base64Bytes', 

100 'Base64Str', 

101 'Base64UrlBytes', 

102 'Base64UrlStr', 

103 'GetPydanticSchema', 

104 'StringConstraints', 

105 'Tag', 

106 'Discriminator', 

107 'JsonValue', 

108 'OnErrorOmit', 

109 'FailFast', 

110) 

111 

112 

113T = TypeVar('T') 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

114 

115 

116@_dataclasses.dataclass 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

117class Strict(_fields.PydanticMetadata, BaseMetadata): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

118 """!!! abstract "Usage Documentation" 

119 [Strict Mode with `Annotated` `Strict`](../concepts/strict_mode.md#strict-mode-with-annotated-strict) 

120 

121 A field metadata class to indicate that a field should be validated in strict mode. 

122 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. 

123 

124 Attributes: 

125 strict: Whether to validate the field in strict mode. 

126 

127 Example: 

128 ```python 

129 from typing import Annotated 

130 

131 from pydantic.types import Strict 

132 

133 StrictBool = Annotated[bool, Strict()] 

134 ``` 

135 """ 

136 

137 strict: bool = True 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

138 

139 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

140 return hash(self.strict) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

141 

142 

143# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

144 

145StrictBool = Annotated[bool, Strict()] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

146"""A boolean that must be either ``True`` or ``False``.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

147 

148# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

149 

150 

151def conint( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

152 *, 

153 strict: bool | None = None, 

154 gt: int | None = None, 

155 ge: int | None = None, 

156 lt: int | None = None, 

157 le: int | None = None, 

158 multiple_of: int | None = None, 

159) -> type[int]: 

160 """ 

161 !!! warning "Discouraged" 

162 This function is **discouraged** in favor of using 

163 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with 

164 [`Field`][pydantic.fields.Field] instead. 

165 

166 This function will be **deprecated** in Pydantic 3.0. 

167 

168 The reason is that `conint` returns a type, which doesn't play well with static analysis tools. 

169 

170 === ":x: Don't do this" 

171 ```python 

172 from pydantic import BaseModel, conint 

173 

174 class Foo(BaseModel): 

175 bar: conint(strict=True, gt=0) 

176 ``` 

177 

178 === ":white_check_mark: Do this" 

179 ```python 

180 from typing import Annotated 

181 

182 from pydantic import BaseModel, Field 

183 

184 class Foo(BaseModel): 

185 bar: Annotated[int, Field(strict=True, gt=0)] 

186 ``` 

187 

188 A wrapper around `int` that allows for additional constraints. 

189 

190 Args: 

191 strict: Whether to validate the integer in strict mode. Defaults to `None`. 

192 gt: The value must be greater than this. 

193 ge: The value must be greater than or equal to this. 

194 lt: The value must be less than this. 

195 le: The value must be less than or equal to this. 

196 multiple_of: The value must be a multiple of this. 

197 

198 Returns: 

199 The wrapped integer type. 

200 

201 ```python 

202 from pydantic import BaseModel, ValidationError, conint 

203 

204 class ConstrainedExample(BaseModel): 

205 constrained_int: conint(gt=1) 

206 

207 m = ConstrainedExample(constrained_int=2) 

208 print(repr(m)) 

209 #> ConstrainedExample(constrained_int=2) 

210 

211 try: 

212 ConstrainedExample(constrained_int=0) 

213 except ValidationError as e: 

214 print(e.errors()) 

215 ''' 

216 [ 

217 { 

218 'type': 'greater_than', 

219 'loc': ('constrained_int',), 

220 'msg': 'Input should be greater than 1', 

221 'input': 0, 

222 'ctx': {'gt': 1}, 

223 'url': 'https://errors.pydantic.dev/2/v/greater_than', 

224 } 

225 ] 

226 ''' 

227 ``` 

228 

229 """ # noqa: D212 

230 return Annotated[ # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

231 int, 

232 Strict(strict) if strict is not None else None, 

233 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), 

234 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, 

235 ] 

236 

237 

238PositiveInt = Annotated[int, annotated_types.Gt(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

239"""An integer that must be greater than zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

240 

241```python 

242from pydantic import BaseModel, PositiveInt, ValidationError 

243 

244class Model(BaseModel): 

245 positive_int: PositiveInt 

246 

247m = Model(positive_int=1) 

248print(repr(m)) 

249#> Model(positive_int=1) 

250 

251try: 

252 Model(positive_int=-1) 

253except ValidationError as e: 

254 print(e.errors()) 

255 ''' 

256 [ 

257 { 

258 'type': 'greater_than', 

259 'loc': ('positive_int',), 

260 'msg': 'Input should be greater than 0', 

261 'input': -1, 

262 'ctx': {'gt': 0}, 

263 'url': 'https://errors.pydantic.dev/2/v/greater_than', 

264 } 

265 ] 

266 ''' 

267``` 

268""" 

269NegativeInt = Annotated[int, annotated_types.Lt(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

270"""An integer that must be less than zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

271 

272```python 

273from pydantic import BaseModel, NegativeInt, ValidationError 

274 

275class Model(BaseModel): 

276 negative_int: NegativeInt 

277 

278m = Model(negative_int=-1) 

279print(repr(m)) 

280#> Model(negative_int=-1) 

281 

282try: 

283 Model(negative_int=1) 

284except ValidationError as e: 

285 print(e.errors()) 

286 ''' 

287 [ 

288 { 

289 'type': 'less_than', 

290 'loc': ('negative_int',), 

291 'msg': 'Input should be less than 0', 

292 'input': 1, 

293 'ctx': {'lt': 0}, 

294 'url': 'https://errors.pydantic.dev/2/v/less_than', 

295 } 

296 ] 

297 ''' 

298``` 

299""" 

300NonPositiveInt = Annotated[int, annotated_types.Le(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

301"""An integer that must be less than or equal to zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

302 

303```python 

304from pydantic import BaseModel, NonPositiveInt, ValidationError 

305 

306class Model(BaseModel): 

307 non_positive_int: NonPositiveInt 

308 

309m = Model(non_positive_int=0) 

310print(repr(m)) 

311#> Model(non_positive_int=0) 

312 

313try: 

314 Model(non_positive_int=1) 

315except ValidationError as e: 

316 print(e.errors()) 

317 ''' 

318 [ 

319 { 

320 'type': 'less_than_equal', 

321 'loc': ('non_positive_int',), 

322 'msg': 'Input should be less than or equal to 0', 

323 'input': 1, 

324 'ctx': {'le': 0}, 

325 'url': 'https://errors.pydantic.dev/2/v/less_than_equal', 

326 } 

327 ] 

328 ''' 

329``` 

330""" 

331NonNegativeInt = Annotated[int, annotated_types.Ge(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

332"""An integer that must be greater than or equal to zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

333 

334```python 

335from pydantic import BaseModel, NonNegativeInt, ValidationError 

336 

337class Model(BaseModel): 

338 non_negative_int: NonNegativeInt 

339 

340m = Model(non_negative_int=0) 

341print(repr(m)) 

342#> Model(non_negative_int=0) 

343 

344try: 

345 Model(non_negative_int=-1) 

346except ValidationError as e: 

347 print(e.errors()) 

348 ''' 

349 [ 

350 { 

351 'type': 'greater_than_equal', 

352 'loc': ('non_negative_int',), 

353 'msg': 'Input should be greater than or equal to 0', 

354 'input': -1, 

355 'ctx': {'ge': 0}, 

356 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal', 

357 } 

358 ] 

359 ''' 

360``` 

361""" 

362StrictInt = Annotated[int, Strict()] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

363"""An integer that must be validated in strict mode. 1bcdefghijaklmnopqrsJtuvwxyzAB

364 

365```python 

366from pydantic import BaseModel, StrictInt, ValidationError 

367 

368class StrictIntModel(BaseModel): 

369 strict_int: StrictInt 

370 

371try: 

372 StrictIntModel(strict_int=3.14159) 

373except ValidationError as e: 

374 print(e) 

375 ''' 

376 1 validation error for StrictIntModel 

377 strict_int 

378 Input should be a valid integer [type=int_type, input_value=3.14159, input_type=float] 

379 ''' 

380``` 

381""" 

382 

383# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

384 

385 

386@_dataclasses.dataclass 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

387class AllowInfNan(_fields.PydanticMetadata): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

388 """A field metadata class to indicate that a field should allow `-inf`, `inf`, and `nan`. 

389 

390 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. 

391 

392 Attributes: 

393 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. Defaults to `True`. 

394 

395 Example: 

396 ```python 

397 from typing import Annotated 

398 

399 from pydantic.types import AllowInfNan 

400 

401 LaxFloat = Annotated[float, AllowInfNan()] 

402 ``` 

403 """ 

404 

405 allow_inf_nan: bool = True 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

406 

407 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

408 return hash(self.allow_inf_nan) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

409 

410 

411def confloat( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

412 *, 

413 strict: bool | None = None, 

414 gt: float | None = None, 

415 ge: float | None = None, 

416 lt: float | None = None, 

417 le: float | None = None, 

418 multiple_of: float | None = None, 

419 allow_inf_nan: bool | None = None, 

420) -> type[float]: 

421 """ 

422 !!! warning "Discouraged" 

423 This function is **discouraged** in favor of using 

424 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with 

425 [`Field`][pydantic.fields.Field] instead. 

426 

427 This function will be **deprecated** in Pydantic 3.0. 

428 

429 The reason is that `confloat` returns a type, which doesn't play well with static analysis tools. 

430 

431 === ":x: Don't do this" 

432 ```python 

433 from pydantic import BaseModel, confloat 

434 

435 class Foo(BaseModel): 

436 bar: confloat(strict=True, gt=0) 

437 ``` 

438 

439 === ":white_check_mark: Do this" 

440 ```python 

441 from typing import Annotated 

442 

443 from pydantic import BaseModel, Field 

444 

445 class Foo(BaseModel): 

446 bar: Annotated[float, Field(strict=True, gt=0)] 

447 ``` 

448 

449 A wrapper around `float` that allows for additional constraints. 

450 

451 Args: 

452 strict: Whether to validate the float in strict mode. 

453 gt: The value must be greater than this. 

454 ge: The value must be greater than or equal to this. 

455 lt: The value must be less than this. 

456 le: The value must be less than or equal to this. 

457 multiple_of: The value must be a multiple of this. 

458 allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. 

459 

460 Returns: 

461 The wrapped float type. 

462 

463 ```python 

464 from pydantic import BaseModel, ValidationError, confloat 

465 

466 class ConstrainedExample(BaseModel): 

467 constrained_float: confloat(gt=1.0) 

468 

469 m = ConstrainedExample(constrained_float=1.1) 

470 print(repr(m)) 

471 #> ConstrainedExample(constrained_float=1.1) 

472 

473 try: 

474 ConstrainedExample(constrained_float=0.9) 

475 except ValidationError as e: 

476 print(e.errors()) 

477 ''' 

478 [ 

479 { 

480 'type': 'greater_than', 

481 'loc': ('constrained_float',), 

482 'msg': 'Input should be greater than 1', 

483 'input': 0.9, 

484 'ctx': {'gt': 1.0}, 

485 'url': 'https://errors.pydantic.dev/2/v/greater_than', 

486 } 

487 ] 

488 ''' 

489 ``` 

490 """ # noqa: D212 

491 return Annotated[ # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

492 float, 

493 Strict(strict) if strict is not None else None, 

494 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), 

495 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, 

496 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None, 

497 ] 

498 

499 

500PositiveFloat = Annotated[float, annotated_types.Gt(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

501"""A float that must be greater than zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

502 

503```python 

504from pydantic import BaseModel, PositiveFloat, ValidationError 

505 

506class Model(BaseModel): 

507 positive_float: PositiveFloat 

508 

509m = Model(positive_float=1.0) 

510print(repr(m)) 

511#> Model(positive_float=1.0) 

512 

513try: 

514 Model(positive_float=-1.0) 

515except ValidationError as e: 

516 print(e.errors()) 

517 ''' 

518 [ 

519 { 

520 'type': 'greater_than', 

521 'loc': ('positive_float',), 

522 'msg': 'Input should be greater than 0', 

523 'input': -1.0, 

524 'ctx': {'gt': 0.0}, 

525 'url': 'https://errors.pydantic.dev/2/v/greater_than', 

526 } 

527 ] 

528 ''' 

529``` 

530""" 

531NegativeFloat = Annotated[float, annotated_types.Lt(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

532"""A float that must be less than zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

533 

534```python 

535from pydantic import BaseModel, NegativeFloat, ValidationError 

536 

537class Model(BaseModel): 

538 negative_float: NegativeFloat 

539 

540m = Model(negative_float=-1.0) 

541print(repr(m)) 

542#> Model(negative_float=-1.0) 

543 

544try: 

545 Model(negative_float=1.0) 

546except ValidationError as e: 

547 print(e.errors()) 

548 ''' 

549 [ 

550 { 

551 'type': 'less_than', 

552 'loc': ('negative_float',), 

553 'msg': 'Input should be less than 0', 

554 'input': 1.0, 

555 'ctx': {'lt': 0.0}, 

556 'url': 'https://errors.pydantic.dev/2/v/less_than', 

557 } 

558 ] 

559 ''' 

560``` 

561""" 

562NonPositiveFloat = Annotated[float, annotated_types.Le(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

563"""A float that must be less than or equal to zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

564 

565```python 

566from pydantic import BaseModel, NonPositiveFloat, ValidationError 

567 

568class Model(BaseModel): 

569 non_positive_float: NonPositiveFloat 

570 

571m = Model(non_positive_float=0.0) 

572print(repr(m)) 

573#> Model(non_positive_float=0.0) 

574 

575try: 

576 Model(non_positive_float=1.0) 

577except ValidationError as e: 

578 print(e.errors()) 

579 ''' 

580 [ 

581 { 

582 'type': 'less_than_equal', 

583 'loc': ('non_positive_float',), 

584 'msg': 'Input should be less than or equal to 0', 

585 'input': 1.0, 

586 'ctx': {'le': 0.0}, 

587 'url': 'https://errors.pydantic.dev/2/v/less_than_equal', 

588 } 

589 ] 

590 ''' 

591``` 

592""" 

593NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

594"""A float that must be greater than or equal to zero. 1bcdefghijaklmnopqrsJtuvwxyzAB

595 

596```python 

597from pydantic import BaseModel, NonNegativeFloat, ValidationError 

598 

599class Model(BaseModel): 

600 non_negative_float: NonNegativeFloat 

601 

602m = Model(non_negative_float=0.0) 

603print(repr(m)) 

604#> Model(non_negative_float=0.0) 

605 

606try: 

607 Model(non_negative_float=-1.0) 

608except ValidationError as e: 

609 print(e.errors()) 

610 ''' 

611 [ 

612 { 

613 'type': 'greater_than_equal', 

614 'loc': ('non_negative_float',), 

615 'msg': 'Input should be greater than or equal to 0', 

616 'input': -1.0, 

617 'ctx': {'ge': 0.0}, 

618 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal', 

619 } 

620 ] 

621 ''' 

622``` 

623""" 

624StrictFloat = Annotated[float, Strict(True)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

625"""A float that must be validated in strict mode. 1bcdefghijaklmnopqrsJtuvwxyzAB

626 

627```python 

628from pydantic import BaseModel, StrictFloat, ValidationError 

629 

630class StrictFloatModel(BaseModel): 

631 strict_float: StrictFloat 

632 

633try: 

634 StrictFloatModel(strict_float='1.0') 

635except ValidationError as e: 

636 print(e) 

637 ''' 

638 1 validation error for StrictFloatModel 

639 strict_float 

640 Input should be a valid number [type=float_type, input_value='1.0', input_type=str] 

641 ''' 

642``` 

643""" 

644FiniteFloat = Annotated[float, AllowInfNan(False)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

645"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). 1bcdefghijaklmnopqrsJtuvwxyzAB

646 

647```python 

648from pydantic import BaseModel, FiniteFloat 

649 

650class Model(BaseModel): 

651 finite: FiniteFloat 

652 

653m = Model(finite=1.0) 

654print(m) 

655#> finite=1.0 

656``` 

657""" 

658 

659 

660# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

661 

662 

663def conbytes( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

664 *, 

665 min_length: int | None = None, 

666 max_length: int | None = None, 

667 strict: bool | None = None, 

668) -> type[bytes]: 

669 """A wrapper around `bytes` that allows for additional constraints. 

670 

671 Args: 

672 min_length: The minimum length of the bytes. 

673 max_length: The maximum length of the bytes. 

674 strict: Whether to validate the bytes in strict mode. 

675 

676 Returns: 

677 The wrapped bytes type. 

678 """ 

679 return Annotated[ # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

680 bytes, 

681 Strict(strict) if strict is not None else None, 

682 annotated_types.Len(min_length or 0, max_length), 

683 ] 

684 

685 

686StrictBytes = Annotated[bytes, Strict()] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

687"""A bytes that must be validated in strict mode.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

688 

689 

690# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

691 

692 

693@_dataclasses.dataclass(frozen=True) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

694class StringConstraints(annotated_types.GroupedMetadata): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

695 """!!! abstract "Usage Documentation" 

696 [`StringConstraints`](../concepts/fields.md#string-constraints) 

697 

698 A field metadata class to apply constraints to `str` types. 

699 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. 

700 

701 Attributes: 

702 strip_whitespace: Whether to remove leading and trailing whitespace. 

703 to_upper: Whether to convert the string to uppercase. 

704 to_lower: Whether to convert the string to lowercase. 

705 strict: Whether to validate the string in strict mode. 

706 min_length: The minimum length of the string. 

707 max_length: The maximum length of the string. 

708 pattern: A regex pattern that the string must match. 

709 

710 Example: 

711 ```python 

712 from typing import Annotated 

713 

714 from pydantic.types import StringConstraints 

715 

716 ConstrainedStr = Annotated[str, StringConstraints(min_length=1, max_length=10)] 

717 ``` 

718 """ 

719 

720 strip_whitespace: bool | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

721 to_upper: bool | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

722 to_lower: bool | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

723 strict: bool | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

724 min_length: int | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

725 max_length: int | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

726 pattern: str | Pattern[str] | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

727 

728 def __iter__(self) -> Iterator[BaseMetadata]: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

729 if self.min_length is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

730 yield MinLen(self.min_length) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

731 if self.max_length is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

732 yield MaxLen(self.max_length) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

733 if self.strict is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

734 yield Strict(self.strict) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

735 if ( 1CDEa

736 self.strip_whitespace is not None 

737 or self.pattern is not None 

738 or self.to_lower is not None 

739 or self.to_upper is not None 

740 ): 

741 yield _fields.pydantic_general_metadata( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

742 strip_whitespace=self.strip_whitespace, 

743 to_upper=self.to_upper, 

744 to_lower=self.to_lower, 

745 pattern=self.pattern, 

746 ) 

747 

748 

749def constr( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

750 *, 

751 strip_whitespace: bool | None = None, 

752 to_upper: bool | None = None, 

753 to_lower: bool | None = None, 

754 strict: bool | None = None, 

755 min_length: int | None = None, 

756 max_length: int | None = None, 

757 pattern: str | Pattern[str] | None = None, 

758) -> type[str]: 

759 """ 

760 !!! warning "Discouraged" 

761 This function is **discouraged** in favor of using 

762 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with 

763 [`StringConstraints`][pydantic.types.StringConstraints] instead. 

764 

765 This function will be **deprecated** in Pydantic 3.0. 

766 

767 The reason is that `constr` returns a type, which doesn't play well with static analysis tools. 

768 

769 === ":x: Don't do this" 

770 ```python 

771 from pydantic import BaseModel, constr 

772 

773 class Foo(BaseModel): 

774 bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$') 

775 ``` 

776 

777 === ":white_check_mark: Do this" 

778 ```python 

779 from typing import Annotated 

780 

781 from pydantic import BaseModel, StringConstraints 

782 

783 class Foo(BaseModel): 

784 bar: Annotated[ 

785 str, 

786 StringConstraints( 

787 strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$' 

788 ), 

789 ] 

790 ``` 

791 

792 A wrapper around `str` that allows for additional constraints. 

793 

794 ```python 

795 from pydantic import BaseModel, constr 

796 

797 class Foo(BaseModel): 

798 bar: constr(strip_whitespace=True, to_upper=True) 

799 

800 foo = Foo(bar=' hello ') 

801 print(foo) 

802 #> bar='HELLO' 

803 ``` 

804 

805 Args: 

806 strip_whitespace: Whether to remove leading and trailing whitespace. 

807 to_upper: Whether to turn all characters to uppercase. 

808 to_lower: Whether to turn all characters to lowercase. 

809 strict: Whether to validate the string in strict mode. 

810 min_length: The minimum length of the string. 

811 max_length: The maximum length of the string. 

812 pattern: A regex pattern to validate the string against. 

813 

814 Returns: 

815 The wrapped string type. 

816 """ # noqa: D212 

817 return Annotated[ # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

818 str, 

819 StringConstraints( 

820 strip_whitespace=strip_whitespace, 

821 to_upper=to_upper, 

822 to_lower=to_lower, 

823 strict=strict, 

824 min_length=min_length, 

825 max_length=max_length, 

826 pattern=pattern, 

827 ), 

828 ] 

829 

830 

831StrictStr = Annotated[str, Strict()] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

832"""A string that must be validated in strict mode.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

833 

834 

835# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

836HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

837 

838 

839def conset( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

840 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None 

841) -> type[set[HashableItemType]]: 

842 """A wrapper around `typing.Set` that allows for additional constraints. 

843 

844 Args: 

845 item_type: The type of the items in the set. 

846 min_length: The minimum length of the set. 

847 max_length: The maximum length of the set. 

848 

849 Returns: 

850 The wrapped set type. 

851 """ 

852 return Annotated[set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

853 

854 

855def confrozenset( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

856 item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None 

857) -> type[frozenset[HashableItemType]]: 

858 """A wrapper around `typing.FrozenSet` that allows for additional constraints. 

859 

860 Args: 

861 item_type: The type of the items in the frozenset. 

862 min_length: The minimum length of the frozenset. 

863 max_length: The maximum length of the frozenset. 

864 

865 Returns: 

866 The wrapped frozenset type. 

867 """ 

868 return Annotated[frozenset[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

869 

870 

871AnyItemType = TypeVar('AnyItemType') 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

872 

873 

874def conlist( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

875 item_type: type[AnyItemType], 

876 *, 

877 min_length: int | None = None, 

878 max_length: int | None = None, 

879 unique_items: bool | None = None, 

880) -> type[list[AnyItemType]]: 

881 """A wrapper around [`list`][] that adds validation. 

882 

883 Args: 

884 item_type: The type of the items in the list. 

885 min_length: The minimum length of the list. Defaults to None. 

886 max_length: The maximum length of the list. Defaults to None. 

887 unique_items: Whether the items in the list must be unique. Defaults to None. 

888 !!! warning Deprecated 

889 The `unique_items` parameter is deprecated, use `Set` instead. 

890 See [this issue](https://github.com/pydantic/pydantic-core/issues/296) for more details. 

891 

892 Returns: 

893 The wrapped list type. 

894 """ 

895 if unique_items is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

896 raise PydanticUserError( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

897 ( 

898 '`unique_items` is removed, use `Set` instead' 

899 '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)' 

900 ), 

901 code='removed-kwargs', 

902 ) 

903 return Annotated[list[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

904 

905 

906# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

907 

908AnyType = TypeVar('AnyType') 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

909if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

910 ImportString = Annotated[AnyType, ...] 

911else: 

912 

913 class ImportString: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

914 """A type that can be used to import a Python object from a string. 

915 

916 `ImportString` expects a string and loads the Python object importable at that dotted path. 

917 Attributes of modules may be separated from the module by `:` or `.`, e.g. if `'math:cos'` is provided, 

918 the resulting field value would be the function `cos`. If a `.` is used and both an attribute and submodule 

919 are present at the same path, the module will be preferred. 

920 

921 On model instantiation, pointers will be evaluated and imported. There is 

922 some nuance to this behavior, demonstrated in the examples below. 

923 

924 ```python 

925 import math 

926 

927 from pydantic import BaseModel, Field, ImportString, ValidationError 

928 

929 class ImportThings(BaseModel): 

930 obj: ImportString 

931 

932 # A string value will cause an automatic import 

933 my_cos = ImportThings(obj='math.cos') 

934 

935 # You can use the imported function as you would expect 

936 cos_of_0 = my_cos.obj(0) 

937 assert cos_of_0 == 1 

938 

939 # A string whose value cannot be imported will raise an error 

940 try: 

941 ImportThings(obj='foo.bar') 

942 except ValidationError as e: 

943 print(e) 

944 ''' 

945 1 validation error for ImportThings 

946 obj 

947 Invalid python path: No module named 'foo.bar' [type=import_error, input_value='foo.bar', input_type=str] 

948 ''' 

949 

950 # Actual python objects can be assigned as well 

951 my_cos = ImportThings(obj=math.cos) 

952 my_cos_2 = ImportThings(obj='math.cos') 

953 my_cos_3 = ImportThings(obj='math:cos') 

954 assert my_cos == my_cos_2 == my_cos_3 

955 

956 # You can set default field value either as Python object: 

957 class ImportThingsDefaultPyObj(BaseModel): 

958 obj: ImportString = math.cos 

959 

960 # or as a string value (but only if used with `validate_default=True`) 

961 class ImportThingsDefaultString(BaseModel): 

962 obj: ImportString = Field(default='math.cos', validate_default=True) 

963 

964 my_cos_default1 = ImportThingsDefaultPyObj() 

965 my_cos_default2 = ImportThingsDefaultString() 

966 assert my_cos_default1.obj == my_cos_default2.obj == math.cos 

967 

968 # note: this will not work! 

969 class ImportThingsMissingValidateDefault(BaseModel): 

970 obj: ImportString = 'math.cos' 

971 

972 my_cos_default3 = ImportThingsMissingValidateDefault() 

973 assert my_cos_default3.obj == 'math.cos' # just string, not evaluated 

974 ``` 

975 

976 Serializing an `ImportString` type to json is also possible. 

977 

978 ```python 

979 from pydantic import BaseModel, ImportString 

980 

981 class ImportThings(BaseModel): 

982 obj: ImportString 

983 

984 # Create an instance 

985 m = ImportThings(obj='math.cos') 

986 print(m) 

987 #> obj=<built-in function cos> 

988 print(m.model_dump_json()) 

989 #> {"obj":"math.cos"} 

990 ``` 

991 """ 

992 

993 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

994 def __class_getitem__(cls, item: AnyType) -> AnyType: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

995 return Annotated[item, cls()] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

996 

997 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

998 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

999 cls, source: type[Any], handler: GetCoreSchemaHandler 

1000 ) -> core_schema.CoreSchema: 

1001 serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1002 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1003 # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any] 

1004 return core_schema.no_info_plain_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1005 function=_validators.import_string, serialization=serializer 

1006 ) 

1007 else: 

1008 return core_schema.no_info_before_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1009 function=_validators.import_string, schema=handler(source), serialization=serializer 

1010 ) 

1011 

1012 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1013 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1014 return handler(core_schema.str_schema()) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1015 

1016 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1017 def _serialize(v: Any) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1018 if isinstance(v, ModuleType): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1019 return v.__name__ 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1020 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1021 return f'{v.__module__}.{v.__name__}' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1022 # Handle special cases for sys.XXX streams 

1023 # if we see more of these, we should consider a more general solution 

1024 elif hasattr(v, 'name'): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1025 if v.name == '<stdout>': 1025 ↛ 1026line 1025 didn't jump to line 1026 because the condition on line 1025 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1026 return 'sys.stdout' 

1027 elif v.name == '<stdin>': 1027 ↛ 1028line 1027 didn't jump to line 1028 because the condition on line 1027 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1028 return 'sys.stdin' 

1029 elif v.name == '<stderr>': 1029 ↛ 1030line 1029 didn't jump to line 1030 because the condition on line 1029 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1030 return 'sys.stderr' 

1031 else: 

1032 return v 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1033 

1034 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1035 return 'ImportString' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1036 

1037 

1038# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1039 

1040 

1041def condecimal( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1042 *, 

1043 strict: bool | None = None, 

1044 gt: int | Decimal | None = None, 

1045 ge: int | Decimal | None = None, 

1046 lt: int | Decimal | None = None, 

1047 le: int | Decimal | None = None, 

1048 multiple_of: int | Decimal | None = None, 

1049 max_digits: int | None = None, 

1050 decimal_places: int | None = None, 

1051 allow_inf_nan: bool | None = None, 

1052) -> type[Decimal]: 

1053 """ 

1054 !!! warning "Discouraged" 

1055 This function is **discouraged** in favor of using 

1056 [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with 

1057 [`Field`][pydantic.fields.Field] instead. 

1058 

1059 This function will be **deprecated** in Pydantic 3.0. 

1060 

1061 The reason is that `condecimal` returns a type, which doesn't play well with static analysis tools. 

1062 

1063 === ":x: Don't do this" 

1064 ```python 

1065 from pydantic import BaseModel, condecimal 

1066 

1067 class Foo(BaseModel): 

1068 bar: condecimal(strict=True, allow_inf_nan=True) 

1069 ``` 

1070 

1071 === ":white_check_mark: Do this" 

1072 ```python 

1073 from decimal import Decimal 

1074 from typing import Annotated 

1075 

1076 from pydantic import BaseModel, Field 

1077 

1078 class Foo(BaseModel): 

1079 bar: Annotated[Decimal, Field(strict=True, allow_inf_nan=True)] 

1080 ``` 

1081 

1082 A wrapper around Decimal that adds validation. 

1083 

1084 Args: 

1085 strict: Whether to validate the value in strict mode. Defaults to `None`. 

1086 gt: The value must be greater than this. Defaults to `None`. 

1087 ge: The value must be greater than or equal to this. Defaults to `None`. 

1088 lt: The value must be less than this. Defaults to `None`. 

1089 le: The value must be less than or equal to this. Defaults to `None`. 

1090 multiple_of: The value must be a multiple of this. Defaults to `None`. 

1091 max_digits: The maximum number of digits. Defaults to `None`. 

1092 decimal_places: The number of decimal places. Defaults to `None`. 

1093 allow_inf_nan: Whether to allow infinity and NaN. Defaults to `None`. 

1094 

1095 ```python 

1096 from decimal import Decimal 

1097 

1098 from pydantic import BaseModel, ValidationError, condecimal 

1099 

1100 class ConstrainedExample(BaseModel): 

1101 constrained_decimal: condecimal(gt=Decimal('1.0')) 

1102 

1103 m = ConstrainedExample(constrained_decimal=Decimal('1.1')) 

1104 print(repr(m)) 

1105 #> ConstrainedExample(constrained_decimal=Decimal('1.1')) 

1106 

1107 try: 

1108 ConstrainedExample(constrained_decimal=Decimal('0.9')) 

1109 except ValidationError as e: 

1110 print(e.errors()) 

1111 ''' 

1112 [ 

1113 { 

1114 'type': 'greater_than', 

1115 'loc': ('constrained_decimal',), 

1116 'msg': 'Input should be greater than 1.0', 

1117 'input': Decimal('0.9'), 

1118 'ctx': {'gt': Decimal('1.0')}, 

1119 'url': 'https://errors.pydantic.dev/2/v/greater_than', 

1120 } 

1121 ] 

1122 ''' 

1123 ``` 

1124 """ # noqa: D212 

1125 return Annotated[ # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1126 Decimal, 

1127 Strict(strict) if strict is not None else None, 

1128 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), 

1129 annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, 

1130 _fields.pydantic_general_metadata(max_digits=max_digits, decimal_places=decimal_places), 

1131 AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None, 

1132 ] 

1133 

1134 

1135# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1136 

1137 

1138@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1139class UuidVersion: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1140 """A field metadata class to indicate a [UUID](https://docs.python.org/3/library/uuid.html) version. 

1141 

1142 Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. 

1143 

1144 Attributes: 

1145 uuid_version: The version of the UUID. Must be one of 1, 3, 4, 5, or 7. 

1146 

1147 Example: 

1148 ```python 

1149 from typing import Annotated 

1150 from uuid import UUID 

1151 

1152 from pydantic.types import UuidVersion 

1153 

1154 UUID1 = Annotated[UUID, UuidVersion(1)] 

1155 ``` 

1156 """ 

1157 

1158 uuid_version: Literal[1, 3, 4, 5, 6, 7, 8] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1159 

1160 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1161 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

1162 ) -> JsonSchemaValue: 

1163 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1164 field_schema.pop('anyOf', None) # remove the bytes/str union 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1165 field_schema.update(type='string', format=f'uuid{self.uuid_version}') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1166 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1167 

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

1169 if isinstance(self, source): 1169 ↛ 1171line 1169 didn't jump to line 1171 because the condition on line 1169 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1170 # used directly as a type 

1171 return core_schema.uuid_schema(version=self.uuid_version) 

1172 else: 

1173 # update existing schema with self.uuid_version 

1174 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1175 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1176 schema['version'] = self.uuid_version # type: ignore 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1177 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1178 

1179 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1180 return hash(type(self.uuid_version)) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1181 

1182 

1183UUID1 = Annotated[UUID, UuidVersion(1)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1184"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. 1bcdefghijaklmnopqrsJtuvwxyzAB

1185 

1186```python 

1187import uuid 

1188 

1189from pydantic import UUID1, BaseModel 

1190 

1191class Model(BaseModel): 

1192 uuid1: UUID1 

1193 

1194Model(uuid1=uuid.uuid1()) 

1195``` 

1196""" 

1197UUID3 = Annotated[UUID, UuidVersion(3)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1198"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. 1bcdefghijaklmnopqrsJtuvwxyzAB

1199 

1200```python 

1201import uuid 

1202 

1203from pydantic import UUID3, BaseModel 

1204 

1205class Model(BaseModel): 

1206 uuid3: UUID3 

1207 

1208Model(uuid3=uuid.uuid3(uuid.NAMESPACE_DNS, 'pydantic.org')) 

1209``` 

1210""" 

1211UUID4 = Annotated[UUID, UuidVersion(4)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1212"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. 1bcdefghijaklmnopqrsJtuvwxyzAB

1213 

1214```python 

1215import uuid 

1216 

1217from pydantic import UUID4, BaseModel 

1218 

1219class Model(BaseModel): 

1220 uuid4: UUID4 

1221 

1222Model(uuid4=uuid.uuid4()) 

1223``` 

1224""" 

1225UUID5 = Annotated[UUID, UuidVersion(5)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1226"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. 1bcdefghijaklmnopqrsJtuvwxyzAB

1227 

1228```python 

1229import uuid 

1230 

1231from pydantic import UUID5, BaseModel 

1232 

1233class Model(BaseModel): 

1234 uuid5: UUID5 

1235 

1236Model(uuid5=uuid.uuid5(uuid.NAMESPACE_DNS, 'pydantic.org')) 

1237``` 

1238""" 

1239UUID6 = Annotated[UUID, UuidVersion(6)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1240"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 6. 1bcdefghijaklmnopqrsJtuvwxyzAB

1241 

1242```python 

1243import uuid 

1244 

1245from pydantic import UUID6, BaseModel 

1246 

1247class Model(BaseModel): 

1248 uuid6: UUID6 

1249 

1250Model(uuid6=uuid.UUID('1efea953-c2d6-6790-aa0a-69db8c87df97')) 

1251``` 

1252""" 

1253UUID7 = Annotated[UUID, UuidVersion(7)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1254"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 7. 1bcdefghijaklmnopqrsJtuvwxyzAB

1255 

1256```python 

1257import uuid 

1258 

1259from pydantic import UUID7, BaseModel 

1260 

1261class Model(BaseModel): 

1262 uuid7: UUID7 

1263 

1264Model(uuid7=uuid.UUID('0194fdcb-1c47-7a09-b52c-561154de0b4a')) 

1265``` 

1266""" 

1267UUID8 = Annotated[UUID, UuidVersion(8)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1268"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 8. 1bcdefghijaklmnopqrsJtuvwxyzAB

1269 

1270```python 

1271import uuid 

1272 

1273from pydantic import UUID8, BaseModel 

1274 

1275class Model(BaseModel): 

1276 uuid8: UUID8 

1277 

1278Model(uuid8=uuid.UUID('81a0b92e-6078-8551-9c81-8ccb666bdab8')) 

1279``` 

1280""" 

1281 

1282# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1283 

1284 

1285@_dataclasses.dataclass 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1286class PathType: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1287 path_type: Literal['file', 'dir', 'new', 'socket'] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1288 

1289 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1290 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

1291 ) -> JsonSchemaValue: 

1292 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1293 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1294 field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1295 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1296 

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

1298 function_lookup = { 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1299 'file': cast(core_schema.WithInfoValidatorFunction, self.validate_file), 

1300 'dir': cast(core_schema.WithInfoValidatorFunction, self.validate_directory), 

1301 'new': cast(core_schema.WithInfoValidatorFunction, self.validate_new), 

1302 'socket': cast(core_schema.WithInfoValidatorFunction, self.validate_socket), 

1303 } 

1304 

1305 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1306 function_lookup[self.path_type], 

1307 handler(source), 

1308 ) 

1309 

1310 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1311 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1312 if path.is_file(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1313 return path 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1314 else: 

1315 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1316 

1317 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1318 def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1319 if path.is_socket(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1320 return path 1CDbcdefghijEa

1321 else: 

1322 raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1323 

1324 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1325 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1326 if path.is_dir(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1327 return path 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1328 else: 

1329 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1330 

1331 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1332 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1333 if path.exists(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1334 raise PydanticCustomError('path_exists', 'Path already exists') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1335 elif not path.parent.exists(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1336 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1337 else: 

1338 return path 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1339 

1340 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1341 return hash(type(self.path_type)) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1342 

1343 

1344FilePath = Annotated[Path, PathType('file')] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1345"""A path that must point to a file. 1bcdefghijaklmnopqrsJtuvwxyzAB

1346 

1347```python 

1348from pathlib import Path 

1349 

1350from pydantic import BaseModel, FilePath, ValidationError 

1351 

1352class Model(BaseModel): 

1353 f: FilePath 

1354 

1355path = Path('text.txt') 

1356path.touch() 

1357m = Model(f='text.txt') 

1358print(m.model_dump()) 

1359#> {'f': PosixPath('text.txt')} 

1360path.unlink() 

1361 

1362path = Path('directory') 

1363path.mkdir(exist_ok=True) 

1364try: 

1365 Model(f='directory') # directory 

1366except ValidationError as e: 

1367 print(e) 

1368 ''' 

1369 1 validation error for Model 

1370 f 

1371 Path does not point to a file [type=path_not_file, input_value='directory', input_type=str] 

1372 ''' 

1373path.rmdir() 

1374 

1375try: 

1376 Model(f='not-exists-file') 

1377except ValidationError as e: 

1378 print(e) 

1379 ''' 

1380 1 validation error for Model 

1381 f 

1382 Path does not point to a file [type=path_not_file, input_value='not-exists-file', input_type=str] 

1383 ''' 

1384``` 

1385""" 

1386DirectoryPath = Annotated[Path, PathType('dir')] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1387"""A path that must point to a directory. 1bcdefghijaklmnopqrsJtuvwxyzAB

1388 

1389```python 

1390from pathlib import Path 

1391 

1392from pydantic import BaseModel, DirectoryPath, ValidationError 

1393 

1394class Model(BaseModel): 

1395 f: DirectoryPath 

1396 

1397path = Path('directory/') 

1398path.mkdir() 

1399m = Model(f='directory/') 

1400print(m.model_dump()) 

1401#> {'f': PosixPath('directory')} 

1402path.rmdir() 

1403 

1404path = Path('file.txt') 

1405path.touch() 

1406try: 

1407 Model(f='file.txt') # file 

1408except ValidationError as e: 

1409 print(e) 

1410 ''' 

1411 1 validation error for Model 

1412 f 

1413 Path does not point to a directory [type=path_not_directory, input_value='file.txt', input_type=str] 

1414 ''' 

1415path.unlink() 

1416 

1417try: 

1418 Model(f='not-exists-directory') 

1419except ValidationError as e: 

1420 print(e) 

1421 ''' 

1422 1 validation error for Model 

1423 f 

1424 Path does not point to a directory [type=path_not_directory, input_value='not-exists-directory', input_type=str] 

1425 ''' 

1426``` 

1427""" 

1428NewPath = Annotated[Path, PathType('new')] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1429"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

1430 

1431SocketPath = Annotated[Path, PathType('socket')] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1432"""A path to an existing socket file""" 1bcdefghijaklmnopqrsJtuvwxyzAB

1433 

1434# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1435 

1436if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1437 # Json[list[str]] will be recognized by type checkers as list[str] 

1438 Json = Annotated[AnyType, ...] 

1439 

1440else: 

1441 

1442 class Json: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1443 """A special type wrapper which loads JSON before parsing. 

1444 

1445 You can use the `Json` data type to make Pydantic first load a raw JSON string before 

1446 validating the loaded data into the parametrized type: 

1447 

1448 ```python 

1449 from typing import Any 

1450 

1451 from pydantic import BaseModel, Json, ValidationError 

1452 

1453 class AnyJsonModel(BaseModel): 

1454 json_obj: Json[Any] 

1455 

1456 class ConstrainedJsonModel(BaseModel): 

1457 json_obj: Json[list[int]] 

1458 

1459 print(AnyJsonModel(json_obj='{"b": 1}')) 

1460 #> json_obj={'b': 1} 

1461 print(ConstrainedJsonModel(json_obj='[1, 2, 3]')) 

1462 #> json_obj=[1, 2, 3] 

1463 

1464 try: 

1465 ConstrainedJsonModel(json_obj=12) 

1466 except ValidationError as e: 

1467 print(e) 

1468 ''' 

1469 1 validation error for ConstrainedJsonModel 

1470 json_obj 

1471 JSON input should be string, bytes or bytearray [type=json_type, input_value=12, input_type=int] 

1472 ''' 

1473 

1474 try: 

1475 ConstrainedJsonModel(json_obj='[a, b]') 

1476 except ValidationError as e: 

1477 print(e) 

1478 ''' 

1479 1 validation error for ConstrainedJsonModel 

1480 json_obj 

1481 Invalid JSON: expected value at line 1 column 2 [type=json_invalid, input_value='[a, b]', input_type=str] 

1482 ''' 

1483 

1484 try: 

1485 ConstrainedJsonModel(json_obj='["a", "b"]') 

1486 except ValidationError as e: 

1487 print(e) 

1488 ''' 

1489 2 validation errors for ConstrainedJsonModel 

1490 json_obj.0 

1491 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] 

1492 json_obj.1 

1493 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='b', input_type=str] 

1494 ''' 

1495 ``` 

1496 

1497 When you dump the model using `model_dump` or `model_dump_json`, the dumped value will be the result of validation, 

1498 not the original JSON string. However, you can use the argument `round_trip=True` to get the original JSON string back: 

1499 

1500 ```python 

1501 from pydantic import BaseModel, Json 

1502 

1503 class ConstrainedJsonModel(BaseModel): 

1504 json_obj: Json[list[int]] 

1505 

1506 print(ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json()) 

1507 #> {"json_obj":[1,2,3]} 

1508 print( 

1509 ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json(round_trip=True) 

1510 ) 

1511 #> {"json_obj":"[1,2,3]"} 

1512 ``` 

1513 """ 

1514 

1515 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1516 def __class_getitem__(cls, item: AnyType) -> AnyType: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1517 return Annotated[item, cls()] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1518 

1519 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1521 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1522 return core_schema.json_schema(None) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1523 else: 

1524 return core_schema.json_schema(handler(source)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1525 

1526 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1527 return 'Json' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1528 

1529 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1530 return hash(type(self)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1531 

1532 def __eq__(self, other: Any) -> bool: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1533 return type(other) is type(self) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1534 

1535 

1536# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1537 

1538SecretType = TypeVar('SecretType') 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1539 

1540 

1541class _SecretBase(Generic[SecretType]): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1542 def __init__(self, secret_value: SecretType) -> None: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1543 self._secret_value: SecretType = secret_value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1544 

1545 def get_secret_value(self) -> SecretType: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1546 """Get the secret value. 

1547 

1548 Returns: 

1549 The secret value. 

1550 """ 

1551 return self._secret_value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1552 

1553 def __eq__(self, other: Any) -> bool: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1554 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1555 

1556 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1557 return hash(self.get_secret_value()) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1558 

1559 def __str__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1560 return str(self._display()) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1561 

1562 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1563 return f'{self.__class__.__name__}({self._display()!r})' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1564 

1565 def _display(self) -> str | bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1566 raise NotImplementedError 

1567 

1568 

1569def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1570 if info.mode == 'json': 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1571 return str(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1572 else: 

1573 return value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1574 

1575 

1576class Secret(_SecretBase[SecretType]): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1577 """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks. 

1578 

1579 You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing 

1580 is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both 

1581 ways of using `Secret` to create a new secret type. 

1582 

1583 1. Directly parametrizing `Secret` with a type: 

1584 

1585 ```python 

1586 from pydantic import BaseModel, Secret 

1587 

1588 SecretBool = Secret[bool] 

1589 

1590 class Model(BaseModel): 

1591 secret_bool: SecretBool 

1592 

1593 m = Model(secret_bool=True) 

1594 print(m.model_dump()) 

1595 #> {'secret_bool': Secret('**********')} 

1596 

1597 print(m.model_dump_json()) 

1598 #> {"secret_bool":"**********"} 

1599 

1600 print(m.secret_bool.get_secret_value()) 

1601 #> True 

1602 ``` 

1603 

1604 2. Subclassing from parametrized `Secret`: 

1605 

1606 ```python 

1607 from datetime import date 

1608 

1609 from pydantic import BaseModel, Secret 

1610 

1611 class SecretDate(Secret[date]): 

1612 def _display(self) -> str: 

1613 return '****/**/**' 

1614 

1615 class Model(BaseModel): 

1616 secret_date: SecretDate 

1617 

1618 m = Model(secret_date=date(2022, 1, 1)) 

1619 print(m.model_dump()) 

1620 #> {'secret_date': SecretDate('****/**/**')} 

1621 

1622 print(m.model_dump_json()) 

1623 #> {"secret_date":"****/**/**"} 

1624 

1625 print(m.secret_date.get_secret_value()) 

1626 #> 2022-01-01 

1627 ``` 

1628 

1629 The value returned by the `_display` method will be used for `repr()` and `str()`. 

1630 

1631 You can enforce constraints on the underlying type through annotations: 

1632 For example: 

1633 

1634 ```python 

1635 from typing import Annotated 

1636 

1637 from pydantic import BaseModel, Field, Secret, ValidationError 

1638 

1639 SecretPosInt = Secret[Annotated[int, Field(gt=0, strict=True)]] 

1640 

1641 class Model(BaseModel): 

1642 sensitive_int: SecretPosInt 

1643 

1644 m = Model(sensitive_int=42) 

1645 print(m.model_dump()) 

1646 #> {'sensitive_int': Secret('**********')} 

1647 

1648 try: 

1649 m = Model(sensitive_int=-42) # (1)! 

1650 except ValidationError as exc_info: 

1651 print(exc_info.errors(include_url=False, include_input=False)) 

1652 ''' 

1653 [ 

1654 { 

1655 'type': 'greater_than', 

1656 'loc': ('sensitive_int',), 

1657 'msg': 'Input should be greater than 0', 

1658 'ctx': {'gt': 0}, 

1659 } 

1660 ] 

1661 ''' 

1662 

1663 try: 

1664 m = Model(sensitive_int='42') # (2)! 

1665 except ValidationError as exc_info: 

1666 print(exc_info.errors(include_url=False, include_input=False)) 

1667 ''' 

1668 [ 

1669 { 

1670 'type': 'int_type', 

1671 'loc': ('sensitive_int',), 

1672 'msg': 'Input should be a valid integer', 

1673 } 

1674 ] 

1675 ''' 

1676 ``` 

1677 

1678 1. The input value is not greater than 0, so it raises a validation error. 

1679 2. The input value is not an integer, so it raises a validation error because the `SecretPosInt` type has strict mode enabled. 

1680 """ 

1681 

1682 def _display(self) -> str | bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1683 return '**********' if self.get_secret_value() else '' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1684 

1685 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1686 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1687 inner_type = None 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1688 # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly 

1689 origin_type = get_origin(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1690 if origin_type is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1691 inner_type = get_args(source)[0] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1692 # otherwise, we need to get the inner type from the base class 

1693 else: 

1694 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1695 for base in bases: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1696 if get_origin(base) is Secret: 1696 ↛ 1695line 1696 didn't jump to line 1695 because the condition on line 1696 was always true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1697 inner_type = get_args(base)[0] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1698 if bases == [] or inner_type is None: 1698 ↛ 1699line 1698 didn't jump to line 1699 because the condition on line 1698 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1699 raise TypeError( 

1700 f"Can't get secret type from {cls.__name__}. " 

1701 'Please use Secret[<type>], or subclass from Secret[<type>] instead.' 

1702 ) 

1703 

1704 inner_schema = handler.generate_schema(inner_type) # type: ignore 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1705 

1706 def validate_secret_value(value, handler) -> Secret[SecretType]: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1707 if isinstance(value, Secret): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1708 value = value.get_secret_value() 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1709 validated_inner = handler(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1710 return cls(validated_inner) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1711 

1712 return core_schema.json_or_python_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1713 python_schema=core_schema.no_info_wrap_validator_function( 

1714 validate_secret_value, 

1715 inner_schema, 

1716 ), 

1717 json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema), 

1718 serialization=core_schema.plain_serializer_function_ser_schema( 

1719 _serialize_secret, 

1720 info_arg=True, 

1721 when_used='always', 

1722 ), 

1723 ) 

1724 

1725 __pydantic_serializer__ = SchemaSerializer( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1726 core_schema.any_schema( 

1727 serialization=core_schema.plain_serializer_function_ser_schema( 

1728 _serialize_secret, 

1729 info_arg=True, 

1730 when_used='always', 

1731 ) 

1732 ) 

1733 ) 

1734 

1735 

1736def _secret_display(value: SecretType) -> str: # type: ignore 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1737 return '**********' if value else '' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1738 

1739 

1740def _serialize_secret_field( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1741 value: _SecretField[SecretType], info: core_schema.SerializationInfo 

1742) -> str | _SecretField[SecretType]: 

1743 if info.mode == 'json': 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1744 # we want the output to always be string without the `b'` prefix for bytes, 

1745 # hence we just use `secret_display` 

1746 return _secret_display(value.get_secret_value()) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1747 else: 

1748 return value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1749 

1750 

1751class _SecretField(_SecretBase[SecretType]): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1752 _inner_schema: ClassVar[CoreSchema] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1753 _error_kind: ClassVar[str] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1754 

1755 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1756 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1757 def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1758 json_schema = handler(cls._inner_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1759 _utils.update_not_none( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1760 json_schema, 

1761 type='string', 

1762 writeOnly=True, 

1763 format='password', 

1764 ) 

1765 return json_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1766 

1767 def get_secret_schema(strict: bool) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1768 inner_schema = {**cls._inner_schema, 'strict': strict} 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1769 json_schema = core_schema.no_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1770 source, # construct the type 

1771 inner_schema, # pyright: ignore[reportArgumentType] 

1772 ) 

1773 return core_schema.json_or_python_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1774 python_schema=core_schema.union_schema( 

1775 [ 

1776 core_schema.is_instance_schema(source), 

1777 json_schema, 

1778 ], 

1779 custom_error_type=cls._error_kind, 

1780 ), 

1781 json_schema=json_schema, 

1782 serialization=core_schema.plain_serializer_function_ser_schema( 

1783 _serialize_secret_field, 

1784 info_arg=True, 

1785 when_used='always', 

1786 ), 

1787 ) 

1788 

1789 return core_schema.lax_or_strict_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1790 lax_schema=get_secret_schema(strict=False), 

1791 strict_schema=get_secret_schema(strict=True), 

1792 metadata={'pydantic_js_functions': [get_json_schema]}, 

1793 ) 

1794 

1795 __pydantic_serializer__ = SchemaSerializer( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1796 core_schema.any_schema( 

1797 serialization=core_schema.plain_serializer_function_ser_schema( 

1798 _serialize_secret_field, 

1799 info_arg=True, 

1800 when_used='always', 

1801 ) 

1802 ) 

1803 ) 

1804 

1805 

1806class SecretStr(_SecretField[str]): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1807 """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks. 

1808 

1809 When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in 

1810 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`. 

1811 

1812 ```python 

1813 from pydantic import BaseModel, SecretStr 

1814 

1815 class User(BaseModel): 

1816 username: str 

1817 password: SecretStr 

1818 

1819 user = User(username='scolvin', password='password1') 

1820 

1821 print(user) 

1822 #> username='scolvin' password=SecretStr('**********') 

1823 print(user.password.get_secret_value()) 

1824 #> password1 

1825 print((SecretStr('password'), SecretStr(''))) 

1826 #> (SecretStr('**********'), SecretStr('')) 

1827 ``` 

1828 

1829 As seen above, by default, [`SecretStr`][pydantic.types.SecretStr] (and [`SecretBytes`][pydantic.types.SecretBytes]) 

1830 will be serialized as `**********` when serializing to json. 

1831 

1832 You can use the [`field_serializer`][pydantic.functional_serializers.field_serializer] to dump the 

1833 secret as plain-text when serializing to json. 

1834 

1835 ```python 

1836 from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer 

1837 

1838 class Model(BaseModel): 

1839 password: SecretStr 

1840 password_bytes: SecretBytes 

1841 

1842 @field_serializer('password', 'password_bytes', when_used='json') 

1843 def dump_secret(self, v): 

1844 return v.get_secret_value() 

1845 

1846 model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes') 

1847 print(model) 

1848 #> password=SecretStr('**********') password_bytes=SecretBytes(b'**********') 

1849 print(model.password) 

1850 #> ********** 

1851 print(model.model_dump()) 

1852 ''' 

1853 { 

1854 'password': SecretStr('**********'), 

1855 'password_bytes': SecretBytes(b'**********'), 

1856 } 

1857 ''' 

1858 print(model.model_dump_json()) 

1859 #> {"password":"IAmSensitive","password_bytes":"IAmSensitiveBytes"} 

1860 ``` 

1861 """ 

1862 

1863 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1864 _error_kind: ClassVar[str] = 'string_type' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1865 

1866 def __len__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1867 return len(self._secret_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1868 

1869 def _display(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1870 return _secret_display(self._secret_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1871 

1872 

1873class SecretBytes(_SecretField[bytes]): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1874 """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks. 

1875 

1876 It displays `b'**********'` instead of the string value on `repr()` and `str()` calls. 

1877 When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in 

1878 calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`. 

1879 

1880 ```python 

1881 from pydantic import BaseModel, SecretBytes 

1882 

1883 class User(BaseModel): 

1884 username: str 

1885 password: SecretBytes 

1886 

1887 user = User(username='scolvin', password=b'password1') 

1888 #> username='scolvin' password=SecretBytes(b'**********') 

1889 print(user.password.get_secret_value()) 

1890 #> b'password1' 

1891 print((SecretBytes(b'password'), SecretBytes(b''))) 

1892 #> (SecretBytes(b'**********'), SecretBytes(b'')) 

1893 ``` 

1894 """ 

1895 

1896 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1897 _error_kind: ClassVar[str] = 'bytes_type' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1898 

1899 def __len__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1900 return len(self._secret_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1901 

1902 def _display(self) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1903 return _secret_display(self._secret_value).encode() 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1904 

1905 

1906# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1907 

1908 

1909class PaymentCardBrand(str, Enum): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1910 amex = 'American Express' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1911 mastercard = 'Mastercard' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1912 visa = 'Visa' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1913 other = 'other' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1914 

1915 def __str__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1916 return self.value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1917 

1918 

1919@deprecated( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1920 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. ' 

1921 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.', 

1922 category=PydanticDeprecatedSince20, 

1923) 

1924class PaymentCardNumber(str): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1925 """Based on: https://en.wikipedia.org/wiki/Payment_card_number.""" 

1926 

1927 strip_whitespace: ClassVar[bool] = True 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1928 min_length: ClassVar[int] = 12 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1929 max_length: ClassVar[int] = 19 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1930 bin: str 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1931 last4: str 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1932 brand: PaymentCardBrand 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1933 

1934 def __init__(self, card_number: str): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1935 self.validate_digits(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1936 

1937 card_number = self.validate_luhn_check_digit(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1938 

1939 self.bin = card_number[:6] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1940 self.last4 = card_number[-4:] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1941 self.brand = self.validate_brand(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1942 

1943 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1944 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1945 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1946 cls.validate, 

1947 core_schema.str_schema( 

1948 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace 

1949 ), 

1950 ) 

1951 

1952 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1953 def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1954 """Validate the card number and return a `PaymentCardNumber` instance.""" 

1955 return cls(input_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1956 

1957 @property 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1958 def masked(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1959 """Mask all but the last 4 digits of the card number. 

1960 

1961 Returns: 

1962 A masked card number string. 

1963 """ 

1964 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1965 return f'{self.bin}{"*" * num_masked}{self.last4}' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1966 

1967 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1968 def validate_digits(cls, card_number: str) -> None: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1969 """Validate that the card number is all digits.""" 

1970 if not card_number.isdigit(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1971 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1972 

1973 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1974 def validate_luhn_check_digit(cls, card_number: str) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1975 """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm.""" 

1976 sum_ = int(card_number[-1]) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1977 length = len(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1978 parity = length % 2 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1979 for i in range(length - 1): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1980 digit = int(card_number[i]) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1981 if i % 2 == parity: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1982 digit *= 2 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1983 if digit > 9: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1984 digit -= 9 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1985 sum_ += digit 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1986 valid = sum_ % 10 == 0 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1987 if not valid: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1988 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1989 return card_number 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1990 

1991 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1992 def validate_brand(card_number: str) -> PaymentCardBrand: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1993 """Validate length based on BIN for major brands: 

1994 https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN). 

1995 """ 

1996 if card_number[0] == '4': 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1997 brand = PaymentCardBrand.visa 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1998 elif 51 <= int(card_number[:2]) <= 55: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1999 brand = PaymentCardBrand.mastercard 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2000 elif card_number[:2] in {'34', '37'}: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2001 brand = PaymentCardBrand.amex 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2002 else: 

2003 brand = PaymentCardBrand.other 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2004 

2005 required_length: None | int | str = None 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2006 if brand in PaymentCardBrand.mastercard: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2007 required_length = 16 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2008 valid = len(card_number) == required_length 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2009 elif brand == PaymentCardBrand.visa: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2010 required_length = '13, 16 or 19' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2011 valid = len(card_number) in {13, 16, 19} 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2012 elif brand == PaymentCardBrand.amex: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2013 required_length = 15 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2014 valid = len(card_number) == required_length 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2015 else: 

2016 valid = True 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2017 

2018 if not valid: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2019 raise PydanticCustomError( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2020 'payment_card_number_brand', 

2021 'Length for a {brand} card must be {required_length}', 

2022 {'brand': brand, 'required_length': required_length}, 

2023 ) 

2024 return brand 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2025 

2026 

2027# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2028 

2029 

2030class ByteSize(int): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2031 """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer. 

2032 

2033 You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into 

2034 an integer, and also to print out human-readable strings representing a number of bytes. 

2035 

2036 In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes, 

2037 and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2, 

2038 rather than a power of 10 (so, for example, `'1 MB'` is treated as `1_000_000` bytes, whereas `'1 MiB'` is treated as `1_048_576` bytes). 

2039 

2040 !!! info 

2041 Note that `1b` will be parsed as "1 byte" and not "1 bit". 

2042 

2043 ```python 

2044 from pydantic import BaseModel, ByteSize 

2045 

2046 class MyModel(BaseModel): 

2047 size: ByteSize 

2048 

2049 print(MyModel(size=52000).size) 

2050 #> 52000 

2051 print(MyModel(size='3000 KiB').size) 

2052 #> 3072000 

2053 

2054 m = MyModel(size='50 PB') 

2055 print(m.size.human_readable()) 

2056 #> 44.4PiB 

2057 print(m.size.human_readable(decimal=True)) 

2058 #> 50.0PB 

2059 print(m.size.human_readable(separator=' ')) 

2060 #> 44.4 PiB 

2061 

2062 print(m.size.to('TiB')) 

2063 #> 45474.73508864641 

2064 ``` 

2065 """ 

2066 

2067 byte_sizes = { 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2068 'b': 1, 

2069 'kb': 10**3, 

2070 'mb': 10**6, 

2071 'gb': 10**9, 

2072 'tb': 10**12, 

2073 'pb': 10**15, 

2074 'eb': 10**18, 

2075 'kib': 2**10, 

2076 'mib': 2**20, 

2077 'gib': 2**30, 

2078 'tib': 2**40, 

2079 'pib': 2**50, 

2080 'eib': 2**60, 

2081 'bit': 1 / 8, 

2082 'kbit': 10**3 / 8, 

2083 'mbit': 10**6 / 8, 

2084 'gbit': 10**9 / 8, 

2085 'tbit': 10**12 / 8, 

2086 'pbit': 10**15 / 8, 

2087 'ebit': 10**18 / 8, 

2088 'kibit': 2**10 / 8, 

2089 'mibit': 2**20 / 8, 

2090 'gibit': 2**30 / 8, 

2091 'tibit': 2**40 / 8, 

2092 'pibit': 2**50 / 8, 

2093 'eibit': 2**60 / 8, 

2094 } 

2095 byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2096 

2097 byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2098 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2099 

2100 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2101 def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2102 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2103 function=cls._validate, 

2104 schema=core_schema.union_schema( 

2105 [ 

2106 core_schema.str_schema(pattern=cls.byte_string_pattern), 

2107 core_schema.int_schema(ge=0), 

2108 ], 

2109 custom_error_type='byte_size', 

2110 custom_error_message='could not parse value and unit from byte string', 

2111 ), 

2112 serialization=core_schema.plain_serializer_function_ser_schema( 

2113 int, return_schema=core_schema.int_schema(ge=0) 

2114 ), 

2115 ) 

2116 

2117 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2118 def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2119 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2120 return cls(int(input_value)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2121 except ValueError: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2122 pass 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2123 

2124 str_match = cls.byte_string_re.match(str(input_value)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2125 if str_match is None: 2125 ↛ 2126line 2125 didn't jump to line 2126 because the condition on line 2125 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2126 raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string') 

2127 

2128 scalar, unit = str_match.groups() 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2129 if unit is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2130 unit = 'b' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2131 

2132 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2133 unit_mult = cls.byte_sizes[unit.lower()] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2134 except KeyError: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2135 raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2136 

2137 return cls(int(float(scalar) * unit_mult)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2138 

2139 def human_readable(self, decimal: bool = False, separator: str = '') -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2140 """Converts a byte size to a human readable string. 

2141 

2142 Args: 

2143 decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units 

2144 (e.g. 1024 bytes per KiB). 

2145 separator: A string used to split the value and unit. Defaults to an empty string (''). 

2146 

2147 Returns: 

2148 A human readable string representation of the byte size. 

2149 """ 

2150 if decimal: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2151 divisor = 1000 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2152 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2153 final_unit = 'EB' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2154 else: 

2155 divisor = 1024 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2156 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2157 final_unit = 'EiB' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2158 

2159 num = float(self) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2160 for unit in units: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2161 if abs(num) < divisor: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2162 if unit == 'B': 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2163 return f'{num:0.0f}{separator}{unit}' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2164 else: 

2165 return f'{num:0.1f}{separator}{unit}' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2166 num /= divisor 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2167 

2168 return f'{num:0.1f}{separator}{final_unit}' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2169 

2170 def to(self, unit: str) -> float: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2171 """Converts a byte size to another unit, including both byte and bit units. 

2172 

2173 Args: 

2174 unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB, 

2175 KiB, MiB, GiB, TiB, PiB, EiB (byte units) and 

2176 bit, kbit, mbit, gbit, tbit, pbit, ebit, 

2177 kibit, mibit, gibit, tibit, pibit, eibit (bit units). 

2178 

2179 Returns: 

2180 The byte size in the new unit. 

2181 """ 

2182 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2183 unit_div = self.byte_sizes[unit.lower()] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2184 except KeyError: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2185 raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2186 

2187 return self / unit_div 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2188 

2189 

2190# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2191 

2192 

2193def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2194 if annotated_type != expected_type: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2195 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2196 

2197 

2198if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2199 PastDate = Annotated[date, ...] 

2200 FutureDate = Annotated[date, ...] 

2201else: 

2202 

2203 class PastDate: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2204 """A date in the past.""" 

2205 

2206 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2207 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2208 cls, source: type[Any], handler: GetCoreSchemaHandler 

2209 ) -> core_schema.CoreSchema: 

2210 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2211 # used directly as a type 

2212 return core_schema.date_schema(now_op='past') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2213 else: 

2214 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2215 _check_annotated_type(schema['type'], 'date', cls.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2216 schema['now_op'] = 'past' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2217 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2218 

2219 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2220 return 'PastDate' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2221 

2222 class FutureDate: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2223 """A date in the future.""" 

2224 

2225 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2226 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2227 cls, source: type[Any], handler: GetCoreSchemaHandler 

2228 ) -> core_schema.CoreSchema: 

2229 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2230 # used directly as a type 

2231 return core_schema.date_schema(now_op='future') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2232 else: 

2233 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2234 _check_annotated_type(schema['type'], 'date', cls.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2235 schema['now_op'] = 'future' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2236 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2237 

2238 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2239 return 'FutureDate' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2240 

2241 

2242def condate( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2243 *, 

2244 strict: bool | None = None, 

2245 gt: date | None = None, 

2246 ge: date | None = None, 

2247 lt: date | None = None, 

2248 le: date | None = None, 

2249) -> type[date]: 

2250 """A wrapper for date that adds constraints. 

2251 

2252 Args: 

2253 strict: Whether to validate the date value in strict mode. Defaults to `None`. 

2254 gt: The value must be greater than this. Defaults to `None`. 

2255 ge: The value must be greater than or equal to this. Defaults to `None`. 

2256 lt: The value must be less than this. Defaults to `None`. 

2257 le: The value must be less than or equal to this. Defaults to `None`. 

2258 

2259 Returns: 

2260 A date type with the specified constraints. 

2261 """ 

2262 return Annotated[ # pyright: ignore[reportReturnType] 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2263 date, 

2264 Strict(strict) if strict is not None else None, 

2265 annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), 

2266 ] 

2267 

2268 

2269# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2270 

2271if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2272 AwareDatetime = Annotated[datetime, ...] 

2273 NaiveDatetime = Annotated[datetime, ...] 

2274 PastDatetime = Annotated[datetime, ...] 

2275 FutureDatetime = Annotated[datetime, ...] 

2276 

2277else: 

2278 

2279 class AwareDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2280 """A datetime that requires timezone info.""" 

2281 

2282 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2283 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2284 cls, source: type[Any], handler: GetCoreSchemaHandler 

2285 ) -> core_schema.CoreSchema: 

2286 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2287 # used directly as a type 

2288 return core_schema.datetime_schema(tz_constraint='aware') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2289 else: 

2290 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2291 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2292 schema['tz_constraint'] = 'aware' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2293 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2294 

2295 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2296 return 'AwareDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2297 

2298 class NaiveDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2299 """A datetime that doesn't require timezone info.""" 

2300 

2301 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2302 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2303 cls, source: type[Any], handler: GetCoreSchemaHandler 

2304 ) -> core_schema.CoreSchema: 

2305 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2306 # used directly as a type 

2307 return core_schema.datetime_schema(tz_constraint='naive') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2308 else: 

2309 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2310 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2311 schema['tz_constraint'] = 'naive' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2312 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2313 

2314 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2315 return 'NaiveDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2316 

2317 class PastDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2318 """A datetime that must be in the past.""" 

2319 

2320 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2321 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2322 cls, source: type[Any], handler: GetCoreSchemaHandler 

2323 ) -> core_schema.CoreSchema: 

2324 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2325 # used directly as a type 

2326 return core_schema.datetime_schema(now_op='past') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2327 else: 

2328 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2329 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2330 schema['now_op'] = 'past' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2331 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2332 

2333 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2334 return 'PastDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2335 

2336 class FutureDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2337 """A datetime that must be in the future.""" 

2338 

2339 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2340 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2341 cls, source: type[Any], handler: GetCoreSchemaHandler 

2342 ) -> core_schema.CoreSchema: 

2343 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2344 # used directly as a type 

2345 return core_schema.datetime_schema(now_op='future') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2346 else: 

2347 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2348 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2349 schema['now_op'] = 'future' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2350 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2351 

2352 def __repr__(self) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2353 return 'FutureDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2354 

2355 

2356# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2357 

2358 

2359class EncoderProtocol(Protocol): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2360 """Protocol for encoding and decoding data to and from bytes.""" 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2361 

2362 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2363 def decode(cls, data: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2364 """Decode the data using the encoder. 

2365 

2366 Args: 

2367 data: The data to decode. 

2368 

2369 Returns: 

2370 The decoded data. 

2371 """ 

2372 ... 

2373 

2374 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2375 def encode(cls, value: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2376 """Encode the data using the encoder. 

2377 

2378 Args: 

2379 value: The data to encode. 

2380 

2381 Returns: 

2382 The encoded data. 

2383 """ 

2384 ... 

2385 

2386 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2387 def get_json_format(cls) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2388 """Get the JSON format for the encoded data. 

2389 

2390 Returns: 

2391 The JSON format for the encoded data. 

2392 """ 

2393 ... 

2394 

2395 

2396class Base64Encoder(EncoderProtocol): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2397 """Standard (non-URL-safe) Base64 encoder.""" 

2398 

2399 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2400 def decode(cls, data: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2401 """Decode the data from base64 encoded bytes to original bytes data. 

2402 

2403 Args: 

2404 data: The data to decode. 

2405 

2406 Returns: 

2407 The decoded data. 

2408 """ 

2409 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2410 return base64.b64decode(data) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2411 except ValueError as e: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2412 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2413 

2414 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2415 def encode(cls, value: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2416 """Encode the data from bytes to a base64 encoded bytes. 

2417 

2418 Args: 

2419 value: The data to encode. 

2420 

2421 Returns: 

2422 The encoded data. 

2423 """ 

2424 return base64.b64encode(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2425 

2426 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2427 def get_json_format(cls) -> Literal['base64']: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2428 """Get the JSON format for the encoded data. 

2429 

2430 Returns: 

2431 The JSON format for the encoded data. 

2432 """ 

2433 return 'base64' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2434 

2435 

2436class Base64UrlEncoder(EncoderProtocol): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2437 """URL-safe Base64 encoder.""" 

2438 

2439 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2440 def decode(cls, data: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2441 """Decode the data from base64 encoded bytes to original bytes data. 

2442 

2443 Args: 

2444 data: The data to decode. 

2445 

2446 Returns: 

2447 The decoded data. 

2448 """ 

2449 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2450 return base64.urlsafe_b64decode(data) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2451 except ValueError as e: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2452 raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2453 

2454 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2455 def encode(cls, value: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2456 """Encode the data from bytes to a base64 encoded bytes. 

2457 

2458 Args: 

2459 value: The data to encode. 

2460 

2461 Returns: 

2462 The encoded data. 

2463 """ 

2464 return base64.urlsafe_b64encode(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2465 

2466 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2467 def get_json_format(cls) -> Literal['base64url']: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2468 """Get the JSON format for the encoded data. 

2469 

2470 Returns: 

2471 The JSON format for the encoded data. 

2472 """ 

2473 return 'base64url' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2474 

2475 

2476@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2477class EncodedBytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2478 """A bytes type that is encoded and decoded using the specified encoder. 

2479 

2480 `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate. 

2481 

2482 ```python 

2483 from typing import Annotated 

2484 

2485 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError 

2486 

2487 class MyEncoder(EncoderProtocol): 

2488 @classmethod 

2489 def decode(cls, data: bytes) -> bytes: 

2490 if data == b'**undecodable**': 

2491 raise ValueError('Cannot decode data') 

2492 return data[13:] 

2493 

2494 @classmethod 

2495 def encode(cls, value: bytes) -> bytes: 

2496 return b'**encoded**: ' + value 

2497 

2498 @classmethod 

2499 def get_json_format(cls) -> str: 

2500 return 'my-encoder' 

2501 

2502 MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)] 

2503 

2504 class Model(BaseModel): 

2505 my_encoded_bytes: MyEncodedBytes 

2506 

2507 # Initialize the model with encoded data 

2508 m = Model(my_encoded_bytes=b'**encoded**: some bytes') 

2509 

2510 # Access decoded value 

2511 print(m.my_encoded_bytes) 

2512 #> b'some bytes' 

2513 

2514 # Serialize into the encoded form 

2515 print(m.model_dump()) 

2516 #> {'my_encoded_bytes': b'**encoded**: some bytes'} 

2517 

2518 # Validate encoded data 

2519 try: 

2520 Model(my_encoded_bytes=b'**undecodable**') 

2521 except ValidationError as e: 

2522 print(e) 

2523 ''' 

2524 1 validation error for Model 

2525 my_encoded_bytes 

2526 Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes] 

2527 ''' 

2528 ``` 

2529 """ 

2530 

2531 encoder: type[EncoderProtocol] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2532 

2533 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2534 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2535 ) -> JsonSchemaValue: 

2536 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2537 field_schema.update(type='string', format=self.encoder.get_json_format()) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2538 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2539 

2540 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2541 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2542 _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2543 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2544 function=self.decode, 

2545 schema=schema, 

2546 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode), 

2547 ) 

2548 

2549 def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2550 """Decode the data using the specified encoder. 

2551 

2552 Args: 

2553 data: The data to decode. 

2554 

2555 Returns: 

2556 The decoded data. 

2557 """ 

2558 return self.encoder.decode(data) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2559 

2560 def encode(self, value: bytes) -> bytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2561 """Encode the data using the specified encoder. 

2562 

2563 Args: 

2564 value: The data to encode. 

2565 

2566 Returns: 

2567 The encoded data. 

2568 """ 

2569 return self.encoder.encode(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2570 

2571 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2572 return hash(self.encoder) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2573 

2574 

2575@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2576class EncodedStr: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2577 """A str type that is encoded and decoded using the specified encoder. 

2578 

2579 `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate. 

2580 

2581 ```python 

2582 from typing import Annotated 

2583 

2584 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError 

2585 

2586 class MyEncoder(EncoderProtocol): 

2587 @classmethod 

2588 def decode(cls, data: bytes) -> bytes: 

2589 if data == b'**undecodable**': 

2590 raise ValueError('Cannot decode data') 

2591 return data[13:] 

2592 

2593 @classmethod 

2594 def encode(cls, value: bytes) -> bytes: 

2595 return b'**encoded**: ' + value 

2596 

2597 @classmethod 

2598 def get_json_format(cls) -> str: 

2599 return 'my-encoder' 

2600 

2601 MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)] 

2602 

2603 class Model(BaseModel): 

2604 my_encoded_str: MyEncodedStr 

2605 

2606 # Initialize the model with encoded data 

2607 m = Model(my_encoded_str='**encoded**: some str') 

2608 

2609 # Access decoded value 

2610 print(m.my_encoded_str) 

2611 #> some str 

2612 

2613 # Serialize into the encoded form 

2614 print(m.model_dump()) 

2615 #> {'my_encoded_str': '**encoded**: some str'} 

2616 

2617 # Validate encoded data 

2618 try: 

2619 Model(my_encoded_str='**undecodable**') 

2620 except ValidationError as e: 

2621 print(e) 

2622 ''' 

2623 1 validation error for Model 

2624 my_encoded_str 

2625 Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str] 

2626 ''' 

2627 ``` 

2628 """ 

2629 

2630 encoder: type[EncoderProtocol] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2631 

2632 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2633 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2634 ) -> JsonSchemaValue: 

2635 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2636 field_schema.update(type='string', format=self.encoder.get_json_format()) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2637 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2638 

2639 def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2640 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2641 _check_annotated_type(schema['type'], 'str', self.__class__.__name__) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2642 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2643 function=self.decode_str, 

2644 schema=schema, 

2645 serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str), 

2646 ) 

2647 

2648 def decode_str(self, data: str, _: core_schema.ValidationInfo) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2649 """Decode the data using the specified encoder. 

2650 

2651 Args: 

2652 data: The data to decode. 

2653 

2654 Returns: 

2655 The decoded data. 

2656 """ 

2657 return self.encoder.decode(data.encode()).decode() 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2658 

2659 def encode_str(self, value: str) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2660 """Encode the data using the specified encoder. 

2661 

2662 Args: 

2663 value: The data to encode. 

2664 

2665 Returns: 

2666 The encoded data. 

2667 """ 

2668 return self.encoder.encode(value.encode()).decode() # noqa: UP008 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2669 

2670 def __hash__(self) -> int: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2671 return hash(self.encoder) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2672 

2673 

2674Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2675"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1bcdefghijaklmnopqrsJtuvwxyzAB

2676 

2677Note: 

2678 Under the hood, `Base64Bytes` uses the standard library `base64.b64encode` and `base64.b64decode` functions. 

2679 

2680 As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect 

2681 decoding. 

2682 

2683Warning: 

2684 In versions of Pydantic prior to v2.10, `Base64Bytes` used [`base64.encodebytes`][base64.encodebytes] 

2685 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html), 

2686 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern 

2687 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions. 

2688 

2689 If you'd still like to use these legacy encoders / decoders, you can achieve this by creating a custom annotated type, 

2690 like follows: 

2691 

2692 ```python 

2693 import base64 

2694 from typing import Annotated, Literal 

2695 

2696 from pydantic_core import PydanticCustomError 

2697 

2698 from pydantic import EncodedBytes, EncoderProtocol 

2699 

2700 class LegacyBase64Encoder(EncoderProtocol): 

2701 @classmethod 

2702 def decode(cls, data: bytes) -> bytes: 

2703 try: 

2704 return base64.decodebytes(data) 

2705 except ValueError as e: 

2706 raise PydanticCustomError( 

2707 'base64_decode', 

2708 "Base64 decoding error: '{error}'", 

2709 {'error': str(e)}, 

2710 ) 

2711 

2712 @classmethod 

2713 def encode(cls, value: bytes) -> bytes: 

2714 return base64.encodebytes(value) 

2715 

2716 @classmethod 

2717 def get_json_format(cls) -> Literal['base64']: 

2718 return 'base64' 

2719 

2720 LegacyBase64Bytes = Annotated[bytes, EncodedBytes(encoder=LegacyBase64Encoder)] 

2721 ``` 

2722 

2723```python 

2724from pydantic import Base64Bytes, BaseModel, ValidationError 

2725 

2726class Model(BaseModel): 

2727 base64_bytes: Base64Bytes 

2728 

2729# Initialize the model with base64 data 

2730m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5') 

2731 

2732# Access decoded value 

2733print(m.base64_bytes) 

2734#> b'This is the way' 

2735 

2736# Serialize into the base64 form 

2737print(m.model_dump()) 

2738#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5'} 

2739 

2740# Validate base64 data 

2741try: 

2742 print(Model(base64_bytes=b'undecodable').base64_bytes) 

2743except ValidationError as e: 

2744 print(e) 

2745 ''' 

2746 1 validation error for Model 

2747 base64_bytes 

2748 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes] 

2749 ''' 

2750``` 

2751""" 

2752Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2753"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. 1bcdefghijaklmnopqrsJtuvwxyzAB

2754 

2755Note: 

2756 Under the hood, `Base64Str` uses the standard library `base64.b64encode` and `base64.b64decode` functions. 

2757 

2758 As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect 

2759 decoding. 

2760 

2761Warning: 

2762 In versions of Pydantic prior to v2.10, `Base64Str` used [`base64.encodebytes`][base64.encodebytes] 

2763 and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html), 

2764 these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern 

2765 [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions. 

2766 

2767 See the [`Base64Bytes`][pydantic.types.Base64Bytes] type for more information on how to 

2768 replicate the old behavior with the legacy encoders / decoders. 

2769 

2770```python 

2771from pydantic import Base64Str, BaseModel, ValidationError 

2772 

2773class Model(BaseModel): 

2774 base64_str: Base64Str 

2775 

2776# Initialize the model with base64 data 

2777m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y') 

2778 

2779# Access decoded value 

2780print(m.base64_str) 

2781#> These aren't the droids you're looking for 

2782 

2783# Serialize into the base64 form 

2784print(m.model_dump()) 

2785#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y'} 

2786 

2787# Validate base64 data 

2788try: 

2789 print(Model(base64_str='undecodable').base64_str) 

2790except ValidationError as e: 

2791 print(e) 

2792 ''' 

2793 1 validation error for Model 

2794 base64_str 

2795 Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str] 

2796 ''' 

2797``` 

2798""" 

2799Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2800"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. 1bcdefghijaklmnopqrsJtuvwxyzAB

2801 

2802Note: 

2803 Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` 

2804 functions. 

2805 

2806 As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data 

2807 (using `'+'` and `'/'`). 

2808 

2809```python 

2810from pydantic import Base64UrlBytes, BaseModel 

2811 

2812class Model(BaseModel): 

2813 base64url_bytes: Base64UrlBytes 

2814 

2815# Initialize the model with base64 data 

2816m = Model(base64url_bytes=b'SHc_dHc-TXc==') 

2817print(m) 

2818#> base64url_bytes=b'Hw?tw>Mw' 

2819``` 

2820""" 

2821Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2822"""A str type that is encoded and decoded using the URL-safe base64 encoder. 1bcdefghijaklmnopqrsJtuvwxyzAB

2823 

2824Note: 

2825 Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` 

2826 functions. 

2827 

2828 As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`). 

2829 

2830```python 

2831from pydantic import Base64UrlStr, BaseModel 

2832 

2833class Model(BaseModel): 

2834 base64url_str: Base64UrlStr 

2835 

2836# Initialize the model with base64 data 

2837m = Model(base64url_str='SHc_dHc-TXc==') 

2838print(m) 

2839#> base64url_str='Hw?tw>Mw' 

2840``` 

2841""" 

2842 

2843 

2844__getattr__ = getattr_migration(__name__) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2845 

2846 

2847@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2848class GetPydanticSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2849 """!!! abstract "Usage Documentation" 

2850 [Using `GetPydanticSchema` to Reduce Boilerplate](../concepts/types.md#using-getpydanticschema-to-reduce-boilerplate) 

2851 

2852 A convenience class for creating an annotation that provides pydantic custom type hooks. 

2853 

2854 This class is intended to eliminate the need to create a custom "marker" which defines the 

2855 `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods. 

2856 

2857 For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do: 

2858 ```python 

2859 from typing import Annotated, Any 

2860 

2861 from pydantic import BaseModel, GetPydanticSchema 

2862 

2863 HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any)) 

2864 

2865 class Model(BaseModel): 

2866 x: Annotated[int, HandleAsAny] # pydantic sees `x: Any` 

2867 

2868 print(repr(Model(x='abc').x)) 

2869 #> 'abc' 

2870 ``` 

2871 """ 

2872 

2873 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2874 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2875 

2876 # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:` 

2877 # which returns `GetPydanticSchema(lambda _s, h: h(type_))` 

2878 

2879 if not TYPE_CHECKING: 2879 ↛ 2891line 2879 didn't jump to line 2891 because the condition on line 2879 was always true1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2880 # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access 

2881 

2882 def __getattr__(self, item: str) -> Any: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2883 """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls.""" 

2884 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2885 return self.get_pydantic_core_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2886 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2886 ↛ 2887line 2886 didn't jump to line 2887 because the condition on line 2886 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2887 return self.get_pydantic_json_schema 

2888 else: 

2889 return object.__getattribute__(self, item) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2890 

2891 __hash__ = object.__hash__ 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2892 

2893 

2894@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2895class Tag: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2896 """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union. 

2897 

2898 Also provides a way to label a union case in error messages. 

2899 

2900 When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that 

2901 should be used to identify that case. For example, in the below example, the `Tag` is used to specify that 

2902 if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it 

2903 returns `'pumpkin'`, the input should be validated as a `PumpkinPie`. 

2904 

2905 The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to 

2906 the appropriate member of the `Union` in question. 

2907 

2908 ```python 

2909 from typing import Annotated, Any, Literal, Union 

2910 

2911 from pydantic import BaseModel, Discriminator, Tag 

2912 

2913 class Pie(BaseModel): 

2914 time_to_cook: int 

2915 num_ingredients: int 

2916 

2917 class ApplePie(Pie): 

2918 fruit: Literal['apple'] = 'apple' 

2919 

2920 class PumpkinPie(Pie): 

2921 filling: Literal['pumpkin'] = 'pumpkin' 

2922 

2923 def get_discriminator_value(v: Any) -> str: 

2924 if isinstance(v, dict): 

2925 return v.get('fruit', v.get('filling')) 

2926 return getattr(v, 'fruit', getattr(v, 'filling', None)) 

2927 

2928 class ThanksgivingDinner(BaseModel): 

2929 dessert: Annotated[ 

2930 Union[ 

2931 Annotated[ApplePie, Tag('apple')], 

2932 Annotated[PumpkinPie, Tag('pumpkin')], 

2933 ], 

2934 Discriminator(get_discriminator_value), 

2935 ] 

2936 

2937 apple_variation = ThanksgivingDinner.model_validate( 

2938 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} 

2939 ) 

2940 print(repr(apple_variation)) 

2941 ''' 

2942 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) 

2943 ''' 

2944 

2945 pumpkin_variation = ThanksgivingDinner.model_validate( 

2946 { 

2947 'dessert': { 

2948 'filling': 'pumpkin', 

2949 'time_to_cook': 40, 

2950 'num_ingredients': 6, 

2951 } 

2952 } 

2953 ) 

2954 print(repr(pumpkin_variation)) 

2955 ''' 

2956 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) 

2957 ''' 

2958 ``` 

2959 

2960 !!! note 

2961 You must specify a `Tag` for every case in a `Tag` that is associated with a 

2962 callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code 

2963 [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag). 

2964 

2965 See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s. 

2966 

2967 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions 

2968 """ 

2969 

2970 tag: str 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2971 

2972 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2973 schema = handler(source_type) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2974 metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2975 metadata['pydantic_internal_union_tag_key'] = self.tag 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2976 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2977 

2978 

2979@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2980class Discriminator: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2981 """!!! abstract "Usage Documentation" 

2982 [Discriminated Unions with `Callable` `Discriminator`](../concepts/unions.md#discriminated-unions-with-callable-discriminator) 

2983 

2984 Provides a way to use a custom callable as the way to extract the value of a union discriminator. 

2985 

2986 This allows you to get validation behavior like you'd get from `Field(discriminator=<field_name>)`, 

2987 but without needing to have a single shared field across all the union choices. This also makes it 

2988 possible to handle unions of models and primitive types with discriminated-union-style validation errors. 

2989 Finally, this allows you to use a custom callable as the way to identify which member of a union a value 

2990 belongs to, while still seeing all the performance benefits of a discriminated union. 

2991 

2992 Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion` 

2993 than it would be as a normal `Union`. 

2994 

2995 ```python 

2996 from typing import Annotated, Any, Literal, Union 

2997 

2998 from pydantic import BaseModel, Discriminator, Tag 

2999 

3000 class Pie(BaseModel): 

3001 time_to_cook: int 

3002 num_ingredients: int 

3003 

3004 class ApplePie(Pie): 

3005 fruit: Literal['apple'] = 'apple' 

3006 

3007 class PumpkinPie(Pie): 

3008 filling: Literal['pumpkin'] = 'pumpkin' 

3009 

3010 def get_discriminator_value(v: Any) -> str: 

3011 if isinstance(v, dict): 

3012 return v.get('fruit', v.get('filling')) 

3013 return getattr(v, 'fruit', getattr(v, 'filling', None)) 

3014 

3015 class ThanksgivingDinner(BaseModel): 

3016 dessert: Annotated[ 

3017 Union[ 

3018 Annotated[ApplePie, Tag('apple')], 

3019 Annotated[PumpkinPie, Tag('pumpkin')], 

3020 ], 

3021 Discriminator(get_discriminator_value), 

3022 ] 

3023 

3024 apple_variation = ThanksgivingDinner.model_validate( 

3025 {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} 

3026 ) 

3027 print(repr(apple_variation)) 

3028 ''' 

3029 ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) 

3030 ''' 

3031 

3032 pumpkin_variation = ThanksgivingDinner.model_validate( 

3033 { 

3034 'dessert': { 

3035 'filling': 'pumpkin', 

3036 'time_to_cook': 40, 

3037 'num_ingredients': 6, 

3038 } 

3039 } 

3040 ) 

3041 print(repr(pumpkin_variation)) 

3042 ''' 

3043 ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) 

3044 ''' 

3045 ``` 

3046 

3047 See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s. 

3048 

3049 [Discriminated Unions]: ../concepts/unions.md#discriminated-unions 

3050 """ 

3051 

3052 discriminator: str | Callable[[Any], Hashable] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3053 """The callable or field name for discriminating the type in a tagged union. 1bcdefghijaklmnopqrsJtuvwxyzAB

3054 

3055 A `Callable` discriminator must extract the value of the discriminator from the input. 

3056 A `str` discriminator must be the name of a field to discriminate against. 

3057 """ 

3058 custom_error_type: str | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3059 """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union 1bcdefghijaklmnopqrsJtuvwxyzAB

3060 validation errors. 

3061 """ 

3062 custom_error_message: str | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3063 """Message to use in custom errors.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

3064 custom_error_context: dict[str, int | str | float] | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3065 """Context to use in custom errors.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

3066 

3067 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3068 if not is_union_origin(get_origin(source_type)): 3068 ↛ 3069line 3068 didn't jump to line 3069 because the condition on line 3068 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3069 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}') 

3070 

3071 if isinstance(self.discriminator, str): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3072 from pydantic import Field 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3073 

3074 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3075 else: 

3076 original_schema = handler(source_type) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3077 return self._convert_schema(original_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3078 

3079 def _convert_schema(self, original_schema: core_schema.CoreSchema) -> core_schema.TaggedUnionSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3080 if original_schema['type'] != 'union': 3080 ↛ 3085line 3080 didn't jump to line 3085 because the condition on line 3080 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3081 # This likely indicates that the schema was a single-item union that was simplified. 

3082 # In this case, we do the same thing we do in 

3083 # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely, 

3084 # package the generated schema back into a single-item union. 

3085 original_schema = core_schema.union_schema([original_schema]) 

3086 

3087 tagged_union_choices = {} 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3088 for choice in original_schema['choices']: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3089 tag = None 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3090 if isinstance(choice, tuple): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3091 choice, tag = choice 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3092 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3093 if metadata is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3094 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3095 if tag is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3096 raise PydanticUserError( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3097 f'`Tag` not provided for choice {choice} used with `Discriminator`', 

3098 code='callable-discriminator-no-tag', 

3099 ) 

3100 tagged_union_choices[tag] = choice 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3101 

3102 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored 

3103 custom_error_type = self.custom_error_type 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3104 if custom_error_type is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3105 custom_error_type = original_schema.get('custom_error_type') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3106 

3107 custom_error_message = self.custom_error_message 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3108 if custom_error_message is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3109 custom_error_message = original_schema.get('custom_error_message') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3110 

3111 custom_error_context = self.custom_error_context 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3112 if custom_error_context is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3113 custom_error_context = original_schema.get('custom_error_context') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3114 

3115 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3116 return core_schema.tagged_union_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3117 tagged_union_choices, 

3118 self.discriminator, 

3119 custom_error_type=custom_error_type, 

3120 custom_error_message=custom_error_message, 

3121 custom_error_context=custom_error_context, 

3122 strict=original_schema.get('strict'), 

3123 ref=original_schema.get('ref'), 

3124 metadata=original_schema.get('metadata'), 

3125 serialization=original_schema.get('serialization'), 

3126 ) 

3127 

3128 

3129_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3130 

3131 

3132def _get_type_name(x: Any) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3133 type_ = type(x) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3134 if type_ in _JSON_TYPES: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3135 return type_.__name__ 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3136 

3137 # Handle proper subclasses; note we don't need to handle None or bool here 

3138 if isinstance(x, int): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3139 return 'int' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3140 if isinstance(x, float): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3141 return 'float' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3142 if isinstance(x, str): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3143 return 'str' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3144 if isinstance(x, list): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3145 return 'list' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3146 if isinstance(x, dict): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3147 return 'dict' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3148 

3149 # Fail by returning the type's actual name 

3150 return getattr(type_, '__name__', '<no type name>') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3151 

3152 

3153class _AllowAnyJson: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3154 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3155 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3156 python_schema = handler(source_type) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3157 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3158 

3159 

3160if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3161 # This seems to only be necessary for mypy 

3162 JsonValue: TypeAlias = Union[ 

3163 list['JsonValue'], 

3164 dict[str, 'JsonValue'], 

3165 str, 

3166 bool, 

3167 int, 

3168 float, 

3169 None, 

3170 ] 

3171 """A `JsonValue` is used to represent a value that can be serialized to JSON. 

3172 

3173 It may be one of: 

3174 

3175 * `list['JsonValue']` 

3176 * `dict[str, 'JsonValue']` 

3177 * `str` 

3178 * `bool` 

3179 * `int` 

3180 * `float` 

3181 * `None` 

3182 

3183 The following example demonstrates how to use `JsonValue` to validate JSON data, 

3184 and what kind of errors to expect when input data is not json serializable. 

3185 

3186 ```python 

3187 import json 

3188 

3189 from pydantic import BaseModel, JsonValue, ValidationError 

3190 

3191 class Model(BaseModel): 

3192 j: JsonValue 

3193 

3194 valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}} 

3195 invalid_json_data = {'j': {'a': {'b': ...}}} 

3196 

3197 print(repr(Model.model_validate(valid_json_data))) 

3198 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) 

3199 print(repr(Model.model_validate_json(json.dumps(valid_json_data)))) 

3200 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) 

3201 

3202 try: 

3203 Model.model_validate(invalid_json_data) 

3204 except ValidationError as e: 

3205 print(e) 

3206 ''' 

3207 1 validation error for Model 

3208 j.dict.a.dict.b 

3209 input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis] 

3210 ''' 

3211 ``` 

3212 """ 

3213 

3214else: 

3215 JsonValue = TypeAliasType( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3216 'JsonValue', 

3217 Annotated[ 

3218 Union[ 

3219 Annotated[list['JsonValue'], Tag('list')], 

3220 Annotated[dict[str, 'JsonValue'], Tag('dict')], 

3221 Annotated[str, Tag('str')], 

3222 Annotated[bool, Tag('bool')], 

3223 Annotated[int, Tag('int')], 

3224 Annotated[float, Tag('float')], 

3225 Annotated[None, Tag('NoneType')], 

3226 ], 

3227 Discriminator( 

3228 _get_type_name, 

3229 custom_error_type='invalid-json-value', 

3230 custom_error_message='input was not a valid JSON value', 

3231 ), 

3232 _AllowAnyJson, 

3233 ], 

3234 ) 

3235 

3236 

3237class _OnErrorOmit: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3238 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3239 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3240 # there is no actual default value here but we use with_default_schema since it already has the on_error 

3241 # behavior implemented and it would be no more efficient to implement it on every other validator 

3242 # or as a standalone validator 

3243 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3244 

3245 

3246OnErrorOmit = Annotated[T, _OnErrorOmit] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3247""" 1bcdefghijaklmnopqrsJtuvwxyzAB

3248When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc. 

3249this annotation omits the item from the iteration if there is any error validating it. 

3250That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded 

3251any invalid items are discarded and the valid ones are returned. 

3252""" 

3253 

3254 

3255@_dataclasses.dataclass 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3256class FailFast(_fields.PydanticMetadata, BaseMetadata): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3257 """A `FailFast` annotation can be used to specify that validation should stop at the first error. 

3258 

3259 This can be useful when you want to validate a large amount of data and you only need to know if it's valid or not. 

3260 

3261 You might want to enable this setting if you want to validate your data faster (basically, if you use this, 

3262 validation will be more performant with the caveat that you get less information). 

3263 

3264 ```python 

3265 from typing import Annotated 

3266 

3267 from pydantic import BaseModel, FailFast, ValidationError 

3268 

3269 class Model(BaseModel): 

3270 x: Annotated[list[int], FailFast()] 

3271 

3272 # This will raise a single error for the first invalid value and stop validation 

3273 try: 

3274 obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c']) 

3275 except ValidationError as e: 

3276 print(e) 

3277 ''' 

3278 1 validation error for Model 

3279 x.2 

3280 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] 

3281 ''' 

3282 ``` 

3283 """ 

3284 

3285 fail_fast: bool = True 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB