Coverage for pydantic/types.py: 97.46%

646 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-13 19:35 +0000

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

2 

3from __future__ import annotations as _annotations 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

4 

5import base64 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

6import dataclasses as _dataclasses 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

7import re 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

8from collections.abc import Hashable, Iterator 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

9from datetime import date, datetime 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

10from decimal import Decimal 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

11from enum import Enum 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

12from pathlib import Path 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

13from re import Pattern 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

14from types import ModuleType 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

15from typing import ( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

28 

29import annotated_types 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

30from annotated_types import BaseMetadata, MaxLen, MinLen 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

33 

34from ._internal import _fields, _internal_dataclass, _typing_extra, _utils, _validators 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

35from ._migration import getattr_migration 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

36from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

37from .errors import PydanticUserError 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

38from .json_schema import JsonSchemaValue 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

39from .warnings import PydanticDeprecatedSince20 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

40 

41if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

42 from ._internal._core_metadata import CoreMetadata 

43 

44__all__ = ( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

45 'Strict', 

46 'StrictStr', 

47 'SocketPath', 

48 'conbytes', 

49 'conlist', 

50 'conset', 

51 'confrozenset', 

52 'constr', 

53 'ImportString', 

54 'conint', 

55 'PositiveInt', 

56 'NegativeInt', 

57 'NonNegativeInt', 

58 'NonPositiveInt', 

59 'confloat', 

60 'PositiveFloat', 

61 'NegativeFloat', 

62 'NonNegativeFloat', 

63 'NonPositiveFloat', 

64 'FiniteFloat', 

65 'condecimal', 

66 'UUID1', 

67 'UUID3', 

68 'UUID4', 

69 'UUID5', 

70 'FilePath', 

71 'DirectoryPath', 

72 'NewPath', 

73 'Json', 

74 'Secret', 

75 'SecretStr', 

76 'SecretBytes', 

77 'StrictBool', 

78 'StrictBytes', 

79 'StrictInt', 

80 'StrictFloat', 

81 'PaymentCardNumber', 

82 'ByteSize', 

83 'PastDate', 

84 'FutureDate', 

85 'PastDatetime', 

86 'FutureDatetime', 

87 'condate', 

88 'AwareDatetime', 

89 'NaiveDatetime', 

90 'AllowInfNan', 

91 'EncoderProtocol', 

92 'EncodedBytes', 

93 'EncodedStr', 

94 'Base64Encoder', 

95 'Base64Bytes', 

96 'Base64Str', 

97 'Base64UrlBytes', 

98 'Base64UrlStr', 

99 'GetPydanticSchema', 

100 'StringConstraints', 

101 'Tag', 

102 'Discriminator', 

103 'JsonValue', 

104 'OnErrorOmit', 

105 'FailFast', 

106) 

107 

108 

109T = TypeVar('T') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

110 

111 

112@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

113class Strict(_fields.PydanticMetadata, BaseMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

114 """!!! abstract "Usage Documentation" 

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

116 

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

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

119 

120 Attributes: 

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

122 

123 Example: 

124 ```python 

125 from typing import Annotated 

126 

127 from pydantic.types import Strict 

128 

129 StrictBool = Annotated[bool, Strict()] 

130 ``` 

131 """ 

132 

133 strict: bool = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

134 

135 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

136 return hash(self.strict) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

137 

138 

139# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

140 

141StrictBool = Annotated[bool, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

142"""A boolean that must be either ``True`` or ``False``.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

143 

144# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

145 

146 

147def conint( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

148 *, 

149 strict: bool | None = None, 

150 gt: int | None = None, 

151 ge: int | None = None, 

152 lt: int | None = None, 

153 le: int | None = None, 

154 multiple_of: int | None = None, 

155) -> type[int]: 

156 """ 

157 !!! warning "Discouraged" 

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

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

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

161 

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

163 

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

165 

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

167 ```python 

168 from pydantic import BaseModel, conint 

169 

170 class Foo(BaseModel): 

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

172 ``` 

173 

174 === ":white_check_mark: Do this" 

175 ```python 

176 from typing import Annotated 

177 

178 from pydantic import BaseModel, Field 

179 

180 class Foo(BaseModel): 

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

182 ``` 

183 

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

185 

186 Args: 

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

188 gt: The value must be greater than this. 

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

190 lt: The value must be less than this. 

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

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

193 

194 Returns: 

195 The wrapped integer type. 

196 

197 ```python 

198 from pydantic import BaseModel, ValidationError, conint 

199 

200 class ConstrainedExample(BaseModel): 

201 constrained_int: conint(gt=1) 

202 

203 m = ConstrainedExample(constrained_int=2) 

204 print(repr(m)) 

205 #> ConstrainedExample(constrained_int=2) 

206 

207 try: 

208 ConstrainedExample(constrained_int=0) 

209 except ValidationError as e: 

210 print(e.errors()) 

211 ''' 

212 [ 

213 { 

214 'type': 'greater_than', 

215 'loc': ('constrained_int',), 

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

217 'input': 0, 

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

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

220 } 

221 ] 

222 ''' 

223 ``` 

224 

225 """ # noqa: D212 

226 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

227 int, 

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

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

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

231 ] 

232 

233 

234PositiveInt = Annotated[int, annotated_types.Gt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

235"""An integer that must be greater than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

236 

237```python 

238from pydantic import BaseModel, PositiveInt, ValidationError 

239 

240class Model(BaseModel): 

241 positive_int: PositiveInt 

242 

243m = Model(positive_int=1) 

244print(repr(m)) 

245#> Model(positive_int=1) 

246 

247try: 

248 Model(positive_int=-1) 

249except ValidationError as e: 

250 print(e.errors()) 

251 ''' 

252 [ 

253 { 

254 'type': 'greater_than', 

255 'loc': ('positive_int',), 

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

257 'input': -1, 

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

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

260 } 

261 ] 

262 ''' 

263``` 

264""" 

265NegativeInt = Annotated[int, annotated_types.Lt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

266"""An integer that must be less than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

267 

268```python 

269from pydantic import BaseModel, NegativeInt, ValidationError 

270 

271class Model(BaseModel): 

272 negative_int: NegativeInt 

273 

274m = Model(negative_int=-1) 

275print(repr(m)) 

276#> Model(negative_int=-1) 

277 

278try: 

279 Model(negative_int=1) 

280except ValidationError as e: 

281 print(e.errors()) 

282 ''' 

283 [ 

284 { 

285 'type': 'less_than', 

286 'loc': ('negative_int',), 

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

288 'input': 1, 

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

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

291 } 

292 ] 

293 ''' 

294``` 

295""" 

296NonPositiveInt = Annotated[int, annotated_types.Le(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

297"""An integer that must be less than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

298 

299```python 

300from pydantic import BaseModel, NonPositiveInt, ValidationError 

301 

302class Model(BaseModel): 

303 non_positive_int: NonPositiveInt 

304 

305m = Model(non_positive_int=0) 

306print(repr(m)) 

307#> Model(non_positive_int=0) 

308 

309try: 

310 Model(non_positive_int=1) 

311except ValidationError as e: 

312 print(e.errors()) 

313 ''' 

314 [ 

315 { 

316 'type': 'less_than_equal', 

317 'loc': ('non_positive_int',), 

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

319 'input': 1, 

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

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

322 } 

323 ] 

324 ''' 

325``` 

326""" 

327NonNegativeInt = Annotated[int, annotated_types.Ge(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

328"""An integer that must be greater than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

329 

330```python 

331from pydantic import BaseModel, NonNegativeInt, ValidationError 

332 

333class Model(BaseModel): 

334 non_negative_int: NonNegativeInt 

335 

336m = Model(non_negative_int=0) 

337print(repr(m)) 

338#> Model(non_negative_int=0) 

339 

340try: 

341 Model(non_negative_int=-1) 

342except ValidationError as e: 

343 print(e.errors()) 

344 ''' 

345 [ 

346 { 

347 'type': 'greater_than_equal', 

348 'loc': ('non_negative_int',), 

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

350 'input': -1, 

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

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

353 } 

354 ] 

355 ''' 

356``` 

357""" 

358StrictInt = Annotated[int, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

359"""An integer that must be validated in strict mode. 1bcdefghiajklmnopqGHIJKLrstuvwxy

360 

361```python 

362from pydantic import BaseModel, StrictInt, ValidationError 

363 

364class StrictIntModel(BaseModel): 

365 strict_int: StrictInt 

366 

367try: 

368 StrictIntModel(strict_int=3.14159) 

369except ValidationError as e: 

370 print(e) 

371 ''' 

372 1 validation error for StrictIntModel 

373 strict_int 

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

375 ''' 

376``` 

377""" 

378 

379# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

380 

381 

382@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

383class AllowInfNan(_fields.PydanticMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

385 

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

387 

388 Attributes: 

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

390 

391 Example: 

392 ```python 

393 from typing import Annotated 

394 

395 from pydantic.types import AllowInfNan 

396 

397 LaxFloat = Annotated[float, AllowInfNan()] 

398 ``` 

399 """ 

400 

401 allow_inf_nan: bool = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

402 

403 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

404 return hash(self.allow_inf_nan) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

405 

406 

407def confloat( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

408 *, 

409 strict: bool | None = None, 

410 gt: float | None = None, 

411 ge: float | None = None, 

412 lt: float | None = None, 

413 le: float | None = None, 

414 multiple_of: float | None = None, 

415 allow_inf_nan: bool | None = None, 

416) -> type[float]: 

417 """ 

418 !!! warning "Discouraged" 

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

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

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

422 

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

424 

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

426 

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

428 ```python 

429 from pydantic import BaseModel, confloat 

430 

431 class Foo(BaseModel): 

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

433 ``` 

434 

435 === ":white_check_mark: Do this" 

436 ```python 

437 from typing import Annotated 

438 

439 from pydantic import BaseModel, Field 

440 

441 class Foo(BaseModel): 

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

443 ``` 

444 

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

446 

447 Args: 

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

449 gt: The value must be greater than this. 

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

451 lt: The value must be less than this. 

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

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

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

455 

456 Returns: 

457 The wrapped float type. 

458 

459 ```python 

460 from pydantic import BaseModel, ValidationError, confloat 

461 

462 class ConstrainedExample(BaseModel): 

463 constrained_float: confloat(gt=1.0) 

464 

465 m = ConstrainedExample(constrained_float=1.1) 

466 print(repr(m)) 

467 #> ConstrainedExample(constrained_float=1.1) 

468 

469 try: 

470 ConstrainedExample(constrained_float=0.9) 

471 except ValidationError as e: 

472 print(e.errors()) 

473 ''' 

474 [ 

475 { 

476 'type': 'greater_than', 

477 'loc': ('constrained_float',), 

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

479 'input': 0.9, 

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

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

482 } 

483 ] 

484 ''' 

485 ``` 

486 """ # noqa: D212 

487 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

488 float, 

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

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

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

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

493 ] 

494 

495 

496PositiveFloat = Annotated[float, annotated_types.Gt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

497"""A float that must be greater than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

498 

499```python 

500from pydantic import BaseModel, PositiveFloat, ValidationError 

501 

502class Model(BaseModel): 

503 positive_float: PositiveFloat 

504 

505m = Model(positive_float=1.0) 

506print(repr(m)) 

507#> Model(positive_float=1.0) 

508 

509try: 

510 Model(positive_float=-1.0) 

511except ValidationError as e: 

512 print(e.errors()) 

513 ''' 

514 [ 

515 { 

516 'type': 'greater_than', 

517 'loc': ('positive_float',), 

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

519 'input': -1.0, 

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

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

522 } 

523 ] 

524 ''' 

525``` 

526""" 

527NegativeFloat = Annotated[float, annotated_types.Lt(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

528"""A float that must be less than zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

529 

530```python 

531from pydantic import BaseModel, NegativeFloat, ValidationError 

532 

533class Model(BaseModel): 

534 negative_float: NegativeFloat 

535 

536m = Model(negative_float=-1.0) 

537print(repr(m)) 

538#> Model(negative_float=-1.0) 

539 

540try: 

541 Model(negative_float=1.0) 

542except ValidationError as e: 

543 print(e.errors()) 

544 ''' 

545 [ 

546 { 

547 'type': 'less_than', 

548 'loc': ('negative_float',), 

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

550 'input': 1.0, 

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

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

553 } 

554 ] 

555 ''' 

556``` 

557""" 

558NonPositiveFloat = Annotated[float, annotated_types.Le(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

559"""A float that must be less than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

560 

561```python 

562from pydantic import BaseModel, NonPositiveFloat, ValidationError 

563 

564class Model(BaseModel): 

565 non_positive_float: NonPositiveFloat 

566 

567m = Model(non_positive_float=0.0) 

568print(repr(m)) 

569#> Model(non_positive_float=0.0) 

570 

571try: 

572 Model(non_positive_float=1.0) 

573except ValidationError as e: 

574 print(e.errors()) 

575 ''' 

576 [ 

577 { 

578 'type': 'less_than_equal', 

579 'loc': ('non_positive_float',), 

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

581 'input': 1.0, 

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

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

584 } 

585 ] 

586 ''' 

587``` 

588""" 

589NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

590"""A float that must be greater than or equal to zero. 1bcdefghiajklmnopqGHIJKLrstuvwxy

591 

592```python 

593from pydantic import BaseModel, NonNegativeFloat, ValidationError 

594 

595class Model(BaseModel): 

596 non_negative_float: NonNegativeFloat 

597 

598m = Model(non_negative_float=0.0) 

599print(repr(m)) 

600#> Model(non_negative_float=0.0) 

601 

602try: 

603 Model(non_negative_float=-1.0) 

604except ValidationError as e: 

605 print(e.errors()) 

606 ''' 

607 [ 

608 { 

609 'type': 'greater_than_equal', 

610 'loc': ('non_negative_float',), 

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

612 'input': -1.0, 

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

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

615 } 

616 ] 

617 ''' 

618``` 

619""" 

620StrictFloat = Annotated[float, Strict(True)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

621"""A float that must be validated in strict mode. 1bcdefghiajklmnopqGHIJKLrstuvwxy

622 

623```python 

624from pydantic import BaseModel, StrictFloat, ValidationError 

625 

626class StrictFloatModel(BaseModel): 

627 strict_float: StrictFloat 

628 

629try: 

630 StrictFloatModel(strict_float='1.0') 

631except ValidationError as e: 

632 print(e) 

633 ''' 

634 1 validation error for StrictFloatModel 

635 strict_float 

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

637 ''' 

638``` 

639""" 

640FiniteFloat = Annotated[float, AllowInfNan(False)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

642 

643```python 

644from pydantic import BaseModel, FiniteFloat 

645 

646class Model(BaseModel): 

647 finite: FiniteFloat 

648 

649m = Model(finite=1.0) 

650print(m) 

651#> finite=1.0 

652``` 

653""" 

654 

655 

656# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

657 

658 

659def conbytes( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

660 *, 

661 min_length: int | None = None, 

662 max_length: int | None = None, 

663 strict: bool | None = None, 

664) -> type[bytes]: 

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

666 

667 Args: 

668 min_length: The minimum length of the bytes. 

669 max_length: The maximum length of the bytes. 

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

671 

672 Returns: 

673 The wrapped bytes type. 

674 """ 

675 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

676 bytes, 

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

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

679 ] 

680 

681 

682StrictBytes = Annotated[bytes, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

683"""A bytes that must be validated in strict mode.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

684 

685 

686# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

687 

688 

689@_dataclasses.dataclass(frozen=True) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

690class StringConstraints(annotated_types.GroupedMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

691 """!!! abstract "Usage Documentation" 

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

693 

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

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

696 

697 Attributes: 

698 strip_whitespace: Whether to remove leading and trailing whitespace. 

699 to_upper: Whether to convert the string to uppercase. 

700 to_lower: Whether to convert the string to lowercase. 

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

702 min_length: The minimum length of the string. 

703 max_length: The maximum length of the string. 

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

705 

706 Example: 

707 ```python 

708 from typing import Annotated 

709 

710 from pydantic.types import StringConstraints 

711 

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

713 ``` 

714 """ 

715 

716 strip_whitespace: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

717 to_upper: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

718 to_lower: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

719 strict: bool | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

720 min_length: int | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

721 max_length: int | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

722 pattern: str | Pattern[str] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

723 

724 def __iter__(self) -> Iterator[BaseMetadata]: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

725 if self.min_length is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

726 yield MinLen(self.min_length) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

727 if self.max_length is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

728 yield MaxLen(self.max_length) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

729 if self.strict is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

730 yield Strict(self.strict) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

731 if ( 1zABa

732 self.strip_whitespace is not None 

733 or self.pattern is not None 

734 or self.to_lower is not None 

735 or self.to_upper is not None 

736 ): 

737 yield _fields.pydantic_general_metadata( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

738 strip_whitespace=self.strip_whitespace, 

739 to_upper=self.to_upper, 

740 to_lower=self.to_lower, 

741 pattern=self.pattern, 

742 ) 

743 

744 

745def constr( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

746 *, 

747 strip_whitespace: bool | None = None, 

748 to_upper: bool | None = None, 

749 to_lower: bool | None = None, 

750 strict: bool | None = None, 

751 min_length: int | None = None, 

752 max_length: int | None = None, 

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

754) -> type[str]: 

755 """ 

756 !!! warning "Discouraged" 

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

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

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

760 

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

762 

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

764 

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

766 ```python 

767 from pydantic import BaseModel, constr 

768 

769 class Foo(BaseModel): 

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

771 ``` 

772 

773 === ":white_check_mark: Do this" 

774 ```python 

775 from typing import Annotated 

776 

777 from pydantic import BaseModel, StringConstraints 

778 

779 class Foo(BaseModel): 

780 bar: Annotated[ 

781 str, 

782 StringConstraints( 

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

784 ), 

785 ] 

786 ``` 

787 

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

789 

790 ```python 

791 from pydantic import BaseModel, constr 

792 

793 class Foo(BaseModel): 

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

795 

796 foo = Foo(bar=' hello ') 

797 print(foo) 

798 #> bar='HELLO' 

799 ``` 

800 

801 Args: 

802 strip_whitespace: Whether to remove leading and trailing whitespace. 

803 to_upper: Whether to turn all characters to uppercase. 

804 to_lower: Whether to turn all characters to lowercase. 

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

806 min_length: The minimum length of the string. 

807 max_length: The maximum length of the string. 

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

809 

810 Returns: 

811 The wrapped string type. 

812 """ # noqa: D212 

813 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

814 str, 

815 StringConstraints( 

816 strip_whitespace=strip_whitespace, 

817 to_upper=to_upper, 

818 to_lower=to_lower, 

819 strict=strict, 

820 min_length=min_length, 

821 max_length=max_length, 

822 pattern=pattern, 

823 ), 

824 ] 

825 

826 

827StrictStr = Annotated[str, Strict()] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

828"""A string that must be validated in strict mode.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

829 

830 

831# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

832HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

833 

834 

835def conset( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

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

839 

840 Args: 

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

842 min_length: The minimum length of the set. 

843 max_length: The maximum length of the set. 

844 

845 Returns: 

846 The wrapped set type. 

847 """ 

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

849 

850 

851def confrozenset( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

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

855 

856 Args: 

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

858 min_length: The minimum length of the frozenset. 

859 max_length: The maximum length of the frozenset. 

860 

861 Returns: 

862 The wrapped frozenset type. 

863 """ 

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

865 

866 

867AnyItemType = TypeVar('AnyItemType') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

868 

869 

870def conlist( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

871 item_type: type[AnyItemType], 

872 *, 

873 min_length: int | None = None, 

874 max_length: int | None = None, 

875 unique_items: bool | None = None, 

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

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

878 

879 Args: 

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

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

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

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

884 !!! warning Deprecated 

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

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

887 

888 Returns: 

889 The wrapped list type. 

890 """ 

891 if unique_items is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

892 raise PydanticUserError( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

893 ( 

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

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

896 ), 

897 code='removed-kwargs', 

898 ) 

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

900 

901 

902# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

903 

904AnyType = TypeVar('AnyType') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

905if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

906 ImportString = Annotated[AnyType, ...] 

907else: 

908 

909 class ImportString: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

911 

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

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

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

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

916 

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

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

919 

920 ```python 

921 import math 

922 

923 from pydantic import BaseModel, Field, ImportString, ValidationError 

924 

925 class ImportThings(BaseModel): 

926 obj: ImportString 

927 

928 # A string value will cause an automatic import 

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

930 

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

932 cos_of_0 = my_cos.obj(0) 

933 assert cos_of_0 == 1 

934 

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

936 try: 

937 ImportThings(obj='foo.bar') 

938 except ValidationError as e: 

939 print(e) 

940 ''' 

941 1 validation error for ImportThings 

942 obj 

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

944 ''' 

945 

946 # Actual python objects can be assigned as well 

947 my_cos = ImportThings(obj=math.cos) 

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

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

950 assert my_cos == my_cos_2 == my_cos_3 

951 

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

953 class ImportThingsDefaultPyObj(BaseModel): 

954 obj: ImportString = math.cos 

955 

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

957 class ImportThingsDefaultString(BaseModel): 

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

959 

960 my_cos_default1 = ImportThingsDefaultPyObj() 

961 my_cos_default2 = ImportThingsDefaultString() 

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

963 

964 # note: this will not work! 

965 class ImportThingsMissingValidateDefault(BaseModel): 

966 obj: ImportString = 'math.cos' 

967 

968 my_cos_default3 = ImportThingsMissingValidateDefault() 

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

970 ``` 

971 

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

973 

974 ```python 

975 from pydantic import BaseModel, ImportString 

976 

977 class ImportThings(BaseModel): 

978 obj: ImportString 

979 

980 # Create an instance 

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

982 print(m) 

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

984 print(m.model_dump_json()) 

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

986 ``` 

987 """ 

988 

989 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

990 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

991 return Annotated[item, cls()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

992 

993 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

994 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

996 ) -> core_schema.CoreSchema: 

997 serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

998 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

1000 return core_schema.no_info_plain_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1001 function=_validators.import_string, serialization=serializer 

1002 ) 

1003 else: 

1004 return core_schema.no_info_before_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

1006 ) 

1007 

1008 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1009 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1010 return handler(core_schema.str_schema()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1011 

1012 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1013 def _serialize(v: Any) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1014 if isinstance(v, ModuleType): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1015 return v.__name__ 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1016 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1017 return f'{v.__module__}.{v.__name__}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1018 # Handle special cases for sys.XXX streams 

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

1020 elif hasattr(v, 'name'): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1021 if v.name == '<stdout>': 1021 ↛ 1022line 1021 didn't jump to line 1022 because the condition on line 1021 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1022 return 'sys.stdout' 

1023 elif v.name == '<stdin>': 1023 ↛ 1024line 1023 didn't jump to line 1024 because the condition on line 1023 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1024 return 'sys.stdin' 

1025 elif v.name == '<stderr>': 1025 ↛ 1026line 1025 didn't jump to line 1026 because the condition on line 1025 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1026 return 'sys.stderr' 

1027 else: 

1028 return v 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1029 

1030 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1031 return 'ImportString' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1032 

1033 

1034# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1035 

1036 

1037def condecimal( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1038 *, 

1039 strict: bool | None = None, 

1040 gt: int | Decimal | None = None, 

1041 ge: int | Decimal | None = None, 

1042 lt: int | Decimal | None = None, 

1043 le: int | Decimal | None = None, 

1044 multiple_of: int | Decimal | None = None, 

1045 max_digits: int | None = None, 

1046 decimal_places: int | None = None, 

1047 allow_inf_nan: bool | None = None, 

1048) -> type[Decimal]: 

1049 """ 

1050 !!! warning "Discouraged" 

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

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

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

1054 

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

1056 

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

1058 

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

1060 ```python 

1061 from pydantic import BaseModel, condecimal 

1062 

1063 class Foo(BaseModel): 

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

1065 ``` 

1066 

1067 === ":white_check_mark: Do this" 

1068 ```python 

1069 from decimal import Decimal 

1070 from typing import Annotated 

1071 

1072 from pydantic import BaseModel, Field 

1073 

1074 class Foo(BaseModel): 

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

1076 ``` 

1077 

1078 A wrapper around Decimal that adds validation. 

1079 

1080 Args: 

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

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

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

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

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

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

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

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

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

1090 

1091 ```python 

1092 from decimal import Decimal 

1093 

1094 from pydantic import BaseModel, ValidationError, condecimal 

1095 

1096 class ConstrainedExample(BaseModel): 

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

1098 

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

1100 print(repr(m)) 

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

1102 

1103 try: 

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

1105 except ValidationError as e: 

1106 print(e.errors()) 

1107 ''' 

1108 [ 

1109 { 

1110 'type': 'greater_than', 

1111 'loc': ('constrained_decimal',), 

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

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

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

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

1116 } 

1117 ] 

1118 ''' 

1119 ``` 

1120 """ # noqa: D212 

1121 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1122 Decimal, 

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

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

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

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

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

1128 ] 

1129 

1130 

1131# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1132 

1133 

1134@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1135class UuidVersion: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1137 

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

1139 

1140 Attributes: 

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

1142 

1143 Example: 

1144 ```python 

1145 from typing import Annotated 

1146 from uuid import UUID 

1147 

1148 from pydantic.types import UuidVersion 

1149 

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

1151 ``` 

1152 """ 

1153 

1154 uuid_version: Literal[1, 3, 4, 5] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1155 

1156 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1158 ) -> JsonSchemaValue: 

1159 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

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

1162 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1163 

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

1165 if isinstance(self, source): 1165 ↛ 1167line 1165 didn't jump to line 1167 because the condition on line 1165 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1166 # used directly as a type 

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

1168 else: 

1169 # update existing schema with self.uuid_version 

1170 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1171 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1172 schema['version'] = self.uuid_version # type: ignore 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1173 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1174 

1175 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1176 return hash(type(self.uuid_version)) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1177 

1178 

1179UUID1 = Annotated[UUID, UuidVersion(1)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1181 

1182```python 

1183import uuid 

1184 

1185from pydantic import UUID1, BaseModel 

1186 

1187class Model(BaseModel): 

1188 uuid1: UUID1 

1189 

1190Model(uuid1=uuid.uuid1()) 

1191``` 

1192""" 

1193UUID3 = Annotated[UUID, UuidVersion(3)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1195 

1196```python 

1197import uuid 

1198 

1199from pydantic import UUID3, BaseModel 

1200 

1201class Model(BaseModel): 

1202 uuid3: UUID3 

1203 

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

1205``` 

1206""" 

1207UUID4 = Annotated[UUID, UuidVersion(4)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1209 

1210```python 

1211import uuid 

1212 

1213from pydantic import UUID4, BaseModel 

1214 

1215class Model(BaseModel): 

1216 uuid4: UUID4 

1217 

1218Model(uuid4=uuid.uuid4()) 

1219``` 

1220""" 

1221UUID5 = Annotated[UUID, UuidVersion(5)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1223 

1224```python 

1225import uuid 

1226 

1227from pydantic import UUID5, BaseModel 

1228 

1229class Model(BaseModel): 

1230 uuid5: UUID5 

1231 

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

1233``` 

1234""" 

1235 

1236 

1237# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1238 

1239 

1240@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1241class PathType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1242 path_type: Literal['file', 'dir', 'new', 'socket'] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1243 

1244 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1246 ) -> JsonSchemaValue: 

1247 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1248 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

1250 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1251 

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

1253 function_lookup = { 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

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

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

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

1258 } 

1259 

1260 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1261 function_lookup[self.path_type], 

1262 handler(source), 

1263 ) 

1264 

1265 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1266 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1267 if path.is_file(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1268 return path 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1269 else: 

1270 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1271 

1272 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1273 def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1274 if path.is_socket(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1275 return path 1zAbcdefghiBa

1276 else: 

1277 raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1278 

1279 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1280 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1281 if path.is_dir(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1282 return path 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1283 else: 

1284 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1285 

1286 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1287 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1288 if path.exists(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1289 raise PydanticCustomError('path_exists', 'Path already exists') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1290 elif not path.parent.exists(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1291 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1292 else: 

1293 return path 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1294 

1295 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1296 return hash(type(self.path_type)) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1297 

1298 

1299FilePath = Annotated[Path, PathType('file')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1300"""A path that must point to a file. 1bcdefghiajklmnopqGHIJKLrstuvwxy

1301 

1302```python 

1303from pathlib import Path 

1304 

1305from pydantic import BaseModel, FilePath, ValidationError 

1306 

1307class Model(BaseModel): 

1308 f: FilePath 

1309 

1310path = Path('text.txt') 

1311path.touch() 

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

1313print(m.model_dump()) 

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

1315path.unlink() 

1316 

1317path = Path('directory') 

1318path.mkdir(exist_ok=True) 

1319try: 

1320 Model(f='directory') # directory 

1321except ValidationError as e: 

1322 print(e) 

1323 ''' 

1324 1 validation error for Model 

1325 f 

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

1327 ''' 

1328path.rmdir() 

1329 

1330try: 

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

1332except ValidationError as e: 

1333 print(e) 

1334 ''' 

1335 1 validation error for Model 

1336 f 

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

1338 ''' 

1339``` 

1340""" 

1341DirectoryPath = Annotated[Path, PathType('dir')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1342"""A path that must point to a directory. 1bcdefghiajklmnopqGHIJKLrstuvwxy

1343 

1344```python 

1345from pathlib import Path 

1346 

1347from pydantic import BaseModel, DirectoryPath, ValidationError 

1348 

1349class Model(BaseModel): 

1350 f: DirectoryPath 

1351 

1352path = Path('directory/') 

1353path.mkdir() 

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

1355print(m.model_dump()) 

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

1357path.rmdir() 

1358 

1359path = Path('file.txt') 

1360path.touch() 

1361try: 

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

1363except ValidationError as e: 

1364 print(e) 

1365 ''' 

1366 1 validation error for Model 

1367 f 

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

1369 ''' 

1370path.unlink() 

1371 

1372try: 

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

1374except ValidationError as e: 

1375 print(e) 

1376 ''' 

1377 1 validation error for Model 

1378 f 

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

1380 ''' 

1381``` 

1382""" 

1383NewPath = Annotated[Path, PathType('new')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1385 

1386SocketPath = Annotated[Path, PathType('socket')] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1387"""A path to an existing socket file""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

1388 

1389# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1390 

1391if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1393 Json = Annotated[AnyType, ...] 

1394 

1395else: 

1396 

1397 class Json: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1399 

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

1401 validating the loaded data into the parametrized type: 

1402 

1403 ```python 

1404 from typing import Any 

1405 

1406 from pydantic import BaseModel, Json, ValidationError 

1407 

1408 class AnyJsonModel(BaseModel): 

1409 json_obj: Json[Any] 

1410 

1411 class ConstrainedJsonModel(BaseModel): 

1412 json_obj: Json[list[int]] 

1413 

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

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

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

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

1418 

1419 try: 

1420 ConstrainedJsonModel(json_obj=12) 

1421 except ValidationError as e: 

1422 print(e) 

1423 ''' 

1424 1 validation error for ConstrainedJsonModel 

1425 json_obj 

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

1427 ''' 

1428 

1429 try: 

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

1431 except ValidationError as e: 

1432 print(e) 

1433 ''' 

1434 1 validation error for ConstrainedJsonModel 

1435 json_obj 

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

1437 ''' 

1438 

1439 try: 

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

1441 except ValidationError as e: 

1442 print(e) 

1443 ''' 

1444 2 validation errors for ConstrainedJsonModel 

1445 json_obj.0 

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

1447 json_obj.1 

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

1449 ''' 

1450 ``` 

1451 

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

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

1454 

1455 ```python 

1456 from pydantic import BaseModel, Json 

1457 

1458 class ConstrainedJsonModel(BaseModel): 

1459 json_obj: Json[list[int]] 

1460 

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

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

1463 print( 

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

1465 ) 

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

1467 ``` 

1468 """ 

1469 

1470 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1471 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1472 return Annotated[item, cls()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1473 

1474 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1476 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1477 return core_schema.json_schema(None) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1478 else: 

1479 return core_schema.json_schema(handler(source)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1480 

1481 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1482 return 'Json' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1483 

1484 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1485 return hash(type(self)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1486 

1487 def __eq__(self, other: Any) -> bool: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1488 return type(other) is type(self) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1489 

1490 

1491# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1492 

1493SecretType = TypeVar('SecretType') 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1494 

1495 

1496class _SecretBase(Generic[SecretType]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1497 def __init__(self, secret_value: SecretType) -> None: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1498 self._secret_value: SecretType = secret_value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1499 

1500 def get_secret_value(self) -> SecretType: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1501 """Get the secret value. 

1502 

1503 Returns: 

1504 The secret value. 

1505 """ 

1506 return self._secret_value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1507 

1508 def __eq__(self, other: Any) -> bool: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1509 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1510 

1511 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1512 return hash(self.get_secret_value()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1513 

1514 def __str__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1515 return str(self._display()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1516 

1517 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1518 return f'{self.__class__.__name__}({self._display()!r})' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1519 

1520 def _display(self) -> str | bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1521 raise NotImplementedError 

1522 

1523 

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

1525 if info.mode == 'json': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1526 return str(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1527 else: 

1528 return value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1529 

1530 

1531class Secret(_SecretBase[SecretType]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1533 

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

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

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

1537 

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

1539 

1540 ```python 

1541 from pydantic import BaseModel, Secret 

1542 

1543 SecretBool = Secret[bool] 

1544 

1545 class Model(BaseModel): 

1546 secret_bool: SecretBool 

1547 

1548 m = Model(secret_bool=True) 

1549 print(m.model_dump()) 

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

1551 

1552 print(m.model_dump_json()) 

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

1554 

1555 print(m.secret_bool.get_secret_value()) 

1556 #> True 

1557 ``` 

1558 

1559 2. Subclassing from parametrized `Secret`: 

1560 

1561 ```python 

1562 from datetime import date 

1563 

1564 from pydantic import BaseModel, Secret 

1565 

1566 class SecretDate(Secret[date]): 

1567 def _display(self) -> str: 

1568 return '****/**/**' 

1569 

1570 class Model(BaseModel): 

1571 secret_date: SecretDate 

1572 

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

1574 print(m.model_dump()) 

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

1576 

1577 print(m.model_dump_json()) 

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

1579 

1580 print(m.secret_date.get_secret_value()) 

1581 #> 2022-01-01 

1582 ``` 

1583 

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

1585 

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

1587 For example: 

1588 

1589 ```python 

1590 from typing import Annotated 

1591 

1592 from pydantic import BaseModel, Field, Secret, ValidationError 

1593 

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

1595 

1596 class Model(BaseModel): 

1597 sensitive_int: SecretPosInt 

1598 

1599 m = Model(sensitive_int=42) 

1600 print(m.model_dump()) 

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

1602 

1603 try: 

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

1605 except ValidationError as exc_info: 

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

1607 ''' 

1608 [ 

1609 { 

1610 'type': 'greater_than', 

1611 'loc': ('sensitive_int',), 

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

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

1614 } 

1615 ] 

1616 ''' 

1617 

1618 try: 

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

1620 except ValidationError as exc_info: 

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

1622 ''' 

1623 [ 

1624 { 

1625 'type': 'int_type', 

1626 'loc': ('sensitive_int',), 

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

1628 } 

1629 ] 

1630 ''' 

1631 ``` 

1632 

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

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

1635 """ 

1636 

1637 def _display(self) -> str | bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1638 return '**********' if self.get_secret_value() else '' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1639 

1640 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1642 inner_type = None 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

1644 origin_type = get_origin(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1645 if origin_type is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1646 inner_type = get_args(source)[0] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

1648 else: 

1649 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1650 for base in bases: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1651 if get_origin(base) is Secret: 1651 ↛ 1650line 1651 didn't jump to line 1650 because the condition on line 1651 was always true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1652 inner_type = get_args(base)[0] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1653 if bases == [] or inner_type is None: 1653 ↛ 1654line 1653 didn't jump to line 1654 because the condition on line 1653 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1654 raise TypeError( 

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

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

1657 ) 

1658 

1659 inner_schema = handler.generate_schema(inner_type) # type: ignore 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1660 

1661 def validate_secret_value(value, handler) -> Secret[SecretType]: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1662 if isinstance(value, Secret): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1663 value = value.get_secret_value() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1664 validated_inner = handler(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1665 return cls(validated_inner) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1666 

1667 return core_schema.json_or_python_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1668 python_schema=core_schema.no_info_wrap_validator_function( 

1669 validate_secret_value, 

1670 inner_schema, 

1671 ), 

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

1673 serialization=core_schema.plain_serializer_function_ser_schema( 

1674 _serialize_secret, 

1675 info_arg=True, 

1676 when_used='always', 

1677 ), 

1678 ) 

1679 

1680 __pydantic_serializer__ = SchemaSerializer( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1681 core_schema.any_schema( 

1682 serialization=core_schema.plain_serializer_function_ser_schema( 

1683 _serialize_secret, 

1684 info_arg=True, 

1685 when_used='always', 

1686 ) 

1687 ) 

1688 ) 

1689 

1690 

1691def _secret_display(value: SecretType) -> str: # type: ignore 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1692 return '**********' if value else '' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1693 

1694 

1695def _serialize_secret_field( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1697) -> str | _SecretField[SecretType]: 

1698 if info.mode == 'json': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

1700 # hence we just use `secret_display` 

1701 return _secret_display(value.get_secret_value()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1702 else: 

1703 return value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1704 

1705 

1706class _SecretField(_SecretBase[SecretType]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1707 _inner_schema: ClassVar[CoreSchema] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1708 _error_kind: ClassVar[str] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1709 

1710 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

1713 json_schema = handler(cls._inner_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1714 _utils.update_not_none( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1715 json_schema, 

1716 type='string', 

1717 writeOnly=True, 

1718 format='password', 

1719 ) 

1720 return json_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1721 

1722 json_schema = core_schema.no_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1723 source, # construct the type 

1724 cls._inner_schema, 

1725 ) 

1726 

1727 def get_secret_schema(strict: bool) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1728 return core_schema.json_or_python_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1729 python_schema=core_schema.union_schema( 

1730 [ 

1731 core_schema.is_instance_schema(source), 

1732 json_schema, 

1733 ], 

1734 custom_error_type=cls._error_kind, 

1735 strict=strict, 

1736 ), 

1737 json_schema=json_schema, 

1738 serialization=core_schema.plain_serializer_function_ser_schema( 

1739 _serialize_secret_field, 

1740 info_arg=True, 

1741 when_used='always', 

1742 ), 

1743 ) 

1744 

1745 return core_schema.lax_or_strict_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1746 lax_schema=get_secret_schema(strict=False), 

1747 strict_schema=get_secret_schema(strict=True), 

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

1749 ) 

1750 

1751 __pydantic_serializer__ = SchemaSerializer( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1752 core_schema.any_schema( 

1753 serialization=core_schema.plain_serializer_function_ser_schema( 

1754 _serialize_secret_field, 

1755 info_arg=True, 

1756 when_used='always', 

1757 ) 

1758 ) 

1759 ) 

1760 

1761 

1762class SecretStr(_SecretField[str]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1764 

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

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

1767 

1768 ```python 

1769 from pydantic import BaseModel, SecretStr 

1770 

1771 class User(BaseModel): 

1772 username: str 

1773 password: SecretStr 

1774 

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

1776 

1777 print(user) 

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

1779 print(user.password.get_secret_value()) 

1780 #> password1 

1781 print((SecretStr('password'), SecretStr(''))) 

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

1783 ``` 

1784 

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

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

1787 

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

1789 secret as plain-text when serializing to json. 

1790 

1791 ```python 

1792 from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer 

1793 

1794 class Model(BaseModel): 

1795 password: SecretStr 

1796 password_bytes: SecretBytes 

1797 

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

1799 def dump_secret(self, v): 

1800 return v.get_secret_value() 

1801 

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

1803 print(model) 

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

1805 print(model.password) 

1806 #> ********** 

1807 print(model.model_dump()) 

1808 ''' 

1809 { 

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

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

1812 } 

1813 ''' 

1814 print(model.model_dump_json()) 

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

1816 ``` 

1817 """ 

1818 

1819 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1820 _error_kind: ClassVar[str] = 'string_type' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1821 

1822 def __len__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1823 return len(self._secret_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1824 

1825 def _display(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1826 return _secret_display(self._secret_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1827 

1828 

1829class SecretBytes(_SecretField[bytes]): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1831 

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

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

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

1835 

1836 ```python 

1837 from pydantic import BaseModel, SecretBytes 

1838 

1839 class User(BaseModel): 

1840 username: str 

1841 password: SecretBytes 

1842 

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

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

1845 print(user.password.get_secret_value()) 

1846 #> b'password1' 

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

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

1849 ``` 

1850 """ 

1851 

1852 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1853 _error_kind: ClassVar[str] = 'bytes_type' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1854 

1855 def __len__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1856 return len(self._secret_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1857 

1858 def _display(self) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1859 return _secret_display(self._secret_value).encode() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1860 

1861 

1862# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1863 

1864 

1865class PaymentCardBrand(str, Enum): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1866 amex = 'American Express' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1867 mastercard = 'Mastercard' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1868 visa = 'Visa' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1869 other = 'other' 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1870 

1871 def __str__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1872 return self.value 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1873 

1874 

1875@deprecated( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

1878 category=PydanticDeprecatedSince20, 

1879) 

1880class PaymentCardNumber(str): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1882 

1883 strip_whitespace: ClassVar[bool] = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1884 min_length: ClassVar[int] = 12 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1885 max_length: ClassVar[int] = 19 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1886 bin: str 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1887 last4: str 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1888 brand: PaymentCardBrand 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1889 

1890 def __init__(self, card_number: str): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1891 self.validate_digits(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1892 

1893 card_number = self.validate_luhn_check_digit(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1894 

1895 self.bin = card_number[:6] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1896 self.last4 = card_number[-4:] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1897 self.brand = self.validate_brand(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1898 

1899 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1901 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1902 cls.validate, 

1903 core_schema.str_schema( 

1904 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace 

1905 ), 

1906 ) 

1907 

1908 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

1911 return cls(input_value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1912 

1913 @property 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1914 def masked(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1916 

1917 Returns: 

1918 A masked card number string. 

1919 """ 

1920 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1921 return f'{self.bin}{"*" * num_masked}{self.last4}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1922 

1923 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1924 def validate_digits(cls, card_number: str) -> None: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1926 if not card_number.isdigit(): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1927 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1928 

1929 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1930 def validate_luhn_check_digit(cls, card_number: str) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1932 sum_ = int(card_number[-1]) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1933 length = len(card_number) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1934 parity = length % 2 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1935 for i in range(length - 1): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1936 digit = int(card_number[i]) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1937 if i % 2 == parity: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1938 digit *= 2 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1939 if digit > 9: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1940 digit -= 9 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1941 sum_ += digit 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1942 valid = sum_ % 10 == 0 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1943 if not valid: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1944 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1945 return card_number 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1946 

1947 @staticmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

1948 def validate_brand(card_number: str) -> PaymentCardBrand: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

1951 """ 

1952 if card_number[0] == '4': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1953 brand = PaymentCardBrand.visa 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1954 elif 51 <= int(card_number[:2]) <= 55: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1955 brand = PaymentCardBrand.mastercard 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1956 elif card_number[:2] in {'34', '37'}: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1957 brand = PaymentCardBrand.amex 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1958 else: 

1959 brand = PaymentCardBrand.other 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1960 

1961 required_length: None | int | str = None 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1962 if brand in PaymentCardBrand.mastercard: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1963 required_length = 16 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1964 valid = len(card_number) == required_length 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1965 elif brand == PaymentCardBrand.visa: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1966 required_length = '13, 16 or 19' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1967 valid = len(card_number) in {13, 16, 19} 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1968 elif brand == PaymentCardBrand.amex: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1969 required_length = 15 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1970 valid = len(card_number) == required_length 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1971 else: 

1972 valid = True 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1973 

1974 if not valid: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1975 raise PydanticCustomError( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1976 'payment_card_number_brand', 

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

1978 {'brand': brand, 'required_length': required_length}, 

1979 ) 

1980 return brand 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

1981 

1982 

1983# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1984 

1985 

1986class ByteSize(int): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

1988 

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

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

1991 

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

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

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

1995 

1996 !!! info 

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

1998 

1999 ```python 

2000 from pydantic import BaseModel, ByteSize 

2001 

2002 class MyModel(BaseModel): 

2003 size: ByteSize 

2004 

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

2006 #> 52000 

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

2008 #> 3072000 

2009 

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

2011 print(m.size.human_readable()) 

2012 #> 44.4PiB 

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

2014 #> 50.0PB 

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

2016 #> 44.4 PiB 

2017 

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

2019 #> 45474.73508864641 

2020 ``` 

2021 """ 

2022 

2023 byte_sizes = { 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2024 'b': 1, 

2025 'kb': 10**3, 

2026 'mb': 10**6, 

2027 'gb': 10**9, 

2028 'tb': 10**12, 

2029 'pb': 10**15, 

2030 'eb': 10**18, 

2031 'kib': 2**10, 

2032 'mib': 2**20, 

2033 'gib': 2**30, 

2034 'tib': 2**40, 

2035 'pib': 2**50, 

2036 'eib': 2**60, 

2037 'bit': 1 / 8, 

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

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

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

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

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

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

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

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

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

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

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

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

2050 } 

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

2052 

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

2054 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2055 

2056 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2058 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2059 function=cls._validate, 

2060 schema=core_schema.union_schema( 

2061 [ 

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

2063 core_schema.int_schema(ge=0), 

2064 ], 

2065 custom_error_type='byte_size', 

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

2067 ), 

2068 serialization=core_schema.plain_serializer_function_ser_schema( 

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

2070 ), 

2071 ) 

2072 

2073 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2075 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2076 return cls(int(input_value)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2077 except ValueError: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2078 pass 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2079 

2080 str_match = cls.byte_string_re.match(str(input_value)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2081 if str_match is None: 2081 ↛ 2082line 2081 didn't jump to line 2082 because the condition on line 2081 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

2083 

2084 scalar, unit = str_match.groups() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2085 if unit is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2086 unit = 'b' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2087 

2088 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2089 unit_mult = cls.byte_sizes[unit.lower()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2090 except KeyError: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

2092 

2093 return cls(int(float(scalar) * unit_mult)) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2094 

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

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

2097 

2098 Args: 

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

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

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

2102 

2103 Returns: 

2104 A human readable string representation of the byte size. 

2105 """ 

2106 if decimal: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2107 divisor = 1000 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2108 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2109 final_unit = 'EB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2110 else: 

2111 divisor = 1024 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2112 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2113 final_unit = 'EiB' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2114 

2115 num = float(self) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2116 for unit in units: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2117 if abs(num) < divisor: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2118 if unit == 'B': 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2119 return f'{num:0.0f}{separator}{unit}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2120 else: 

2121 return f'{num:0.1f}{separator}{unit}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2122 num /= divisor 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2123 

2124 return f'{num:0.1f}{separator}{final_unit}' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2125 

2126 def to(self, unit: str) -> float: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2128 

2129 Args: 

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

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

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

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

2134 

2135 Returns: 

2136 The byte size in the new unit. 

2137 """ 

2138 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2139 unit_div = self.byte_sizes[unit.lower()] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2140 except KeyError: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

2142 

2143 return self / unit_div 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2144 

2145 

2146# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2147 

2148 

2149def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2150 if annotated_type != expected_type: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

2152 

2153 

2154if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2155 PastDate = Annotated[date, ...] 

2156 FutureDate = Annotated[date, ...] 

2157else: 

2158 

2159 class PastDate: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2160 """A date in the past.""" 

2161 

2162 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2163 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2165 ) -> core_schema.CoreSchema: 

2166 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2167 # used directly as a type 

2168 return core_schema.date_schema(now_op='past') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2169 else: 

2170 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2171 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2172 schema['now_op'] = 'past' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2173 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2174 

2175 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2176 return 'PastDate' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2177 

2178 class FutureDate: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2179 """A date in the future.""" 

2180 

2181 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2182 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2184 ) -> core_schema.CoreSchema: 

2185 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2186 # used directly as a type 

2187 return core_schema.date_schema(now_op='future') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2188 else: 

2189 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2190 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2191 schema['now_op'] = 'future' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2192 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2193 

2194 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2195 return 'FutureDate' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2196 

2197 

2198def condate( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2199 *, 

2200 strict: bool | None = None, 

2201 gt: date | None = None, 

2202 ge: date | None = None, 

2203 lt: date | None = None, 

2204 le: date | None = None, 

2205) -> type[date]: 

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

2207 

2208 Args: 

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

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

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

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

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

2214 

2215 Returns: 

2216 A date type with the specified constraints. 

2217 """ 

2218 return Annotated[ # pyright: ignore[reportReturnType] 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2219 date, 

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

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

2222 ] 

2223 

2224 

2225# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2226 

2227if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2228 AwareDatetime = Annotated[datetime, ...] 

2229 NaiveDatetime = Annotated[datetime, ...] 

2230 PastDatetime = Annotated[datetime, ...] 

2231 FutureDatetime = Annotated[datetime, ...] 

2232 

2233else: 

2234 

2235 class AwareDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2237 

2238 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2239 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2241 ) -> core_schema.CoreSchema: 

2242 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2243 # used directly as a type 

2244 return core_schema.datetime_schema(tz_constraint='aware') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2245 else: 

2246 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2247 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2248 schema['tz_constraint'] = 'aware' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2249 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2250 

2251 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2252 return 'AwareDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2253 

2254 class NaiveDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2256 

2257 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2258 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2260 ) -> core_schema.CoreSchema: 

2261 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2262 # used directly as a type 

2263 return core_schema.datetime_schema(tz_constraint='naive') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2264 else: 

2265 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2266 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2267 schema['tz_constraint'] = 'naive' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2268 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2269 

2270 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2271 return 'NaiveDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2272 

2273 class PastDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2275 

2276 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2277 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2279 ) -> core_schema.CoreSchema: 

2280 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2281 # used directly as a type 

2282 return core_schema.datetime_schema(now_op='past') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2283 else: 

2284 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2285 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2286 schema['now_op'] = 'past' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2287 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2288 

2289 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2290 return 'PastDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2291 

2292 class FutureDatetime: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2294 

2295 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2296 def __get_pydantic_core_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2298 ) -> core_schema.CoreSchema: 

2299 if cls is source: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2300 # used directly as a type 

2301 return core_schema.datetime_schema(now_op='future') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2302 else: 

2303 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2304 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2305 schema['now_op'] = 'future' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2306 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2307 

2308 def __repr__(self) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2309 return 'FutureDatetime' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2310 

2311 

2312# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2313 

2314 

2315class EncoderProtocol(Protocol): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2316 """Protocol for encoding and decoding data to and from bytes.""" 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2317 

2318 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2319 def decode(cls, data: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2320 """Decode the data using the encoder. 

2321 

2322 Args: 

2323 data: The data to decode. 

2324 

2325 Returns: 

2326 The decoded data. 

2327 """ 

2328 ... 

2329 

2330 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2331 def encode(cls, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2332 """Encode the data using the encoder. 

2333 

2334 Args: 

2335 value: The data to encode. 

2336 

2337 Returns: 

2338 The encoded data. 

2339 """ 

2340 ... 

2341 

2342 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2343 def get_json_format(cls) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2345 

2346 Returns: 

2347 The JSON format for the encoded data. 

2348 """ 

2349 ... 

2350 

2351 

2352class Base64Encoder(EncoderProtocol): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2354 

2355 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2356 def decode(cls, data: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2358 

2359 Args: 

2360 data: The data to decode. 

2361 

2362 Returns: 

2363 The decoded data. 

2364 """ 

2365 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2366 return base64.b64decode(data) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2367 except ValueError as e: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

2369 

2370 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2371 def encode(cls, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2373 

2374 Args: 

2375 value: The data to encode. 

2376 

2377 Returns: 

2378 The encoded data. 

2379 """ 

2380 return base64.b64encode(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2381 

2382 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2383 def get_json_format(cls) -> Literal['base64']: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2385 

2386 Returns: 

2387 The JSON format for the encoded data. 

2388 """ 

2389 return 'base64' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2390 

2391 

2392class Base64UrlEncoder(EncoderProtocol): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2393 """URL-safe Base64 encoder.""" 

2394 

2395 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2396 def decode(cls, data: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2398 

2399 Args: 

2400 data: The data to decode. 

2401 

2402 Returns: 

2403 The decoded data. 

2404 """ 

2405 try: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2406 return base64.urlsafe_b64decode(data) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2407 except ValueError as e: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

2409 

2410 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2411 def encode(cls, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2413 

2414 Args: 

2415 value: The data to encode. 

2416 

2417 Returns: 

2418 The encoded data. 

2419 """ 

2420 return base64.urlsafe_b64encode(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2421 

2422 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2423 def get_json_format(cls) -> Literal['base64url']: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2425 

2426 Returns: 

2427 The JSON format for the encoded data. 

2428 """ 

2429 return 'base64url' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2430 

2431 

2432@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2433class EncodedBytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2435 

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

2437 

2438 ```python 

2439 from typing import Annotated 

2440 

2441 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError 

2442 

2443 class MyEncoder(EncoderProtocol): 

2444 @classmethod 

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

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

2447 raise ValueError('Cannot decode data') 

2448 return data[13:] 

2449 

2450 @classmethod 

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

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

2453 

2454 @classmethod 

2455 def get_json_format(cls) -> str: 

2456 return 'my-encoder' 

2457 

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

2459 

2460 class Model(BaseModel): 

2461 my_encoded_bytes: MyEncodedBytes 

2462 

2463 # Initialize the model with encoded data 

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

2465 

2466 # Access decoded value 

2467 print(m.my_encoded_bytes) 

2468 #> b'some bytes' 

2469 

2470 # Serialize into the encoded form 

2471 print(m.model_dump()) 

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

2473 

2474 # Validate encoded data 

2475 try: 

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

2477 except ValidationError as e: 

2478 print(e) 

2479 ''' 

2480 1 validation error for Model 

2481 my_encoded_bytes 

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

2483 ''' 

2484 ``` 

2485 """ 

2486 

2487 encoder: type[EncoderProtocol] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2488 

2489 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2491 ) -> JsonSchemaValue: 

2492 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2493 field_schema.update(type='string', format=self.encoder.get_json_format()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2494 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2495 

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

2497 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2498 _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2499 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2500 function=self.decode, 

2501 schema=schema, 

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

2503 ) 

2504 

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

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

2507 

2508 Args: 

2509 data: The data to decode. 

2510 

2511 Returns: 

2512 The decoded data. 

2513 """ 

2514 return self.encoder.decode(data) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2515 

2516 def encode(self, value: bytes) -> bytes: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2518 

2519 Args: 

2520 value: The data to encode. 

2521 

2522 Returns: 

2523 The encoded data. 

2524 """ 

2525 return self.encoder.encode(value) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2526 

2527 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2528 return hash(self.encoder) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2529 

2530 

2531@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2532class EncodedStr: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2534 

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

2536 

2537 ```python 

2538 from typing import Annotated 

2539 

2540 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError 

2541 

2542 class MyEncoder(EncoderProtocol): 

2543 @classmethod 

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

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

2546 raise ValueError('Cannot decode data') 

2547 return data[13:] 

2548 

2549 @classmethod 

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

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

2552 

2553 @classmethod 

2554 def get_json_format(cls) -> str: 

2555 return 'my-encoder' 

2556 

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

2558 

2559 class Model(BaseModel): 

2560 my_encoded_str: MyEncodedStr 

2561 

2562 # Initialize the model with encoded data 

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

2564 

2565 # Access decoded value 

2566 print(m.my_encoded_str) 

2567 #> some str 

2568 

2569 # Serialize into the encoded form 

2570 print(m.model_dump()) 

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

2572 

2573 # Validate encoded data 

2574 try: 

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

2576 except ValidationError as e: 

2577 print(e) 

2578 ''' 

2579 1 validation error for Model 

2580 my_encoded_str 

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

2582 ''' 

2583 ``` 

2584 """ 

2585 

2586 encoder: type[EncoderProtocol] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2587 

2588 def __get_pydantic_json_schema__( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2590 ) -> JsonSchemaValue: 

2591 field_schema = handler(core_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2592 field_schema.update(type='string', format=self.encoder.get_json_format()) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2593 return field_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2594 

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

2596 schema = handler(source) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2597 _check_annotated_type(schema['type'], 'str', self.__class__.__name__) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2598 return core_schema.with_info_after_validator_function( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2599 function=self.decode_str, 

2600 schema=schema, 

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

2602 ) 

2603 

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

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

2606 

2607 Args: 

2608 data: The data to decode. 

2609 

2610 Returns: 

2611 The decoded data. 

2612 """ 

2613 return self.encoder.decode(data.encode()).decode() 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2614 

2615 def encode_str(self, value: str) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2617 

2618 Args: 

2619 value: The data to encode. 

2620 

2621 Returns: 

2622 The encoded data. 

2623 """ 

2624 return self.encoder.encode(value.encode()).decode() # noqa: UP008 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2625 

2626 def __hash__(self) -> int: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2627 return hash(self.encoder) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2628 

2629 

2630Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2632 

2633Note: 

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

2635 

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

2637 decoding. 

2638 

2639Warning: 

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

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

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

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

2644 

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

2646 like follows: 

2647 

2648 ```python 

2649 import base64 

2650 from typing import Annotated, Literal 

2651 

2652 from pydantic_core import PydanticCustomError 

2653 

2654 from pydantic import EncodedBytes, EncoderProtocol 

2655 

2656 class LegacyBase64Encoder(EncoderProtocol): 

2657 @classmethod 

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

2659 try: 

2660 return base64.decodebytes(data) 

2661 except ValueError as e: 

2662 raise PydanticCustomError( 

2663 'base64_decode', 

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

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

2666 ) 

2667 

2668 @classmethod 

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

2670 return base64.encodebytes(value) 

2671 

2672 @classmethod 

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

2674 return 'base64' 

2675 

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

2677 ``` 

2678 

2679```python 

2680from pydantic import Base64Bytes, BaseModel, ValidationError 

2681 

2682class Model(BaseModel): 

2683 base64_bytes: Base64Bytes 

2684 

2685# Initialize the model with base64 data 

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

2687 

2688# Access decoded value 

2689print(m.base64_bytes) 

2690#> b'This is the way' 

2691 

2692# Serialize into the base64 form 

2693print(m.model_dump()) 

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

2695 

2696# Validate base64 data 

2697try: 

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

2699except ValidationError as e: 

2700 print(e) 

2701 ''' 

2702 1 validation error for Model 

2703 base64_bytes 

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

2705 ''' 

2706``` 

2707""" 

2708Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2710 

2711Note: 

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

2713 

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

2715 decoding. 

2716 

2717Warning: 

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

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

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

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

2722 

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

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

2725 

2726```python 

2727from pydantic import Base64Str, BaseModel, ValidationError 

2728 

2729class Model(BaseModel): 

2730 base64_str: Base64Str 

2731 

2732# Initialize the model with base64 data 

2733m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y') 

2734 

2735# Access decoded value 

2736print(m.base64_str) 

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

2738 

2739# Serialize into the base64 form 

2740print(m.model_dump()) 

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

2742 

2743# Validate base64 data 

2744try: 

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

2746except ValidationError as e: 

2747 print(e) 

2748 ''' 

2749 1 validation error for Model 

2750 base64_str 

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

2752 ''' 

2753``` 

2754""" 

2755Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2757 

2758Note: 

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

2760 functions. 

2761 

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

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

2764 

2765```python 

2766from pydantic import Base64UrlBytes, BaseModel 

2767 

2768class Model(BaseModel): 

2769 base64url_bytes: Base64UrlBytes 

2770 

2771# Initialize the model with base64 data 

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

2773print(m) 

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

2775``` 

2776""" 

2777Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2779 

2780Note: 

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

2782 functions. 

2783 

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

2785 

2786```python 

2787from pydantic import Base64UrlStr, BaseModel 

2788 

2789class Model(BaseModel): 

2790 base64url_str: Base64UrlStr 

2791 

2792# Initialize the model with base64 data 

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

2794print(m) 

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

2796``` 

2797""" 

2798 

2799 

2800__getattr__ = getattr_migration(__name__) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2801 

2802 

2803@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2804class GetPydanticSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2805 """!!! abstract "Usage Documentation" 

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

2807 

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

2809 

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

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

2812 

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

2814 ```python 

2815 from typing import Annotated, Any 

2816 

2817 from pydantic import BaseModel, GetPydanticSchema 

2818 

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

2820 

2821 class Model(BaseModel): 

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

2823 

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

2825 #> 'abc' 

2826 ``` 

2827 """ 

2828 

2829 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2830 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2831 

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

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

2834 

2835 if not TYPE_CHECKING: 2835 ↛ 2847line 2835 didn't jump to line 2847 because the condition on line 2835 was always true1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2837 

2838 def __getattr__(self, item: str) -> Any: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2840 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2841 return self.get_pydantic_core_schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2842 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2842 ↛ 2843line 2842 didn't jump to line 2843 because the condition on line 2842 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2843 return self.get_pydantic_json_schema 

2844 else: 

2845 return object.__getattribute__(self, item) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2846 

2847 __hash__ = object.__hash__ 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2848 

2849 

2850@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2851class Tag: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

2853 

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

2855 

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

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

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

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

2860 

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

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

2863 

2864 ```python 

2865 from typing import Annotated, Any, Literal, Union 

2866 

2867 from pydantic import BaseModel, Discriminator, Tag 

2868 

2869 class Pie(BaseModel): 

2870 time_to_cook: int 

2871 num_ingredients: int 

2872 

2873 class ApplePie(Pie): 

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

2875 

2876 class PumpkinPie(Pie): 

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

2878 

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

2880 if isinstance(v, dict): 

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

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

2883 

2884 class ThanksgivingDinner(BaseModel): 

2885 dessert: Annotated[ 

2886 Union[ 

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

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

2889 ], 

2890 Discriminator(get_discriminator_value), 

2891 ] 

2892 

2893 apple_variation = ThanksgivingDinner.model_validate( 

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

2895 ) 

2896 print(repr(apple_variation)) 

2897 ''' 

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

2899 ''' 

2900 

2901 pumpkin_variation = ThanksgivingDinner.model_validate( 

2902 { 

2903 'dessert': { 

2904 'filling': 'pumpkin', 

2905 'time_to_cook': 40, 

2906 'num_ingredients': 6, 

2907 } 

2908 } 

2909 ) 

2910 print(repr(pumpkin_variation)) 

2911 ''' 

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

2913 ''' 

2914 ``` 

2915 

2916 !!! note 

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

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

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

2920 

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

2922 

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

2924 """ 

2925 

2926 tag: str 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2927 

2928 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2929 schema = handler(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2930 metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2931 metadata['pydantic_internal_union_tag_key'] = self.tag 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2932 return schema 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

2933 

2934 

2935@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2936class Discriminator: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

2937 """!!! abstract "Usage Documentation" 

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

2939 

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

2941 

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

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

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

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

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

2947 

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

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

2950 

2951 ```python 

2952 from typing import Annotated, Any, Literal, Union 

2953 

2954 from pydantic import BaseModel, Discriminator, Tag 

2955 

2956 class Pie(BaseModel): 

2957 time_to_cook: int 

2958 num_ingredients: int 

2959 

2960 class ApplePie(Pie): 

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

2962 

2963 class PumpkinPie(Pie): 

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

2965 

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

2967 if isinstance(v, dict): 

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

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

2970 

2971 class ThanksgivingDinner(BaseModel): 

2972 dessert: Annotated[ 

2973 Union[ 

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

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

2976 ], 

2977 Discriminator(get_discriminator_value), 

2978 ] 

2979 

2980 apple_variation = ThanksgivingDinner.model_validate( 

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

2982 ) 

2983 print(repr(apple_variation)) 

2984 ''' 

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

2986 ''' 

2987 

2988 pumpkin_variation = ThanksgivingDinner.model_validate( 

2989 { 

2990 'dessert': { 

2991 'filling': 'pumpkin', 

2992 'time_to_cook': 40, 

2993 'num_ingredients': 6, 

2994 } 

2995 } 

2996 ) 

2997 print(repr(pumpkin_variation)) 

2998 ''' 

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

3000 ''' 

3001 ``` 

3002 

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

3004 

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

3006 """ 

3007 

3008 discriminator: str | Callable[[Any], Hashable] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

3010 

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

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

3013 """ 

3014 custom_error_type: str | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3015 """Type to use in [custom errors](../errors/errors.md#custom-errors) replacing the standard discriminated union 1bcdefghiajklmnopqGHIJKLrstuvwxy

3016 validation errors. 

3017 """ 

3018 custom_error_message: str | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3019 """Message to use in custom errors.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

3020 custom_error_context: dict[str, int | str | float] | None = None 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3021 """Context to use in custom errors.""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

3022 

3023 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3024 origin = _typing_extra.get_origin(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3025 if not origin or not _typing_extra.origin_is_union(origin): 3025 ↛ 3026line 3025 didn't jump to line 3026 because the condition on line 3025 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

3027 

3028 if isinstance(self.discriminator, str): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3029 from pydantic import Field 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3030 

3031 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3032 else: 

3033 original_schema = handler(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3034 return self._convert_schema(original_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3035 

3036 def _convert_schema(self, original_schema: core_schema.CoreSchema) -> core_schema.TaggedUnionSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3037 if original_schema['type'] != 'union': 3037 ↛ 3042line 3037 didn't jump to line 3042 because the condition on line 3037 was never true1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

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

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

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

3042 original_schema = core_schema.union_schema([original_schema]) 

3043 

3044 tagged_union_choices = {} 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3045 for choice in original_schema['choices']: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3046 tag = None 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3047 if isinstance(choice, tuple): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3048 choice, tag = choice 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3049 metadata = cast('CoreMetadata | None', choice.get('metadata')) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3050 if metadata is not None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3051 tag = metadata.get('pydantic_internal_union_tag_key') or tag 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3052 if tag is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3053 raise PydanticUserError( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

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

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

3056 ) 

3057 tagged_union_choices[tag] = choice 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3058 

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

3060 custom_error_type = self.custom_error_type 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3061 if custom_error_type is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3062 custom_error_type = original_schema.get('custom_error_type') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3063 

3064 custom_error_message = self.custom_error_message 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3065 if custom_error_message is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3066 custom_error_message = original_schema.get('custom_error_message') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3067 

3068 custom_error_context = self.custom_error_context 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3069 if custom_error_context is None: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3070 custom_error_context = original_schema.get('custom_error_context') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3071 

3072 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3073 return core_schema.tagged_union_schema( 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3074 tagged_union_choices, 

3075 self.discriminator, 

3076 custom_error_type=custom_error_type, 

3077 custom_error_message=custom_error_message, 

3078 custom_error_context=custom_error_context, 

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

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

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

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

3083 ) 

3084 

3085 

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

3087 

3088 

3089def _get_type_name(x: Any) -> str: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3090 type_ = type(x) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3091 if type_ in _JSON_TYPES: 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3092 return type_.__name__ 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3093 

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

3095 if isinstance(x, int): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3096 return 'int' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3097 if isinstance(x, float): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3098 return 'float' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3099 if isinstance(x, str): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3100 return 'str' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3101 if isinstance(x, list): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3102 return 'list' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3103 if isinstance(x, dict): 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3104 return 'dict' 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3105 

3106 # Fail by returning the type's actual name 

3107 return getattr(type_, '__name__', '<no type name>') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3108 

3109 

3110class _AllowAnyJson: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3111 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3112 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3113 python_schema = handler(source_type) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3114 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3115 

3116 

3117if TYPE_CHECKING: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3118 # This seems to only be necessary for mypy 

3119 JsonValue: TypeAlias = Union[ 

3120 list['JsonValue'], 

3121 dict[str, 'JsonValue'], 

3122 str, 

3123 bool, 

3124 int, 

3125 float, 

3126 None, 

3127 ] 

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

3129 

3130 It may be one of: 

3131 

3132 * `list['JsonValue']` 

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

3134 * `str` 

3135 * `bool` 

3136 * `int` 

3137 * `float` 

3138 * `None` 

3139 

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

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

3142 

3143 ```python 

3144 import json 

3145 

3146 from pydantic import BaseModel, JsonValue, ValidationError 

3147 

3148 class Model(BaseModel): 

3149 j: JsonValue 

3150 

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

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

3153 

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

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

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

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

3158 

3159 try: 

3160 Model.model_validate(invalid_json_data) 

3161 except ValidationError as e: 

3162 print(e) 

3163 ''' 

3164 1 validation error for Model 

3165 j.dict.a.dict.b 

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

3167 ''' 

3168 ``` 

3169 """ 

3170 

3171else: 

3172 JsonValue = TypeAliasType( 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3173 'JsonValue', 

3174 Annotated[ 

3175 Union[ 

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

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

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

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

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

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

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

3183 ], 

3184 Discriminator( 

3185 _get_type_name, 

3186 custom_error_type='invalid-json-value', 

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

3188 ), 

3189 _AllowAnyJson, 

3190 ], 

3191 ) 

3192 

3193 

3194class _OnErrorOmit: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3195 @classmethod 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3196 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

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

3199 # or as a standalone validator 

3200 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1zAbcdefghiBaCDjklmnopqEFrstuvwxy

3201 

3202 

3203OnErrorOmit = Annotated[T, _OnErrorOmit] 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3204""" 1bcdefghiajklmnopqGHIJKLrstuvwxy

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

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

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

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

3209""" 

3210 

3211 

3212@_dataclasses.dataclass 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

3213class FailFast(_fields.PydanticMetadata, BaseMetadata): 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy

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

3215 

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

3217 

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

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

3220 

3221 ```python 

3222 from typing import Annotated 

3223 

3224 from pydantic import BaseModel, FailFast, ValidationError 

3225 

3226 class Model(BaseModel): 

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

3228 

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

3230 try: 

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

3232 except ValidationError as e: 

3233 print(e) 

3234 ''' 

3235 1 validation error for Model 

3236 x.2 

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

3238 ''' 

3239 ``` 

3240 """ 

3241 

3242 fail_fast: bool = True 1zAbcdefghiBaCDjklmnopqMGHIJKLEFrstuvwxy