Coverage for pydantic/types.py: 97.72%

651 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 08:39 +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, 6, 7 or 8. 

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 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

1172 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1173 

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

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

1176 

1177 

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

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

1180 

1181```python 

1182import uuid 

1183 

1184from pydantic import UUID1, BaseModel 

1185 

1186class Model(BaseModel): 

1187 uuid1: UUID1 

1188 

1189Model(uuid1=uuid.uuid1()) 

1190``` 

1191""" 

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

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

1194 

1195```python 

1196import uuid 

1197 

1198from pydantic import UUID3, BaseModel 

1199 

1200class Model(BaseModel): 

1201 uuid3: UUID3 

1202 

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

1204``` 

1205""" 

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

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

1208 

1209```python 

1210import uuid 

1211 

1212from pydantic import UUID4, BaseModel 

1213 

1214class Model(BaseModel): 

1215 uuid4: UUID4 

1216 

1217Model(uuid4=uuid.uuid4()) 

1218``` 

1219""" 

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

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

1222 

1223```python 

1224import uuid 

1225 

1226from pydantic import UUID5, BaseModel 

1227 

1228class Model(BaseModel): 

1229 uuid5: UUID5 

1230 

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

1232``` 

1233""" 

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

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

1236 

1237```python 

1238import uuid 

1239 

1240from pydantic import UUID6, BaseModel 

1241 

1242class Model(BaseModel): 

1243 uuid6: UUID6 

1244 

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

1246``` 

1247""" 

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

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

1250 

1251```python 

1252import uuid 

1253 

1254from pydantic import UUID7, BaseModel 

1255 

1256class Model(BaseModel): 

1257 uuid7: UUID7 

1258 

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

1260``` 

1261""" 

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

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

1264 

1265```python 

1266import uuid 

1267 

1268from pydantic import UUID8, BaseModel 

1269 

1270class Model(BaseModel): 

1271 uuid8: UUID8 

1272 

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

1274``` 

1275""" 

1276 

1277# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1278 

1279 

1280@_dataclasses.dataclass 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1281class PathType: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1283 

1284 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1286 ) -> JsonSchemaValue: 

1287 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

1290 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1291 

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

1293 function_lookup = { 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

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

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

1298 } 

1299 

1300 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1301 function_lookup[self.path_type], 

1302 handler(source), 

1303 ) 

1304 

1305 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1307 if path.is_file(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1308 return path 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1309 else: 

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

1311 

1312 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1314 if path.is_socket(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1315 return path 1CDbcdefghijEa

1316 else: 

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

1318 

1319 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1321 if path.is_dir(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1322 return path 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1323 else: 

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

1325 

1326 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1328 if path.exists(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

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

1332 else: 

1333 return path 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1334 

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

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

1337 

1338 

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

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

1341 

1342```python 

1343from pathlib import Path 

1344 

1345from pydantic import BaseModel, FilePath, ValidationError 

1346 

1347class Model(BaseModel): 

1348 f: FilePath 

1349 

1350path = Path('text.txt') 

1351path.touch() 

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

1353print(m.model_dump()) 

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

1355path.unlink() 

1356 

1357path = Path('directory') 

1358path.mkdir(exist_ok=True) 

1359try: 

1360 Model(f='directory') # directory 

1361except ValidationError as e: 

1362 print(e) 

1363 ''' 

1364 1 validation error for Model 

1365 f 

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

1367 ''' 

1368path.rmdir() 

1369 

1370try: 

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

1372except ValidationError as e: 

1373 print(e) 

1374 ''' 

1375 1 validation error for Model 

1376 f 

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

1378 ''' 

1379``` 

1380""" 

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

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

1383 

1384```python 

1385from pathlib import Path 

1386 

1387from pydantic import BaseModel, DirectoryPath, ValidationError 

1388 

1389class Model(BaseModel): 

1390 f: DirectoryPath 

1391 

1392path = Path('directory/') 

1393path.mkdir() 

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

1395print(m.model_dump()) 

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

1397path.rmdir() 

1398 

1399path = Path('file.txt') 

1400path.touch() 

1401try: 

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

1403except ValidationError as e: 

1404 print(e) 

1405 ''' 

1406 1 validation error for Model 

1407 f 

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

1409 ''' 

1410path.unlink() 

1411 

1412try: 

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

1414except ValidationError as e: 

1415 print(e) 

1416 ''' 

1417 1 validation error for Model 

1418 f 

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

1420 ''' 

1421``` 

1422""" 

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

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

1425 

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

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

1428 

1429# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1430 

1431if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1433 Json = Annotated[AnyType, ...] 

1434 

1435else: 

1436 

1437 class Json: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1439 

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

1441 validating the loaded data into the parametrized type: 

1442 

1443 ```python 

1444 from typing import Any 

1445 

1446 from pydantic import BaseModel, Json, ValidationError 

1447 

1448 class AnyJsonModel(BaseModel): 

1449 json_obj: Json[Any] 

1450 

1451 class ConstrainedJsonModel(BaseModel): 

1452 json_obj: Json[list[int]] 

1453 

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

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

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

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

1458 

1459 try: 

1460 ConstrainedJsonModel(json_obj=12) 

1461 except ValidationError as e: 

1462 print(e) 

1463 ''' 

1464 1 validation error for ConstrainedJsonModel 

1465 json_obj 

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

1467 ''' 

1468 

1469 try: 

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

1471 except ValidationError as e: 

1472 print(e) 

1473 ''' 

1474 1 validation error for ConstrainedJsonModel 

1475 json_obj 

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

1477 ''' 

1478 

1479 try: 

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

1481 except ValidationError as e: 

1482 print(e) 

1483 ''' 

1484 2 validation errors for ConstrainedJsonModel 

1485 json_obj.0 

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

1487 json_obj.1 

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

1489 ''' 

1490 ``` 

1491 

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

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

1494 

1495 ```python 

1496 from pydantic import BaseModel, Json 

1497 

1498 class ConstrainedJsonModel(BaseModel): 

1499 json_obj: Json[list[int]] 

1500 

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

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

1503 print( 

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

1505 ) 

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

1507 ``` 

1508 """ 

1509 

1510 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

1513 

1514 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1516 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1517 return core_schema.json_schema(None) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1518 else: 

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

1520 

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

1522 return 'Json' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1523 

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

1525 return hash(type(self)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1526 

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

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

1529 

1530 

1531# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1532 

1533SecretType = TypeVar('SecretType') 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1534 

1535 

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

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

1538 self._secret_value: SecretType = secret_value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1539 

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

1541 """Get the secret value. 

1542 

1543 Returns: 

1544 The secret value. 

1545 """ 

1546 return self._secret_value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1547 

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

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

1550 

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

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

1553 

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

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

1556 

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

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

1559 

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

1561 raise NotImplementedError 

1562 

1563 

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

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

1566 return str(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1567 else: 

1568 return value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1569 

1570 

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

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

1573 

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

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

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

1577 

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

1579 

1580 ```python 

1581 from pydantic import BaseModel, Secret 

1582 

1583 SecretBool = Secret[bool] 

1584 

1585 class Model(BaseModel): 

1586 secret_bool: SecretBool 

1587 

1588 m = Model(secret_bool=True) 

1589 print(m.model_dump()) 

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

1591 

1592 print(m.model_dump_json()) 

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

1594 

1595 print(m.secret_bool.get_secret_value()) 

1596 #> True 

1597 ``` 

1598 

1599 2. Subclassing from parametrized `Secret`: 

1600 

1601 ```python 

1602 from datetime import date 

1603 

1604 from pydantic import BaseModel, Secret 

1605 

1606 class SecretDate(Secret[date]): 

1607 def _display(self) -> str: 

1608 return '****/**/**' 

1609 

1610 class Model(BaseModel): 

1611 secret_date: SecretDate 

1612 

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

1614 print(m.model_dump()) 

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

1616 

1617 print(m.model_dump_json()) 

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

1619 

1620 print(m.secret_date.get_secret_value()) 

1621 #> 2022-01-01 

1622 ``` 

1623 

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

1625 

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

1627 For example: 

1628 

1629 ```python 

1630 from typing import Annotated 

1631 

1632 from pydantic import BaseModel, Field, Secret, ValidationError 

1633 

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

1635 

1636 class Model(BaseModel): 

1637 sensitive_int: SecretPosInt 

1638 

1639 m = Model(sensitive_int=42) 

1640 print(m.model_dump()) 

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

1642 

1643 try: 

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

1645 except ValidationError as exc_info: 

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

1647 ''' 

1648 [ 

1649 { 

1650 'type': 'greater_than', 

1651 'loc': ('sensitive_int',), 

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

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

1654 } 

1655 ] 

1656 ''' 

1657 

1658 try: 

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

1660 except ValidationError as exc_info: 

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

1662 ''' 

1663 [ 

1664 { 

1665 'type': 'int_type', 

1666 'loc': ('sensitive_int',), 

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

1668 } 

1669 ] 

1670 ''' 

1671 ``` 

1672 

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

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

1675 """ 

1676 

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

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

1679 

1680 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1682 inner_type = None 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

1684 origin_type = get_origin(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1685 if origin_type is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

1688 else: 

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

1690 for base in bases: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

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

1694 raise TypeError( 

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

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

1697 ) 

1698 

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

1700 

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

1702 if isinstance(value, Secret): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1703 value = value.get_secret_value() 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1704 validated_inner = handler(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1705 return cls(validated_inner) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1706 

1707 return core_schema.json_or_python_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1708 python_schema=core_schema.no_info_wrap_validator_function( 

1709 validate_secret_value, 

1710 inner_schema, 

1711 ), 

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

1713 serialization=core_schema.plain_serializer_function_ser_schema( 

1714 _serialize_secret, 

1715 info_arg=True, 

1716 when_used='always', 

1717 ), 

1718 ) 

1719 

1720 __pydantic_serializer__ = SchemaSerializer( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1721 core_schema.any_schema( 

1722 serialization=core_schema.plain_serializer_function_ser_schema( 

1723 _serialize_secret, 

1724 info_arg=True, 

1725 when_used='always', 

1726 ) 

1727 ) 

1728 ) 

1729 

1730 

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

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

1733 

1734 

1735def _serialize_secret_field( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1737) -> str | _SecretField[SecretType]: 

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

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

1740 # hence we just use `secret_display` 

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

1742 else: 

1743 return value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1744 

1745 

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

1747 _inner_schema: ClassVar[CoreSchema] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1748 _error_kind: ClassVar[str] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1749 

1750 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

1753 json_schema = handler(cls._inner_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1754 _utils.update_not_none( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1755 json_schema, 

1756 type='string', 

1757 writeOnly=True, 

1758 format='password', 

1759 ) 

1760 return json_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1761 

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

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

1764 json_schema = core_schema.no_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1765 source, # construct the type 

1766 inner_schema, # pyright: ignore[reportArgumentType] 

1767 ) 

1768 return core_schema.json_or_python_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1769 python_schema=core_schema.union_schema( 

1770 [ 

1771 core_schema.is_instance_schema(source), 

1772 json_schema, 

1773 ], 

1774 custom_error_type=cls._error_kind, 

1775 ), 

1776 json_schema=json_schema, 

1777 serialization=core_schema.plain_serializer_function_ser_schema( 

1778 _serialize_secret_field, 

1779 info_arg=True, 

1780 when_used='always', 

1781 ), 

1782 ) 

1783 

1784 return core_schema.lax_or_strict_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1785 lax_schema=get_secret_schema(strict=False), 

1786 strict_schema=get_secret_schema(strict=True), 

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

1788 ) 

1789 

1790 __pydantic_serializer__ = SchemaSerializer( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1791 core_schema.any_schema( 

1792 serialization=core_schema.plain_serializer_function_ser_schema( 

1793 _serialize_secret_field, 

1794 info_arg=True, 

1795 when_used='always', 

1796 ) 

1797 ) 

1798 ) 

1799 

1800 

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

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

1803 

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

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

1806 

1807 ```python 

1808 from pydantic import BaseModel, SecretStr 

1809 

1810 class User(BaseModel): 

1811 username: str 

1812 password: SecretStr 

1813 

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

1815 

1816 print(user) 

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

1818 print(user.password.get_secret_value()) 

1819 #> password1 

1820 print((SecretStr('password'), SecretStr(''))) 

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

1822 ``` 

1823 

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

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

1826 

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

1828 secret as plain-text when serializing to json. 

1829 

1830 ```python 

1831 from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer 

1832 

1833 class Model(BaseModel): 

1834 password: SecretStr 

1835 password_bytes: SecretBytes 

1836 

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

1838 def dump_secret(self, v): 

1839 return v.get_secret_value() 

1840 

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

1842 print(model) 

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

1844 print(model.password) 

1845 #> ********** 

1846 print(model.model_dump()) 

1847 ''' 

1848 { 

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

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

1851 } 

1852 ''' 

1853 print(model.model_dump_json()) 

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

1855 ``` 

1856 """ 

1857 

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

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

1860 

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

1862 return len(self._secret_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1863 

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

1865 return _secret_display(self._secret_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1866 

1867 

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

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

1870 

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

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

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

1874 

1875 ```python 

1876 from pydantic import BaseModel, SecretBytes 

1877 

1878 class User(BaseModel): 

1879 username: str 

1880 password: SecretBytes 

1881 

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

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

1884 print(user.password.get_secret_value()) 

1885 #> b'password1' 

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

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

1888 ``` 

1889 """ 

1890 

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

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

1893 

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

1895 return len(self._secret_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1896 

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

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

1899 

1900 

1901# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1902 

1903 

1904class PaymentCardBrand(str, Enum): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1905 amex = 'American Express' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1906 mastercard = 'Mastercard' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1907 visa = 'Visa' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1908 other = 'other' 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1909 

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

1911 return self.value 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1912 

1913 

1914@deprecated( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

1917 category=PydanticDeprecatedSince20, 

1918) 

1919class PaymentCardNumber(str): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1921 

1922 strip_whitespace: ClassVar[bool] = True 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1923 min_length: ClassVar[int] = 12 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1924 max_length: ClassVar[int] = 19 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1925 bin: str 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1926 last4: str 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1927 brand: PaymentCardBrand 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

1928 

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

1930 self.validate_digits(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1931 

1932 card_number = self.validate_luhn_check_digit(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1933 

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

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

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

1937 

1938 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

1940 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1941 cls.validate, 

1942 core_schema.str_schema( 

1943 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace 

1944 ), 

1945 ) 

1946 

1947 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

1950 return cls(input_value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1951 

1952 @property 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

1955 

1956 Returns: 

1957 A masked card number string. 

1958 """ 

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

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

1961 

1962 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

1965 if not card_number.isdigit(): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

1967 

1968 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

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

1972 length = len(card_number) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1973 parity = length % 2 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

1976 if i % 2 == parity: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1977 digit *= 2 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1978 if digit > 9: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1979 digit -= 9 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1980 sum_ += digit 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1981 valid = sum_ % 10 == 0 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1982 if not valid: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

1984 return card_number 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1985 

1986 @staticmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

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

1990 """ 

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

1992 brand = PaymentCardBrand.visa 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

1994 brand = PaymentCardBrand.mastercard 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

1996 brand = PaymentCardBrand.amex 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1997 else: 

1998 brand = PaymentCardBrand.other 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

1999 

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

2001 if brand in PaymentCardBrand.mastercard: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2002 required_length = 16 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2004 elif brand == PaymentCardBrand.visa: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2007 elif brand == PaymentCardBrand.amex: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2008 required_length = 15 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2010 else: 

2011 valid = True 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2012 

2013 if not valid: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2014 raise PydanticCustomError( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2015 'payment_card_number_brand', 

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

2017 {'brand': brand, 'required_length': required_length}, 

2018 ) 

2019 return brand 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2020 

2021 

2022# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2023 

2024 

2025class ByteSize(int): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2027 

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

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

2030 

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

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

2033 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). 

2034 

2035 !!! info 

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

2037 

2038 ```python 

2039 from pydantic import BaseModel, ByteSize 

2040 

2041 class MyModel(BaseModel): 

2042 size: ByteSize 

2043 

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

2045 #> 52000 

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

2047 #> 3072000 

2048 

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

2050 print(m.size.human_readable()) 

2051 #> 44.4PiB 

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

2053 #> 50.0PB 

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

2055 #> 44.4 PiB 

2056 

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

2058 #> 45474.73508864641 

2059 ``` 

2060 """ 

2061 

2062 byte_sizes = { 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2063 'b': 1, 

2064 'kb': 10**3, 

2065 'mb': 10**6, 

2066 'gb': 10**9, 

2067 'tb': 10**12, 

2068 'pb': 10**15, 

2069 'eb': 10**18, 

2070 'kib': 2**10, 

2071 'mib': 2**20, 

2072 'gib': 2**30, 

2073 'tib': 2**40, 

2074 'pib': 2**50, 

2075 'eib': 2**60, 

2076 'bit': 1 / 8, 

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

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

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

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

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

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

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

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

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

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

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

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

2089 } 

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

2091 

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

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

2094 

2095 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2097 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2098 function=cls._validate, 

2099 schema=core_schema.union_schema( 

2100 [ 

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

2102 core_schema.int_schema(ge=0), 

2103 ], 

2104 custom_error_type='byte_size', 

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

2106 ), 

2107 serialization=core_schema.plain_serializer_function_ser_schema( 

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

2109 ), 

2110 ) 

2111 

2112 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2114 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2115 return cls(int(input_value)) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2116 except ValueError: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2117 pass 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2118 

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

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

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

2122 

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

2124 if unit is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2125 unit = 'b' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2126 

2127 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2129 except KeyError: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2131 

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

2133 

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

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

2136 

2137 Args: 

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

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

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

2141 

2142 Returns: 

2143 A human readable string representation of the byte size. 

2144 """ 

2145 if decimal: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2146 divisor = 1000 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2148 final_unit = 'EB' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2149 else: 

2150 divisor = 1024 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2152 final_unit = 'EiB' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2153 

2154 num = float(self) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2155 for unit in units: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2156 if abs(num) < divisor: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2157 if unit == 'B': 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2159 else: 

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

2161 num /= divisor 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2162 

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

2164 

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

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

2167 

2168 Args: 

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

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

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

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

2173 

2174 Returns: 

2175 The byte size in the new unit. 

2176 """ 

2177 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2179 except KeyError: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2181 

2182 return self / unit_div 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2183 

2184 

2185# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2186 

2187 

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

2189 if annotated_type != expected_type: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2191 

2192 

2193if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2194 PastDate = Annotated[date, ...] 

2195 FutureDate = Annotated[date, ...] 

2196else: 

2197 

2198 class PastDate: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2199 """A date in the past.""" 

2200 

2201 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2202 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2204 ) -> core_schema.CoreSchema: 

2205 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2206 # used directly as a type 

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

2208 else: 

2209 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2212 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2213 

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

2215 return 'PastDate' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2216 

2217 class FutureDate: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2218 """A date in the future.""" 

2219 

2220 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2221 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2223 ) -> core_schema.CoreSchema: 

2224 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2225 # used directly as a type 

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

2227 else: 

2228 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2231 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2232 

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

2234 return 'FutureDate' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2235 

2236 

2237def condate( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2238 *, 

2239 strict: bool | None = None, 

2240 gt: date | None = None, 

2241 ge: date | None = None, 

2242 lt: date | None = None, 

2243 le: date | None = None, 

2244) -> type[date]: 

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

2246 

2247 Args: 

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

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

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

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

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

2253 

2254 Returns: 

2255 A date type with the specified constraints. 

2256 """ 

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

2258 date, 

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

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

2261 ] 

2262 

2263 

2264# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2265 

2266if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2267 AwareDatetime = Annotated[datetime, ...] 

2268 NaiveDatetime = Annotated[datetime, ...] 

2269 PastDatetime = Annotated[datetime, ...] 

2270 FutureDatetime = Annotated[datetime, ...] 

2271 

2272else: 

2273 

2274 class AwareDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2276 

2277 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2278 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2280 ) -> core_schema.CoreSchema: 

2281 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2282 # used directly as a type 

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

2284 else: 

2285 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2288 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2289 

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

2291 return 'AwareDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2292 

2293 class NaiveDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2295 

2296 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2297 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2299 ) -> core_schema.CoreSchema: 

2300 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2301 # used directly as a type 

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

2303 else: 

2304 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2307 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2308 

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

2310 return 'NaiveDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2311 

2312 class PastDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2314 

2315 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2316 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2318 ) -> core_schema.CoreSchema: 

2319 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2320 # used directly as a type 

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

2322 else: 

2323 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2326 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2327 

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

2329 return 'PastDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2330 

2331 class FutureDatetime: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2333 

2334 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2335 def __get_pydantic_core_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2337 ) -> core_schema.CoreSchema: 

2338 if cls is source: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2339 # used directly as a type 

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

2341 else: 

2342 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2345 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2346 

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

2348 return 'FutureDatetime' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2349 

2350 

2351# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2352 

2353 

2354class EncoderProtocol(Protocol): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2356 

2357 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2359 """Decode the data using the encoder. 

2360 

2361 Args: 

2362 data: The data to decode. 

2363 

2364 Returns: 

2365 The decoded data. 

2366 """ 

2367 ... 

2368 

2369 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2371 """Encode the data using the encoder. 

2372 

2373 Args: 

2374 value: The data to encode. 

2375 

2376 Returns: 

2377 The encoded data. 

2378 """ 

2379 ... 

2380 

2381 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2384 

2385 Returns: 

2386 The JSON format for the encoded data. 

2387 """ 

2388 ... 

2389 

2390 

2391class Base64Encoder(EncoderProtocol): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2393 

2394 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2397 

2398 Args: 

2399 data: The data to decode. 

2400 

2401 Returns: 

2402 The decoded data. 

2403 """ 

2404 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2405 return base64.b64decode(data) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2406 except ValueError as e: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2408 

2409 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2412 

2413 Args: 

2414 value: The data to encode. 

2415 

2416 Returns: 

2417 The encoded data. 

2418 """ 

2419 return base64.b64encode(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2420 

2421 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2424 

2425 Returns: 

2426 The JSON format for the encoded data. 

2427 """ 

2428 return 'base64' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2429 

2430 

2431class Base64UrlEncoder(EncoderProtocol): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2432 """URL-safe Base64 encoder.""" 

2433 

2434 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2437 

2438 Args: 

2439 data: The data to decode. 

2440 

2441 Returns: 

2442 The decoded data. 

2443 """ 

2444 try: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2445 return base64.urlsafe_b64decode(data) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2446 except ValueError as e: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2448 

2449 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2452 

2453 Args: 

2454 value: The data to encode. 

2455 

2456 Returns: 

2457 The encoded data. 

2458 """ 

2459 return base64.urlsafe_b64encode(value) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2460 

2461 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

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

2464 

2465 Returns: 

2466 The JSON format for the encoded data. 

2467 """ 

2468 return 'base64url' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2469 

2470 

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

2472class EncodedBytes: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2474 

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

2476 

2477 ```python 

2478 from typing import Annotated 

2479 

2480 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError 

2481 

2482 class MyEncoder(EncoderProtocol): 

2483 @classmethod 

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

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

2486 raise ValueError('Cannot decode data') 

2487 return data[13:] 

2488 

2489 @classmethod 

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

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

2492 

2493 @classmethod 

2494 def get_json_format(cls) -> str: 

2495 return 'my-encoder' 

2496 

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

2498 

2499 class Model(BaseModel): 

2500 my_encoded_bytes: MyEncodedBytes 

2501 

2502 # Initialize the model with encoded data 

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

2504 

2505 # Access decoded value 

2506 print(m.my_encoded_bytes) 

2507 #> b'some bytes' 

2508 

2509 # Serialize into the encoded form 

2510 print(m.model_dump()) 

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

2512 

2513 # Validate encoded data 

2514 try: 

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

2516 except ValidationError as e: 

2517 print(e) 

2518 ''' 

2519 1 validation error for Model 

2520 my_encoded_bytes 

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

2522 ''' 

2523 ``` 

2524 """ 

2525 

2526 encoder: type[EncoderProtocol] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2527 

2528 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2530 ) -> JsonSchemaValue: 

2531 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2533 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2534 

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

2536 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2538 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2539 function=self.decode, 

2540 schema=schema, 

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

2542 ) 

2543 

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

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

2546 

2547 Args: 

2548 data: The data to decode. 

2549 

2550 Returns: 

2551 The decoded data. 

2552 """ 

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

2554 

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

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

2557 

2558 Args: 

2559 value: The data to encode. 

2560 

2561 Returns: 

2562 The encoded data. 

2563 """ 

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

2565 

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

2567 return hash(self.encoder) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2568 

2569 

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

2571class EncodedStr: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2573 

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

2575 

2576 ```python 

2577 from typing import Annotated 

2578 

2579 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError 

2580 

2581 class MyEncoder(EncoderProtocol): 

2582 @classmethod 

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

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

2585 raise ValueError('Cannot decode data') 

2586 return data[13:] 

2587 

2588 @classmethod 

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

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

2591 

2592 @classmethod 

2593 def get_json_format(cls) -> str: 

2594 return 'my-encoder' 

2595 

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

2597 

2598 class Model(BaseModel): 

2599 my_encoded_str: MyEncodedStr 

2600 

2601 # Initialize the model with encoded data 

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

2603 

2604 # Access decoded value 

2605 print(m.my_encoded_str) 

2606 #> some str 

2607 

2608 # Serialize into the encoded form 

2609 print(m.model_dump()) 

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

2611 

2612 # Validate encoded data 

2613 try: 

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

2615 except ValidationError as e: 

2616 print(e) 

2617 ''' 

2618 1 validation error for Model 

2619 my_encoded_str 

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

2621 ''' 

2622 ``` 

2623 """ 

2624 

2625 encoder: type[EncoderProtocol] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2626 

2627 def __get_pydantic_json_schema__( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2629 ) -> JsonSchemaValue: 

2630 field_schema = handler(core_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2632 return field_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2633 

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

2635 schema = handler(source) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2637 return core_schema.with_info_after_validator_function( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2638 function=self.decode_str, 

2639 schema=schema, 

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

2641 ) 

2642 

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

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

2645 

2646 Args: 

2647 data: The data to decode. 

2648 

2649 Returns: 

2650 The decoded data. 

2651 """ 

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

2653 

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

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

2656 

2657 Args: 

2658 value: The data to encode. 

2659 

2660 Returns: 

2661 The encoded data. 

2662 """ 

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

2664 

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

2666 return hash(self.encoder) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2667 

2668 

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

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

2671 

2672Note: 

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

2674 

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

2676 decoding. 

2677 

2678Warning: 

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

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

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

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

2683 

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

2685 like follows: 

2686 

2687 ```python 

2688 import base64 

2689 from typing import Annotated, Literal 

2690 

2691 from pydantic_core import PydanticCustomError 

2692 

2693 from pydantic import EncodedBytes, EncoderProtocol 

2694 

2695 class LegacyBase64Encoder(EncoderProtocol): 

2696 @classmethod 

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

2698 try: 

2699 return base64.decodebytes(data) 

2700 except ValueError as e: 

2701 raise PydanticCustomError( 

2702 'base64_decode', 

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

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

2705 ) 

2706 

2707 @classmethod 

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

2709 return base64.encodebytes(value) 

2710 

2711 @classmethod 

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

2713 return 'base64' 

2714 

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

2716 ``` 

2717 

2718```python 

2719from pydantic import Base64Bytes, BaseModel, ValidationError 

2720 

2721class Model(BaseModel): 

2722 base64_bytes: Base64Bytes 

2723 

2724# Initialize the model with base64 data 

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

2726 

2727# Access decoded value 

2728print(m.base64_bytes) 

2729#> b'This is the way' 

2730 

2731# Serialize into the base64 form 

2732print(m.model_dump()) 

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

2734 

2735# Validate base64 data 

2736try: 

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

2738except ValidationError as e: 

2739 print(e) 

2740 ''' 

2741 1 validation error for Model 

2742 base64_bytes 

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

2744 ''' 

2745``` 

2746""" 

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

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

2749 

2750Note: 

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

2752 

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

2754 decoding. 

2755 

2756Warning: 

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

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

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

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

2761 

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

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

2764 

2765```python 

2766from pydantic import Base64Str, BaseModel, ValidationError 

2767 

2768class Model(BaseModel): 

2769 base64_str: Base64Str 

2770 

2771# Initialize the model with base64 data 

2772m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y') 

2773 

2774# Access decoded value 

2775print(m.base64_str) 

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

2777 

2778# Serialize into the base64 form 

2779print(m.model_dump()) 

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

2781 

2782# Validate base64 data 

2783try: 

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

2785except ValidationError as e: 

2786 print(e) 

2787 ''' 

2788 1 validation error for Model 

2789 base64_str 

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

2791 ''' 

2792``` 

2793""" 

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

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

2796 

2797Note: 

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

2799 functions. 

2800 

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

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

2803 

2804```python 

2805from pydantic import Base64UrlBytes, BaseModel 

2806 

2807class Model(BaseModel): 

2808 base64url_bytes: Base64UrlBytes 

2809 

2810# Initialize the model with base64 data 

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

2812print(m) 

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

2814``` 

2815""" 

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

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

2818 

2819Note: 

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

2821 functions. 

2822 

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

2824 

2825```python 

2826from pydantic import Base64UrlStr, BaseModel 

2827 

2828class Model(BaseModel): 

2829 base64url_str: Base64UrlStr 

2830 

2831# Initialize the model with base64 data 

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

2833print(m) 

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

2835``` 

2836""" 

2837 

2838 

2839__getattr__ = getattr_migration(__name__) 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2840 

2841 

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

2843class GetPydanticSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2844 """!!! abstract "Usage Documentation" 

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

2846 

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

2848 

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

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

2851 

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

2853 ```python 

2854 from typing import Annotated, Any 

2855 

2856 from pydantic import BaseModel, GetPydanticSchema 

2857 

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

2859 

2860 class Model(BaseModel): 

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

2862 

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

2864 #> 'abc' 

2865 ``` 

2866 """ 

2867 

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

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

2870 

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

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

2873 

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

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

2876 

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

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

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

2880 return self.get_pydantic_core_schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

2882 return self.get_pydantic_json_schema 

2883 else: 

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

2885 

2886 __hash__ = object.__hash__ 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2887 

2888 

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

2890class Tag: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

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

2892 

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

2894 

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

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

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

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

2899 

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

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

2902 

2903 ```python 

2904 from typing import Annotated, Any, Literal, Union 

2905 

2906 from pydantic import BaseModel, Discriminator, Tag 

2907 

2908 class Pie(BaseModel): 

2909 time_to_cook: int 

2910 num_ingredients: int 

2911 

2912 class ApplePie(Pie): 

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

2914 

2915 class PumpkinPie(Pie): 

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

2917 

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

2919 if isinstance(v, dict): 

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

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

2922 

2923 class ThanksgivingDinner(BaseModel): 

2924 dessert: Annotated[ 

2925 Union[ 

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

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

2928 ], 

2929 Discriminator(get_discriminator_value), 

2930 ] 

2931 

2932 apple_variation = ThanksgivingDinner.model_validate( 

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

2934 ) 

2935 print(repr(apple_variation)) 

2936 ''' 

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

2938 ''' 

2939 

2940 pumpkin_variation = ThanksgivingDinner.model_validate( 

2941 { 

2942 'dessert': { 

2943 'filling': 'pumpkin', 

2944 'time_to_cook': 40, 

2945 'num_ingredients': 6, 

2946 } 

2947 } 

2948 ) 

2949 print(repr(pumpkin_variation)) 

2950 ''' 

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

2952 ''' 

2953 ``` 

2954 

2955 !!! note 

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

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

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

2959 

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

2961 

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

2963 """ 

2964 

2965 tag: str 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2966 

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

2968 schema = handler(source_type) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

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

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

2971 return schema 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

2972 

2973 

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

2975class Discriminator: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

2976 """!!! abstract "Usage Documentation" 

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

2978 

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

2980 

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

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

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

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

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

2986 

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

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

2989 

2990 ```python 

2991 from typing import Annotated, Any, Literal, Union 

2992 

2993 from pydantic import BaseModel, Discriminator, Tag 

2994 

2995 class Pie(BaseModel): 

2996 time_to_cook: int 

2997 num_ingredients: int 

2998 

2999 class ApplePie(Pie): 

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

3001 

3002 class PumpkinPie(Pie): 

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

3004 

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

3006 if isinstance(v, dict): 

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

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

3009 

3010 class ThanksgivingDinner(BaseModel): 

3011 dessert: Annotated[ 

3012 Union[ 

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

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

3015 ], 

3016 Discriminator(get_discriminator_value), 

3017 ] 

3018 

3019 apple_variation = ThanksgivingDinner.model_validate( 

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

3021 ) 

3022 print(repr(apple_variation)) 

3023 ''' 

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

3025 ''' 

3026 

3027 pumpkin_variation = ThanksgivingDinner.model_validate( 

3028 { 

3029 'dessert': { 

3030 'filling': 'pumpkin', 

3031 'time_to_cook': 40, 

3032 'num_ingredients': 6, 

3033 } 

3034 } 

3035 ) 

3036 print(repr(pumpkin_variation)) 

3037 ''' 

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

3039 ''' 

3040 ``` 

3041 

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

3043 

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

3045 """ 

3046 

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

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

3049 

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

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

3052 """ 

3053 custom_error_type: str | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3054 """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union 1bcdefghijaklmnopqrsJtuvwxyzAB

3055 validation errors. 

3056 """ 

3057 custom_error_message: str | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3058 """Message to use in custom errors.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

3059 custom_error_context: dict[str, int | str | float] | None = None 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3060 """Context to use in custom errors.""" 1bcdefghijaklmnopqrsJtuvwxyzAB

3061 

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

3063 if not is_union_origin(get_origin(source_type)): 3063 ↛ 3064line 3063 didn't jump to line 3064 because the condition on line 3063 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3064 raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}') 

3065 

3066 if isinstance(self.discriminator, str): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3067 from pydantic import Field 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3068 

3069 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3070 else: 

3071 original_schema = handler(source_type) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3072 return self._convert_schema(original_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3073 

3074 def _convert_schema(self, original_schema: core_schema.CoreSchema) -> core_schema.TaggedUnionSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3075 if original_schema['type'] != 'union': 3075 ↛ 3080line 3075 didn't jump to line 3080 because the condition on line 3075 was never true1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3076 # This likely indicates that the schema was a single-item union that was simplified. 

3077 # In this case, we do the same thing we do in 

3078 # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely, 

3079 # package the generated schema back into a single-item union. 

3080 original_schema = core_schema.union_schema([original_schema]) 

3081 

3082 tagged_union_choices = {} 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3083 for choice in original_schema['choices']: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3084 tag = None 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3085 if isinstance(choice, tuple): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3086 choice, tag = choice 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3087 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3088 if metadata is not None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3089 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3090 if tag is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3091 raise PydanticUserError( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3092 f'`Tag` not provided for choice {choice} used with `Discriminator`', 

3093 code='callable-discriminator-no-tag', 

3094 ) 

3095 tagged_union_choices[tag] = choice 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3096 

3097 # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored 

3098 custom_error_type = self.custom_error_type 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3099 if custom_error_type is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3100 custom_error_type = original_schema.get('custom_error_type') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3101 

3102 custom_error_message = self.custom_error_message 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3103 if custom_error_message is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3104 custom_error_message = original_schema.get('custom_error_message') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3105 

3106 custom_error_context = self.custom_error_context 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3107 if custom_error_context is None: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3108 custom_error_context = original_schema.get('custom_error_context') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3109 

3110 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3111 return core_schema.tagged_union_schema( 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3112 tagged_union_choices, 

3113 self.discriminator, 

3114 custom_error_type=custom_error_type, 

3115 custom_error_message=custom_error_message, 

3116 custom_error_context=custom_error_context, 

3117 strict=original_schema.get('strict'), 

3118 ref=original_schema.get('ref'), 

3119 metadata=original_schema.get('metadata'), 

3120 serialization=original_schema.get('serialization'), 

3121 ) 

3122 

3123 

3124_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3125 

3126 

3127def _get_type_name(x: Any) -> str: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3128 type_ = type(x) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3129 if type_ in _JSON_TYPES: 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3130 return type_.__name__ 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3131 

3132 # Handle proper subclasses; note we don't need to handle None or bool here 

3133 if isinstance(x, int): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3134 return 'int' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3135 if isinstance(x, float): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3136 return 'float' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3137 if isinstance(x, str): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3138 return 'str' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3139 if isinstance(x, list): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3140 return 'list' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3141 if isinstance(x, dict): 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3142 return 'dict' 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3143 

3144 # Fail by returning the type's actual name 

3145 return getattr(type_, '__name__', '<no type name>') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3146 

3147 

3148class _AllowAnyJson: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3149 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3150 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3151 python_schema = handler(source_type) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3152 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3153 

3154 

3155if TYPE_CHECKING: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3156 # This seems to only be necessary for mypy 

3157 JsonValue: TypeAlias = Union[ 

3158 list['JsonValue'], 

3159 dict[str, 'JsonValue'], 

3160 str, 

3161 bool, 

3162 int, 

3163 float, 

3164 None, 

3165 ] 

3166 """A `JsonValue` is used to represent a value that can be serialized to JSON. 

3167 

3168 It may be one of: 

3169 

3170 * `list['JsonValue']` 

3171 * `dict[str, 'JsonValue']` 

3172 * `str` 

3173 * `bool` 

3174 * `int` 

3175 * `float` 

3176 * `None` 

3177 

3178 The following example demonstrates how to use `JsonValue` to validate JSON data, 

3179 and what kind of errors to expect when input data is not json serializable. 

3180 

3181 ```python 

3182 import json 

3183 

3184 from pydantic import BaseModel, JsonValue, ValidationError 

3185 

3186 class Model(BaseModel): 

3187 j: JsonValue 

3188 

3189 valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}} 

3190 invalid_json_data = {'j': {'a': {'b': ...}}} 

3191 

3192 print(repr(Model.model_validate(valid_json_data))) 

3193 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) 

3194 print(repr(Model.model_validate_json(json.dumps(valid_json_data)))) 

3195 #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) 

3196 

3197 try: 

3198 Model.model_validate(invalid_json_data) 

3199 except ValidationError as e: 

3200 print(e) 

3201 ''' 

3202 1 validation error for Model 

3203 j.dict.a.dict.b 

3204 input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis] 

3205 ''' 

3206 ``` 

3207 """ 

3208 

3209else: 

3210 JsonValue = TypeAliasType( 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3211 'JsonValue', 

3212 Annotated[ 

3213 Union[ 

3214 Annotated[list['JsonValue'], Tag('list')], 

3215 Annotated[dict[str, 'JsonValue'], Tag('dict')], 

3216 Annotated[str, Tag('str')], 

3217 Annotated[bool, Tag('bool')], 

3218 Annotated[int, Tag('int')], 

3219 Annotated[float, Tag('float')], 

3220 Annotated[None, Tag('NoneType')], 

3221 ], 

3222 Discriminator( 

3223 _get_type_name, 

3224 custom_error_type='invalid-json-value', 

3225 custom_error_message='input was not a valid JSON value', 

3226 ), 

3227 _AllowAnyJson, 

3228 ], 

3229 ) 

3230 

3231 

3232class _OnErrorOmit: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3233 @classmethod 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3234 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3235 # there is no actual default value here but we use with_default_schema since it already has the on_error 

3236 # behavior implemented and it would be no more efficient to implement it on every other validator 

3237 # or as a standalone validator 

3238 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1CDbcdefghijEaFGklmnopqrsHItuvwxyzAB

3239 

3240 

3241OnErrorOmit = Annotated[T, _OnErrorOmit] 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3242""" 1bcdefghijaklmnopqrsJtuvwxyzAB

3243When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc. 

3244this annotation omits the item from the iteration if there is any error validating it. 

3245That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded 

3246any invalid items are discarded and the valid ones are returned. 

3247""" 

3248 

3249 

3250@_dataclasses.dataclass 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3251class FailFast(_fields.PydanticMetadata, BaseMetadata): 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB

3252 """A `FailFast` annotation can be used to specify that validation should stop at the first error. 

3253 

3254 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. 

3255 

3256 You might want to enable this setting if you want to validate your data faster (basically, if you use this, 

3257 validation will be more performant with the caveat that you get less information). 

3258 

3259 ```python 

3260 from typing import Annotated 

3261 

3262 from pydantic import BaseModel, FailFast, ValidationError 

3263 

3264 class Model(BaseModel): 

3265 x: Annotated[list[int], FailFast()] 

3266 

3267 # This will raise a single error for the first invalid value and stop validation 

3268 try: 

3269 obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c']) 

3270 except ValidationError as e: 

3271 print(e) 

3272 ''' 

3273 1 validation error for Model 

3274 x.2 

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

3276 ''' 

3277 ``` 

3278 """ 

3279 

3280 fail_fast: bool = True 1CDbcdefghijEaFGklmnopqrsJHItuvwxyzAB