Coverage for pydantic/types.py: 97.87%

622 statements  

« prev     ^ index     » next       coverage.py v7.5.4, created at 2024-07-03 19:29 +0000

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

2 

3from __future__ import annotations as _annotations 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

4 

5import base64 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

6import dataclasses as _dataclasses 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

7import re 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

8from datetime import date, datetime 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

9from decimal import Decimal 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

10from enum import Enum 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

11from pathlib import Path 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

12from types import ModuleType 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

13from typing import ( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

14 TYPE_CHECKING, 

15 Any, 

16 Callable, 

17 ClassVar, 

18 Dict, 

19 FrozenSet, 

20 Generic, 

21 Hashable, 

22 Iterator, 

23 List, 

24 Pattern, 

25 Set, 

26 TypeVar, 

27 Union, 

28 cast, 

29 get_args, 

30 get_origin, 

31) 

32from uuid import UUID 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

33 

34import annotated_types 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

35from annotated_types import BaseMetadata, MaxLen, MinLen 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

36from pydantic_core import CoreSchema, PydanticCustomError, core_schema 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

37from typing_extensions import Annotated, Literal, Protocol, TypeAlias, TypeAliasType, deprecated 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

38 

39from ._internal import ( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

40 _core_utils, 

41 _fields, 

42 _internal_dataclass, 

43 _typing_extra, 

44 _utils, 

45 _validators, 

46) 

47from ._migration import getattr_migration 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

48from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

49from .errors import PydanticUserError 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

50from .json_schema import JsonSchemaValue 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

51from .warnings import PydanticDeprecatedSince20 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

52 

53__all__ = ( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

54 'Strict', 

55 'StrictStr', 

56 'conbytes', 

57 'conlist', 

58 'conset', 

59 'confrozenset', 

60 'constr', 

61 'ImportString', 

62 'conint', 

63 'PositiveInt', 

64 'NegativeInt', 

65 'NonNegativeInt', 

66 'NonPositiveInt', 

67 'confloat', 

68 'PositiveFloat', 

69 'NegativeFloat', 

70 'NonNegativeFloat', 

71 'NonPositiveFloat', 

72 'FiniteFloat', 

73 'condecimal', 

74 'UUID1', 

75 'UUID3', 

76 'UUID4', 

77 'UUID5', 

78 'FilePath', 

79 'DirectoryPath', 

80 'NewPath', 

81 'Json', 

82 'Secret', 

83 'SecretStr', 

84 'SecretBytes', 

85 'StrictBool', 

86 'StrictBytes', 

87 'StrictInt', 

88 'StrictFloat', 

89 'PaymentCardNumber', 

90 'ByteSize', 

91 'PastDate', 

92 'FutureDate', 

93 'PastDatetime', 

94 'FutureDatetime', 

95 'condate', 

96 'AwareDatetime', 

97 'NaiveDatetime', 

98 'AllowInfNan', 

99 'EncoderProtocol', 

100 'EncodedBytes', 

101 'EncodedStr', 

102 'Base64Encoder', 

103 'Base64Bytes', 

104 'Base64Str', 

105 'Base64UrlBytes', 

106 'Base64UrlStr', 

107 'GetPydanticSchema', 

108 'StringConstraints', 

109 'Tag', 

110 'Discriminator', 

111 'JsonValue', 

112 'OnErrorOmit', 

113 'FailFast', 

114) 

115 

116 

117T = TypeVar('T') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

118 

119 

120@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

121class Strict(_fields.PydanticMetadata, BaseMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

122 """Usage docs: https://docs.pydantic.dev/2.8/concepts/strict_mode/#strict-mode-with-annotated-strict 

123 

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

125 

126 Attributes: 

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

128 

129 Example: 

130 ```python 

131 from typing_extensions import Annotated 

132 

133 from pydantic.types import Strict 

134 

135 StrictBool = Annotated[bool, Strict()] 

136 ``` 

137 """ 

138 

139 strict: bool = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

140 

141 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

142 return hash(self.strict) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

143 

144 

145# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

146 

147StrictBool = Annotated[bool, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

148"""A boolean that must be either ``True`` or ``False``.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

149 

150# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

151 

152 

153def conint( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

154 *, 

155 strict: bool | None = None, 

156 gt: int | None = None, 

157 ge: int | None = None, 

158 lt: int | None = None, 

159 le: int | None = None, 

160 multiple_of: int | None = None, 

161) -> type[int]: 

162 """ 

163 !!! warning "Discouraged" 

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

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

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

167 

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

169 

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

171 

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

173 ```py 

174 from pydantic import BaseModel, conint 

175 

176 class Foo(BaseModel): 

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

178 ``` 

179 

180 === ":white_check_mark: Do this" 

181 ```py 

182 from typing_extensions import Annotated 

183 

184 from pydantic import BaseModel, Field 

185 

186 class Foo(BaseModel): 

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

188 ``` 

189 

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

191 

192 Args: 

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

194 gt: The value must be greater than this. 

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

196 lt: The value must be less than this. 

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

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

199 

200 Returns: 

201 The wrapped integer type. 

202 

203 ```py 

204 from pydantic import BaseModel, ValidationError, conint 

205 

206 class ConstrainedExample(BaseModel): 

207 constrained_int: conint(gt=1) 

208 

209 m = ConstrainedExample(constrained_int=2) 

210 print(repr(m)) 

211 #> ConstrainedExample(constrained_int=2) 

212 

213 try: 

214 ConstrainedExample(constrained_int=0) 

215 except ValidationError as e: 

216 print(e.errors()) 

217 ''' 

218 [ 

219 { 

220 'type': 'greater_than', 

221 'loc': ('constrained_int',), 

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

223 'input': 0, 

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

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

226 } 

227 ] 

228 ''' 

229 ``` 

230 

231 """ # noqa: D212 

232 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

233 int, 

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

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

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

237 ] 

238 

239 

240PositiveInt = Annotated[int, annotated_types.Gt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

241"""An integer that must be greater than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

242 

243```py 

244from pydantic import BaseModel, PositiveInt, ValidationError 

245 

246class Model(BaseModel): 

247 positive_int: PositiveInt 

248 

249m = Model(positive_int=1) 

250print(repr(m)) 

251#> Model(positive_int=1) 

252 

253try: 

254 Model(positive_int=-1) 

255except ValidationError as e: 

256 print(e.errors()) 

257 ''' 

258 [ 

259 { 

260 'type': 'greater_than', 

261 'loc': ('positive_int',), 

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

263 'input': -1, 

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

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

266 } 

267 ] 

268 ''' 

269``` 

270""" 

271NegativeInt = Annotated[int, annotated_types.Lt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

272"""An integer that must be less than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

273 

274```py 

275from pydantic import BaseModel, NegativeInt, ValidationError 

276 

277class Model(BaseModel): 

278 negative_int: NegativeInt 

279 

280m = Model(negative_int=-1) 

281print(repr(m)) 

282#> Model(negative_int=-1) 

283 

284try: 

285 Model(negative_int=1) 

286except ValidationError as e: 

287 print(e.errors()) 

288 ''' 

289 [ 

290 { 

291 'type': 'less_than', 

292 'loc': ('negative_int',), 

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

294 'input': 1, 

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

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

297 } 

298 ] 

299 ''' 

300``` 

301""" 

302NonPositiveInt = Annotated[int, annotated_types.Le(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

303"""An integer that must be less than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

304 

305```py 

306from pydantic import BaseModel, NonPositiveInt, ValidationError 

307 

308class Model(BaseModel): 

309 non_positive_int: NonPositiveInt 

310 

311m = Model(non_positive_int=0) 

312print(repr(m)) 

313#> Model(non_positive_int=0) 

314 

315try: 

316 Model(non_positive_int=1) 

317except ValidationError as e: 

318 print(e.errors()) 

319 ''' 

320 [ 

321 { 

322 'type': 'less_than_equal', 

323 'loc': ('non_positive_int',), 

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

325 'input': 1, 

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

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

328 } 

329 ] 

330 ''' 

331``` 

332""" 

333NonNegativeInt = Annotated[int, annotated_types.Ge(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

334"""An integer that must be greater than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

335 

336```py 

337from pydantic import BaseModel, NonNegativeInt, ValidationError 

338 

339class Model(BaseModel): 

340 non_negative_int: NonNegativeInt 

341 

342m = Model(non_negative_int=0) 

343print(repr(m)) 

344#> Model(non_negative_int=0) 

345 

346try: 

347 Model(non_negative_int=-1) 

348except ValidationError as e: 

349 print(e.errors()) 

350 ''' 

351 [ 

352 { 

353 'type': 'greater_than_equal', 

354 'loc': ('non_negative_int',), 

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

356 'input': -1, 

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

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

359 } 

360 ] 

361 ''' 

362``` 

363""" 

364StrictInt = Annotated[int, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

365"""An integer that must be validated in strict mode. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

366 

367```py 

368from pydantic import BaseModel, StrictInt, ValidationError 

369 

370class StrictIntModel(BaseModel): 

371 strict_int: StrictInt 

372 

373try: 

374 StrictIntModel(strict_int=3.14159) 

375except ValidationError as e: 

376 print(e) 

377 ''' 

378 1 validation error for StrictIntModel 

379 strict_int 

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

381 ''' 

382``` 

383""" 

384 

385# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

386 

387 

388@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

389class AllowInfNan(_fields.PydanticMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

391 

392 allow_inf_nan: bool = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

393 

394 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

395 return hash(self.allow_inf_nan) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

396 

397 

398def confloat( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

399 *, 

400 strict: bool | None = None, 

401 gt: float | None = None, 

402 ge: float | None = None, 

403 lt: float | None = None, 

404 le: float | None = None, 

405 multiple_of: float | None = None, 

406 allow_inf_nan: bool | None = None, 

407) -> type[float]: 

408 """ 

409 !!! warning "Discouraged" 

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

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

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

413 

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

415 

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

417 

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

419 ```py 

420 from pydantic import BaseModel, confloat 

421 

422 class Foo(BaseModel): 

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

424 ``` 

425 

426 === ":white_check_mark: Do this" 

427 ```py 

428 from typing_extensions import Annotated 

429 

430 from pydantic import BaseModel, Field 

431 

432 class Foo(BaseModel): 

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

434 ``` 

435 

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

437 

438 Args: 

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

440 gt: The value must be greater than this. 

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

442 lt: The value must be less than this. 

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

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

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

446 

447 Returns: 

448 The wrapped float type. 

449 

450 ```py 

451 from pydantic import BaseModel, ValidationError, confloat 

452 

453 class ConstrainedExample(BaseModel): 

454 constrained_float: confloat(gt=1.0) 

455 

456 m = ConstrainedExample(constrained_float=1.1) 

457 print(repr(m)) 

458 #> ConstrainedExample(constrained_float=1.1) 

459 

460 try: 

461 ConstrainedExample(constrained_float=0.9) 

462 except ValidationError as e: 

463 print(e.errors()) 

464 ''' 

465 [ 

466 { 

467 'type': 'greater_than', 

468 'loc': ('constrained_float',), 

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

470 'input': 0.9, 

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

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

473 } 

474 ] 

475 ''' 

476 ``` 

477 """ # noqa: D212 

478 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

479 float, 

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

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

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

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

484 ] 

485 

486 

487PositiveFloat = Annotated[float, annotated_types.Gt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

488"""A float that must be greater than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

489 

490```py 

491from pydantic import BaseModel, PositiveFloat, ValidationError 

492 

493class Model(BaseModel): 

494 positive_float: PositiveFloat 

495 

496m = Model(positive_float=1.0) 

497print(repr(m)) 

498#> Model(positive_float=1.0) 

499 

500try: 

501 Model(positive_float=-1.0) 

502except ValidationError as e: 

503 print(e.errors()) 

504 ''' 

505 [ 

506 { 

507 'type': 'greater_than', 

508 'loc': ('positive_float',), 

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

510 'input': -1.0, 

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

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

513 } 

514 ] 

515 ''' 

516``` 

517""" 

518NegativeFloat = Annotated[float, annotated_types.Lt(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

519"""A float that must be less than zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

520 

521```py 

522from pydantic import BaseModel, NegativeFloat, ValidationError 

523 

524class Model(BaseModel): 

525 negative_float: NegativeFloat 

526 

527m = Model(negative_float=-1.0) 

528print(repr(m)) 

529#> Model(negative_float=-1.0) 

530 

531try: 

532 Model(negative_float=1.0) 

533except ValidationError as e: 

534 print(e.errors()) 

535 ''' 

536 [ 

537 { 

538 'type': 'less_than', 

539 'loc': ('negative_float',), 

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

541 'input': 1.0, 

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

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

544 } 

545 ] 

546 ''' 

547``` 

548""" 

549NonPositiveFloat = Annotated[float, annotated_types.Le(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

550"""A float that must be less than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

551 

552```py 

553from pydantic import BaseModel, NonPositiveFloat, ValidationError 

554 

555class Model(BaseModel): 

556 non_positive_float: NonPositiveFloat 

557 

558m = Model(non_positive_float=0.0) 

559print(repr(m)) 

560#> Model(non_positive_float=0.0) 

561 

562try: 

563 Model(non_positive_float=1.0) 

564except ValidationError as e: 

565 print(e.errors()) 

566 ''' 

567 [ 

568 { 

569 'type': 'less_than_equal', 

570 'loc': ('non_positive_float',), 

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

572 'input': 1.0, 

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

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

575 } 

576 ] 

577 ''' 

578``` 

579""" 

580NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

581"""A float that must be greater than or equal to zero. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

582 

583```py 

584from pydantic import BaseModel, NonNegativeFloat, ValidationError 

585 

586class Model(BaseModel): 

587 non_negative_float: NonNegativeFloat 

588 

589m = Model(non_negative_float=0.0) 

590print(repr(m)) 

591#> Model(non_negative_float=0.0) 

592 

593try: 

594 Model(non_negative_float=-1.0) 

595except ValidationError as e: 

596 print(e.errors()) 

597 ''' 

598 [ 

599 { 

600 'type': 'greater_than_equal', 

601 'loc': ('non_negative_float',), 

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

603 'input': -1.0, 

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

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

606 } 

607 ] 

608 ''' 

609``` 

610""" 

611StrictFloat = Annotated[float, Strict(True)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

612"""A float that must be validated in strict mode. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

613 

614```py 

615from pydantic import BaseModel, StrictFloat, ValidationError 

616 

617class StrictFloatModel(BaseModel): 

618 strict_float: StrictFloat 

619 

620try: 

621 StrictFloatModel(strict_float='1.0') 

622except ValidationError as e: 

623 print(e) 

624 ''' 

625 1 validation error for StrictFloatModel 

626 strict_float 

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

628 ''' 

629``` 

630""" 

631FiniteFloat = Annotated[float, AllowInfNan(False)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

633 

634```py 

635from pydantic import BaseModel, FiniteFloat 

636 

637class Model(BaseModel): 

638 finite: FiniteFloat 

639 

640m = Model(finite=1.0) 

641print(m) 

642#> finite=1.0 

643``` 

644""" 

645 

646 

647# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

648 

649 

650def conbytes( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

651 *, 

652 min_length: int | None = None, 

653 max_length: int | None = None, 

654 strict: bool | None = None, 

655) -> type[bytes]: 

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

657 

658 Args: 

659 min_length: The minimum length of the bytes. 

660 max_length: The maximum length of the bytes. 

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

662 

663 Returns: 

664 The wrapped bytes type. 

665 """ 

666 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

667 bytes, 

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

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

670 ] 

671 

672 

673StrictBytes = Annotated[bytes, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

674"""A bytes that must be validated in strict mode.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

675 

676 

677# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

678 

679 

680@_dataclasses.dataclass(frozen=True) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

681class StringConstraints(annotated_types.GroupedMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

682 """Usage docs: https://docs.pydantic.dev/2.8/concepts/fields/#string-constraints 

683 

684 Apply constraints to `str` types. 

685 

686 Attributes: 

687 strip_whitespace: Whether to remove leading and trailing whitespace. 

688 to_upper: Whether to convert the string to uppercase. 

689 to_lower: Whether to convert the string to lowercase. 

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

691 min_length: The minimum length of the string. 

692 max_length: The maximum length of the string. 

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

694 """ 

695 

696 strip_whitespace: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

697 to_upper: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

698 to_lower: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

699 strict: bool | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

700 min_length: int | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

701 max_length: int | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

702 pattern: str | Pattern[str] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

703 

704 def __iter__(self) -> Iterator[BaseMetadata]: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

705 if self.min_length is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

706 yield MinLen(self.min_length) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

707 if self.max_length is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

708 yield MaxLen(self.max_length) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

709 if self.strict is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

710 yield Strict(self.strict) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

711 if ( 1zABCDaEFGH

712 self.strip_whitespace is not None 

713 or self.pattern is not None 

714 or self.to_lower is not None 

715 or self.to_upper is not None 

716 ): 

717 yield _fields.pydantic_general_metadata( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

718 strip_whitespace=self.strip_whitespace, 

719 to_upper=self.to_upper, 

720 to_lower=self.to_lower, 

721 pattern=self.pattern, 

722 ) 

723 

724 

725def constr( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

726 *, 

727 strip_whitespace: bool | None = None, 

728 to_upper: bool | None = None, 

729 to_lower: bool | None = None, 

730 strict: bool | None = None, 

731 min_length: int | None = None, 

732 max_length: int | None = None, 

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

734) -> type[str]: 

735 """ 

736 !!! warning "Discouraged" 

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

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

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

740 

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

742 

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

744 

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

746 ```py 

747 from pydantic import BaseModel, constr 

748 

749 class Foo(BaseModel): 

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

751 ``` 

752 

753 === ":white_check_mark: Do this" 

754 ```py 

755 from typing_extensions import Annotated 

756 

757 from pydantic import BaseModel, StringConstraints 

758 

759 class Foo(BaseModel): 

760 bar: Annotated[str, StringConstraints(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$')] 

761 ``` 

762 

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

764 

765 ```py 

766 from pydantic import BaseModel, constr 

767 

768 class Foo(BaseModel): 

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

770 

771 

772 foo = Foo(bar=' hello ') 

773 print(foo) 

774 #> bar='HELLO' 

775 ``` 

776 

777 Args: 

778 strip_whitespace: Whether to remove leading and trailing whitespace. 

779 to_upper: Whether to turn all characters to uppercase. 

780 to_lower: Whether to turn all characters to lowercase. 

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

782 min_length: The minimum length of the string. 

783 max_length: The maximum length of the string. 

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

785 

786 Returns: 

787 The wrapped string type. 

788 """ # noqa: D212 

789 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

790 str, 

791 StringConstraints( 

792 strip_whitespace=strip_whitespace, 

793 to_upper=to_upper, 

794 to_lower=to_lower, 

795 strict=strict, 

796 min_length=min_length, 

797 max_length=max_length, 

798 pattern=pattern, 

799 ), 

800 ] 

801 

802 

803StrictStr = Annotated[str, Strict()] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

804"""A string that must be validated in strict mode.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

805 

806 

807# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

808HashableItemType = TypeVar('HashableItemType', bound=Hashable) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

809 

810 

811def conset( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

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

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

815 

816 Args: 

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

818 min_length: The minimum length of the set. 

819 max_length: The maximum length of the set. 

820 

821 Returns: 

822 The wrapped set type. 

823 """ 

824 return Annotated[Set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

825 

826 

827def confrozenset( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

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

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

831 

832 Args: 

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

834 min_length: The minimum length of the frozenset. 

835 max_length: The maximum length of the frozenset. 

836 

837 Returns: 

838 The wrapped frozenset type. 

839 """ 

840 return Annotated[FrozenSet[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

841 

842 

843AnyItemType = TypeVar('AnyItemType') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

844 

845 

846def conlist( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

847 item_type: type[AnyItemType], 

848 *, 

849 min_length: int | None = None, 

850 max_length: int | None = None, 

851 unique_items: bool | None = None, 

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

853 """A wrapper around typing.List that adds validation. 

854 

855 Args: 

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

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

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

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

860 !!! warning Deprecated 

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

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

863 

864 Returns: 

865 The wrapped list type. 

866 """ 

867 if unique_items is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

868 raise PydanticUserError( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

869 ( 

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

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

872 ), 

873 code='removed-kwargs', 

874 ) 

875 return Annotated[List[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

876 

877 

878# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

879 

880AnyType = TypeVar('AnyType') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

881if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

882 ImportString = Annotated[AnyType, ...] 1a

883else: 

884 

885 class ImportString: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

886 """A type that can be used to import a type from a string. 

887 

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

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

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

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

892 

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

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

895 

896 **Good behavior:** 

897 ```py 

898 from math import cos 

899 

900 from pydantic import BaseModel, Field, ImportString, ValidationError 

901 

902 

903 class ImportThings(BaseModel): 

904 obj: ImportString 

905 

906 

907 # A string value will cause an automatic import 

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

909 

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

911 cos_of_0 = my_cos.obj(0) 

912 assert cos_of_0 == 1 

913 

914 

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

916 try: 

917 ImportThings(obj='foo.bar') 

918 except ValidationError as e: 

919 print(e) 

920 ''' 

921 1 validation error for ImportThings 

922 obj 

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

924 ''' 

925 

926 

927 # Actual python objects can be assigned as well 

928 my_cos = ImportThings(obj=cos) 

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

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

931 assert my_cos == my_cos_2 == my_cos_3 

932 

933 

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

935 class ImportThingsDefaultPyObj(BaseModel): 

936 obj: ImportString = math.cos 

937 

938 

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

940 class ImportThingsDefaultString(BaseModel): 

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

942 

943 

944 my_cos_default1 = ImportThingsDefaultPyObj() 

945 my_cos_default2 = ImportThingsDefaultString() 

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

947 

948 

949 # note: this will not work! 

950 class ImportThingsMissingValidateDefault(BaseModel): 

951 obj: ImportString = 'math.cos' 

952 

953 my_cos_default3 = ImportThingsMissingValidateDefault() 

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

955 ``` 

956 

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

958 

959 ```py 

960 from pydantic import BaseModel, ImportString 

961 

962 

963 class ImportThings(BaseModel): 

964 obj: ImportString 

965 

966 

967 # Create an instance 

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

969 print(m) 

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

971 print(m.model_dump_json()) 

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

973 ``` 

974 """ 

975 

976 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

977 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

978 return Annotated[item, cls()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

979 

980 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

981 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

983 ) -> core_schema.CoreSchema: 

984 serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

985 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

987 return core_schema.no_info_plain_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

988 function=_validators.import_string, serialization=serializer 

989 ) 

990 else: 

991 return core_schema.no_info_before_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

993 ) 

994 

995 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

996 def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

997 return handler(core_schema.str_schema()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

998 

999 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1000 def _serialize(v: Any) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1001 if isinstance(v, ModuleType): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1002 return v.__name__ 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1003 elif hasattr(v, '__module__') and hasattr(v, '__name__'): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1004 return f'{v.__module__}.{v.__name__}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1005 else: 

1006 return v 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1007 

1008 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1009 return 'ImportString' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1010 

1011 

1012# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1013 

1014 

1015def condecimal( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1016 *, 

1017 strict: bool | None = None, 

1018 gt: int | Decimal | None = None, 

1019 ge: int | Decimal | None = None, 

1020 lt: int | Decimal | None = None, 

1021 le: int | Decimal | None = None, 

1022 multiple_of: int | Decimal | None = None, 

1023 max_digits: int | None = None, 

1024 decimal_places: int | None = None, 

1025 allow_inf_nan: bool | None = None, 

1026) -> type[Decimal]: 

1027 """ 

1028 !!! warning "Discouraged" 

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

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

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

1032 

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

1034 

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

1036 

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

1038 ```py 

1039 from pydantic import BaseModel, condecimal 

1040 

1041 class Foo(BaseModel): 

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

1043 ``` 

1044 

1045 === ":white_check_mark: Do this" 

1046 ```py 

1047 from decimal import Decimal 

1048 

1049 from typing_extensions import Annotated 

1050 

1051 from pydantic import BaseModel, Field 

1052 

1053 class Foo(BaseModel): 

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

1055 ``` 

1056 

1057 A wrapper around Decimal that adds validation. 

1058 

1059 Args: 

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

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

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

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

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

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

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

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

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

1069 

1070 ```py 

1071 from decimal import Decimal 

1072 

1073 from pydantic import BaseModel, ValidationError, condecimal 

1074 

1075 class ConstrainedExample(BaseModel): 

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

1077 

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

1079 print(repr(m)) 

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

1081 

1082 try: 

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

1084 except ValidationError as e: 

1085 print(e.errors()) 

1086 ''' 

1087 [ 

1088 { 

1089 'type': 'greater_than', 

1090 'loc': ('constrained_decimal',), 

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

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

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

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

1095 } 

1096 ] 

1097 ''' 

1098 ``` 

1099 """ # noqa: D212 

1100 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1101 Decimal, 

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

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

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

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

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

1107 ] 

1108 

1109 

1110# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1111 

1112 

1113@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1114class UuidVersion: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1116 

1117 uuid_version: Literal[1, 3, 4, 5] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1118 

1119 def __get_pydantic_json_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1121 ) -> JsonSchemaValue: 

1122 field_schema = handler(core_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

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

1125 return field_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1126 

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

1128 if isinstance(self, source): 1128 ↛ 1130line 1128 didn't jump to line 1130 because the condition on line 1128 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1129 # used directly as a type 

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

1131 else: 

1132 # update existing schema with self.uuid_version 

1133 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1134 _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1135 schema['version'] = self.uuid_version # type: ignore 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1136 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1137 

1138 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1139 return hash(type(self.uuid_version)) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1140 

1141 

1142UUID1 = Annotated[UUID, UuidVersion(1)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1144 

1145```py 

1146import uuid 

1147 

1148from pydantic import UUID1, BaseModel 

1149 

1150class Model(BaseModel): 

1151 uuid1: UUID1 

1152 

1153Model(uuid1=uuid.uuid1()) 

1154``` 

1155""" 

1156UUID3 = Annotated[UUID, UuidVersion(3)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1158 

1159```py 

1160import uuid 

1161 

1162from pydantic import UUID3, BaseModel 

1163 

1164class Model(BaseModel): 

1165 uuid3: UUID3 

1166 

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

1168``` 

1169""" 

1170UUID4 = Annotated[UUID, UuidVersion(4)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1172 

1173```py 

1174import uuid 

1175 

1176from pydantic import UUID4, BaseModel 

1177 

1178class Model(BaseModel): 

1179 uuid4: UUID4 

1180 

1181Model(uuid4=uuid.uuid4()) 

1182``` 

1183""" 

1184UUID5 = Annotated[UUID, UuidVersion(5)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1186 

1187```py 

1188import uuid 

1189 

1190from pydantic import UUID5, BaseModel 

1191 

1192class Model(BaseModel): 

1193 uuid5: UUID5 

1194 

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

1196``` 

1197""" 

1198 

1199 

1200# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1201 

1202 

1203@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1204class PathType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1205 path_type: Literal['file', 'dir', 'new'] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1206 

1207 def __get_pydantic_json_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1209 ) -> JsonSchemaValue: 

1210 field_schema = handler(core_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1211 format_conversion = {'file': 'file-path', 'dir': 'directory-path'} 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1213 return field_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1214 

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

1216 function_lookup = { 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

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

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

1220 } 

1221 

1222 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1223 function_lookup[self.path_type], 

1224 handler(source), 

1225 ) 

1226 

1227 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1228 def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1229 if path.is_file(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1230 return path 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1231 else: 

1232 raise PydanticCustomError('path_not_file', 'Path does not point to a file') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1233 

1234 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1235 def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1236 if path.is_dir(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1237 return path 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1238 else: 

1239 raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1240 

1241 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1242 def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1243 if path.exists(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1244 raise PydanticCustomError('path_exists', 'Path already exists') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1245 elif not path.parent.exists(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1246 raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1247 else: 

1248 return path 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1249 

1250 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1251 return hash(type(self.path_type)) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1252 

1253 

1254FilePath = Annotated[Path, PathType('file')] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1255"""A path that must point to a file. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

1256 

1257```py 

1258from pathlib import Path 

1259 

1260from pydantic import BaseModel, FilePath, ValidationError 

1261 

1262class Model(BaseModel): 

1263 f: FilePath 

1264 

1265path = Path('text.txt') 

1266path.touch() 

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

1268print(m.model_dump()) 

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

1270path.unlink() 

1271 

1272path = Path('directory') 

1273path.mkdir(exist_ok=True) 

1274try: 

1275 Model(f='directory') # directory 

1276except ValidationError as e: 

1277 print(e) 

1278 ''' 

1279 1 validation error for Model 

1280 f 

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

1282 ''' 

1283path.rmdir() 

1284 

1285try: 

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

1287except ValidationError as e: 

1288 print(e) 

1289 ''' 

1290 1 validation error for Model 

1291 f 

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

1293 ''' 

1294``` 

1295""" 

1296DirectoryPath = Annotated[Path, PathType('dir')] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1297"""A path that must point to a directory. 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

1298 

1299```py 

1300from pathlib import Path 

1301 

1302from pydantic import BaseModel, DirectoryPath, ValidationError 

1303 

1304class Model(BaseModel): 

1305 f: DirectoryPath 

1306 

1307path = Path('directory/') 

1308path.mkdir() 

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

1310print(m.model_dump()) 

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

1312path.rmdir() 

1313 

1314path = Path('file.txt') 

1315path.touch() 

1316try: 

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

1318except ValidationError as e: 

1319 print(e) 

1320 ''' 

1321 1 validation error for Model 

1322 f 

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

1324 ''' 

1325path.unlink() 

1326 

1327try: 

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

1329except ValidationError as e: 

1330 print(e) 

1331 ''' 

1332 1 validation error for Model 

1333 f 

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

1335 ''' 

1336``` 

1337""" 

1338NewPath = Annotated[Path, PathType('new')] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1340 

1341 

1342# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1343 

1344if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1346 Json = Annotated[AnyType, ...] 

1347 

1348else: 

1349 

1350 class Json: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1352 

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

1354 validating the loaded data into the parametrized type: 

1355 

1356 ```py 

1357 from typing import Any, List 

1358 

1359 from pydantic import BaseModel, Json, ValidationError 

1360 

1361 

1362 class AnyJsonModel(BaseModel): 

1363 json_obj: Json[Any] 

1364 

1365 

1366 class ConstrainedJsonModel(BaseModel): 

1367 json_obj: Json[List[int]] 

1368 

1369 

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

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

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

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

1374 

1375 try: 

1376 ConstrainedJsonModel(json_obj=12) 

1377 except ValidationError as e: 

1378 print(e) 

1379 ''' 

1380 1 validation error for ConstrainedJsonModel 

1381 json_obj 

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

1383 ''' 

1384 

1385 try: 

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

1387 except ValidationError as e: 

1388 print(e) 

1389 ''' 

1390 1 validation error for ConstrainedJsonModel 

1391 json_obj 

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

1393 ''' 

1394 

1395 try: 

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

1397 except ValidationError as e: 

1398 print(e) 

1399 ''' 

1400 2 validation errors for ConstrainedJsonModel 

1401 json_obj.0 

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

1403 json_obj.1 

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

1405 ''' 

1406 ``` 

1407 

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

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

1410 

1411 ```py 

1412 from typing import List 

1413 

1414 from pydantic import BaseModel, Json 

1415 

1416 

1417 class ConstrainedJsonModel(BaseModel): 

1418 json_obj: Json[List[int]] 

1419 

1420 

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

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

1423 print( 

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

1425 ) 

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

1427 ``` 

1428 """ 

1429 

1430 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1431 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1432 return Annotated[item, cls()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1433 

1434 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1436 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1437 return core_schema.json_schema(None) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1438 else: 

1439 return core_schema.json_schema(handler(source)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1440 

1441 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1442 return 'Json' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1443 

1444 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1445 return hash(type(self)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1446 

1447 def __eq__(self, other: Any) -> bool: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1448 return type(other) == type(self) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1449 

1450 

1451# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1452 

1453SecretType = TypeVar('SecretType') 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1454 

1455 

1456class _SecretBase(Generic[SecretType]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1457 def __init__(self, secret_value: SecretType) -> None: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1458 self._secret_value: SecretType = secret_value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1459 

1460 def get_secret_value(self) -> SecretType: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1461 """Get the secret value. 

1462 

1463 Returns: 

1464 The secret value. 

1465 """ 

1466 return self._secret_value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1467 

1468 def __eq__(self, other: Any) -> bool: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1469 return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1470 

1471 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1472 return hash(self.get_secret_value()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1473 

1474 def __str__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1475 return str(self._display()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1476 

1477 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1478 return f'{self.__class__.__name__}({self._display()!r})' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1479 

1480 def _display(self) -> str | bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1481 raise NotImplementedError 

1482 

1483 

1484class Secret(_SecretBase[SecretType]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1486 

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

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

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

1490 

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

1492 

1493 ```py 

1494 from pydantic import BaseModel, Secret 

1495 

1496 SecretBool = Secret[bool] 

1497 

1498 class Model(BaseModel): 

1499 secret_bool: SecretBool 

1500 

1501 m = Model(secret_bool=True) 

1502 print(m.model_dump()) 

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

1504 

1505 print(m.model_dump_json()) 

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

1507 

1508 print(m.secret_bool.get_secret_value()) 

1509 #> True 

1510 ``` 

1511 

1512 2. Subclassing from parametrized `Secret`: 

1513 

1514 ```py 

1515 from datetime import date 

1516 

1517 from pydantic import BaseModel, Secret 

1518 

1519 class SecretDate(Secret[date]): 

1520 def _display(self) -> str: 

1521 return '****/**/**' 

1522 

1523 class Model(BaseModel): 

1524 secret_date: SecretDate 

1525 

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

1527 print(m.model_dump()) 

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

1529 

1530 print(m.model_dump_json()) 

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

1532 

1533 print(m.secret_date.get_secret_value()) 

1534 #> 2022-01-01 

1535 ``` 

1536 

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

1538 """ 

1539 

1540 def _display(self) -> str | bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1541 return '**********' if self.get_secret_value() else '' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1542 

1543 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1545 inner_type = None 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1547 origin_type = get_origin(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1548 if origin_type is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1549 inner_type = get_args(source)[0] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1551 else: 

1552 bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1553 for base in bases: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1554 if get_origin(base) is Secret: 1554 ↛ 1553line 1554 didn't jump to line 1553 because the condition on line 1554 was always true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1555 inner_type = get_args(base)[0] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1556 if bases == [] or inner_type is None: 1556 ↛ 1557line 1556 didn't jump to line 1557 because the condition on line 1556 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1557 raise TypeError( 

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

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

1560 ) 

1561 

1562 inner_schema = handler.generate_schema(inner_type) # type: ignore 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1563 

1564 def validate_secret_value(value, handler) -> Secret[SecretType]: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1565 if isinstance(value, Secret): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1566 value = value.get_secret_value() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1567 validated_inner = handler(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1568 return cls(validated_inner) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1569 

1570 def serialize(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1571 if info.mode == 'json': 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1572 return str(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1573 else: 

1574 return value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1575 

1576 return core_schema.json_or_python_schema( 1576 ↛ exitline 1576 didn't jump to the function exit1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1577 python_schema=core_schema.no_info_wrap_validator_function( 

1578 validate_secret_value, 

1579 inner_schema, 

1580 ), 

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

1582 serialization=core_schema.plain_serializer_function_ser_schema( 

1583 serialize, 

1584 info_arg=True, 

1585 when_used='always', 

1586 ), 

1587 ) 

1588 

1589 

1590def _secret_display(value: SecretType) -> str: # type: ignore 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1591 return '**********' if value else '' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1592 

1593 

1594class _SecretField(_SecretBase[SecretType]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1595 _inner_schema: ClassVar[CoreSchema] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1596 _error_kind: ClassVar[str] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1597 

1598 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1600 def serialize( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1602 ) -> str | _SecretField[SecretType]: 

1603 if info.mode == 'json': 1603 ↛ 1608line 1603 didn't jump to line 1608 because the condition on line 1603 was always true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1605 # hence we just use `secret_display` 

1606 return _secret_display(value.get_secret_value()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1607 else: 

1608 return value 

1609 

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

1611 json_schema = handler(cls._inner_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1612 _utils.update_not_none( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1613 json_schema, 

1614 type='string', 

1615 writeOnly=True, 

1616 format='password', 

1617 ) 

1618 return json_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1619 

1620 json_schema = core_schema.no_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1621 source, # construct the type 

1622 cls._inner_schema, 

1623 ) 

1624 

1625 def get_secret_schema(strict: bool) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1626 return core_schema.json_or_python_schema( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1627 python_schema=core_schema.union_schema( 

1628 [ 

1629 core_schema.is_instance_schema(source), 

1630 json_schema, 

1631 ], 

1632 custom_error_type=cls._error_kind, 

1633 strict=strict, 

1634 ), 

1635 json_schema=json_schema, 

1636 serialization=core_schema.plain_serializer_function_ser_schema( 

1637 serialize, 

1638 info_arg=True, 

1639 return_schema=core_schema.str_schema(), 

1640 when_used='json', 

1641 ), 

1642 ) 

1643 

1644 return core_schema.lax_or_strict_schema( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1645 lax_schema=get_secret_schema(strict=False), 

1646 strict_schema=get_secret_schema(strict=True), 

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

1648 ) 

1649 

1650 

1651class SecretStr(_SecretField[str]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1653 

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

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

1656 

1657 ```py 

1658 from pydantic import BaseModel, SecretStr 

1659 

1660 class User(BaseModel): 

1661 username: str 

1662 password: SecretStr 

1663 

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

1665 

1666 print(user) 

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

1668 print(user.password.get_secret_value()) 

1669 #> password1 

1670 print((SecretStr('password'), SecretStr(''))) 

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

1672 ``` 

1673 """ 

1674 

1675 _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1676 _error_kind: ClassVar[str] = 'string_type' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1677 

1678 def __len__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1679 return len(self._secret_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1680 

1681 def _display(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1682 return _secret_display(self._secret_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1683 

1684 

1685class SecretBytes(_SecretField[bytes]): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1687 

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

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

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

1691 

1692 ```py 

1693 from pydantic import BaseModel, SecretBytes 

1694 

1695 class User(BaseModel): 

1696 username: str 

1697 password: SecretBytes 

1698 

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

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

1701 print(user.password.get_secret_value()) 

1702 #> b'password1' 

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

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

1705 ``` 

1706 """ 

1707 

1708 _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1709 _error_kind: ClassVar[str] = 'bytes_type' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1710 

1711 def __len__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1712 return len(self._secret_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1713 

1714 def _display(self) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1715 return _secret_display(self._secret_value).encode() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1716 

1717 

1718# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1719 

1720 

1721class PaymentCardBrand(str, Enum): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1722 amex = 'American Express' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1723 mastercard = 'Mastercard' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1724 visa = 'Visa' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1725 other = 'other' 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1726 

1727 def __str__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1728 return self.value 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1729 

1730 

1731@deprecated( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

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

1734 category=PydanticDeprecatedSince20, 

1735) 

1736class PaymentCardNumber(str): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1738 

1739 strip_whitespace: ClassVar[bool] = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1740 min_length: ClassVar[int] = 12 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1741 max_length: ClassVar[int] = 19 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1742 bin: str 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1743 last4: str 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1744 brand: PaymentCardBrand 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1745 

1746 def __init__(self, card_number: str): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1747 self.validate_digits(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1748 

1749 card_number = self.validate_luhn_check_digit(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1750 

1751 self.bin = card_number[:6] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1752 self.last4 = card_number[-4:] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1753 self.brand = self.validate_brand(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1754 

1755 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1757 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1758 cls.validate, 

1759 core_schema.str_schema( 

1760 min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace 

1761 ), 

1762 ) 

1763 

1764 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

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

1767 return cls(input_value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1768 

1769 @property 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1770 def masked(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1772 

1773 Returns: 

1774 A masked card number string. 

1775 """ 

1776 num_masked = len(self) - 10 # len(bin) + len(last4) == 10 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1777 return f'{self.bin}{"*" * num_masked}{self.last4}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1778 

1779 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1780 def validate_digits(cls, card_number: str) -> None: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1782 if not card_number.isdigit(): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1783 raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1784 

1785 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1786 def validate_luhn_check_digit(cls, card_number: str) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1788 sum_ = int(card_number[-1]) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1789 length = len(card_number) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1790 parity = length % 2 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1791 for i in range(length - 1): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1792 digit = int(card_number[i]) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1793 if i % 2 == parity: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1794 digit *= 2 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1795 if digit > 9: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1796 digit -= 9 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1797 sum_ += digit 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1798 valid = sum_ % 10 == 0 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1799 if not valid: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1800 raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1801 return card_number 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1802 

1803 @staticmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1804 def validate_brand(card_number: str) -> PaymentCardBrand: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

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

1807 """ 

1808 if card_number[0] == '4': 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1809 brand = PaymentCardBrand.visa 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1810 elif 51 <= int(card_number[:2]) <= 55: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1811 brand = PaymentCardBrand.mastercard 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1812 elif card_number[:2] in {'34', '37'}: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1813 brand = PaymentCardBrand.amex 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1814 else: 

1815 brand = PaymentCardBrand.other 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1816 

1817 required_length: None | int | str = None 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1818 if brand in PaymentCardBrand.mastercard: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1819 required_length = 16 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1820 valid = len(card_number) == required_length 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1821 elif brand == PaymentCardBrand.visa: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1822 required_length = '13, 16 or 19' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1823 valid = len(card_number) in {13, 16, 19} 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1824 elif brand == PaymentCardBrand.amex: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1825 required_length = 15 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1826 valid = len(card_number) == required_length 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1827 else: 

1828 valid = True 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1829 

1830 if not valid: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1831 raise PydanticCustomError( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1832 'payment_card_number_brand', 

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

1834 {'brand': brand, 'required_length': required_length}, 

1835 ) 

1836 return brand 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1837 

1838 

1839# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

1840 

1841 

1842class ByteSize(int): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1844 

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

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

1847 

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

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

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

1851 

1852 !!! info 

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

1854 

1855 ```py 

1856 from pydantic import BaseModel, ByteSize 

1857 

1858 class MyModel(BaseModel): 

1859 size: ByteSize 

1860 

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

1862 #> 52000 

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

1864 #> 3072000 

1865 

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

1867 print(m.size.human_readable()) 

1868 #> 44.4PiB 

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

1870 #> 50.0PB 

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

1872 #> 44.4 PiB 

1873 

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

1875 #> 45474.73508864641 

1876 ``` 

1877 """ 

1878 

1879 byte_sizes = { 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1880 'b': 1, 

1881 'kb': 10**3, 

1882 'mb': 10**6, 

1883 'gb': 10**9, 

1884 'tb': 10**12, 

1885 'pb': 10**15, 

1886 'eb': 10**18, 

1887 'kib': 2**10, 

1888 'mib': 2**20, 

1889 'gib': 2**30, 

1890 'tib': 2**40, 

1891 'pib': 2**50, 

1892 'eib': 2**60, 

1893 'bit': 1 / 8, 

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

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

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

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

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

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

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

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

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

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

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

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

1906 } 

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

1908 

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

1910 byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

1911 

1912 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1914 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1915 function=cls._validate, 

1916 schema=core_schema.union_schema( 

1917 [ 

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

1919 core_schema.int_schema(ge=0), 

1920 ], 

1921 custom_error_type='byte_size', 

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

1923 ), 

1924 serialization=core_schema.plain_serializer_function_ser_schema( 

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

1926 ), 

1927 ) 

1928 

1929 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1931 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1932 return cls(int(input_value)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1933 except ValueError: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1934 pass 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1935 

1936 str_match = cls.byte_string_re.match(str(input_value)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1937 if str_match is None: 1937 ↛ 1938line 1937 didn't jump to line 1938 because the condition on line 1937 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1939 

1940 scalar, unit = str_match.groups() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1941 if unit is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1942 unit = 'b' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1943 

1944 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1945 unit_mult = cls.byte_sizes[unit.lower()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1946 except KeyError: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1948 

1949 return cls(int(float(scalar) * unit_mult)) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1950 

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

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

1953 

1954 Args: 

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

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

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

1958 

1959 Returns: 

1960 A human readable string representation of the byte size. 

1961 """ 

1962 if decimal: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1963 divisor = 1000 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1964 units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1965 final_unit = 'EB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1966 else: 

1967 divisor = 1024 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1968 units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1969 final_unit = 'EiB' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1970 

1971 num = float(self) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1972 for unit in units: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1973 if abs(num) < divisor: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1974 if unit == 'B': 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1975 return f'{num:0.0f}{separator}{unit}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1976 else: 

1977 return f'{num:0.1f}{separator}{unit}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1978 num /= divisor 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1979 

1980 return f'{num:0.1f}{separator}{final_unit}' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1981 

1982 def to(self, unit: str) -> float: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

1984 

1985 Args: 

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

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

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

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

1990 

1991 Returns: 

1992 The byte size in the new unit. 

1993 """ 

1994 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1995 unit_div = self.byte_sizes[unit.lower()] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

1996 except KeyError: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

1998 

1999 return self / unit_div 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2000 

2001 

2002# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2003 

2004 

2005def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2006 if annotated_type != expected_type: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2007 raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid_annotated_type') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2008 

2009 

2010if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2011 PastDate = Annotated[date, ...] 

2012 FutureDate = Annotated[date, ...] 

2013else: 

2014 

2015 class PastDate: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2016 """A date in the past.""" 

2017 

2018 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2019 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2021 ) -> core_schema.CoreSchema: 

2022 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2023 # used directly as a type 

2024 return core_schema.date_schema(now_op='past') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2025 else: 

2026 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2027 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2028 schema['now_op'] = 'past' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2029 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2030 

2031 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2032 return 'PastDate' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2033 

2034 class FutureDate: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2035 """A date in the future.""" 

2036 

2037 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2038 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2040 ) -> core_schema.CoreSchema: 

2041 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2042 # used directly as a type 

2043 return core_schema.date_schema(now_op='future') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2044 else: 

2045 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2046 _check_annotated_type(schema['type'], 'date', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2047 schema['now_op'] = 'future' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2048 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2049 

2050 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2051 return 'FutureDate' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2052 

2053 

2054def condate( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2055 *, 

2056 strict: bool | None = None, 

2057 gt: date | None = None, 

2058 ge: date | None = None, 

2059 lt: date | None = None, 

2060 le: date | None = None, 

2061) -> type[date]: 

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

2063 

2064 Args: 

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

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

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

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

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

2070 

2071 Returns: 

2072 A date type with the specified constraints. 

2073 """ 

2074 return Annotated[ # pyright: ignore[reportReturnType] 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2075 date, 

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

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

2078 ] 

2079 

2080 

2081# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2082 

2083if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2084 AwareDatetime = Annotated[datetime, ...] 

2085 NaiveDatetime = Annotated[datetime, ...] 

2086 PastDatetime = Annotated[datetime, ...] 

2087 FutureDatetime = Annotated[datetime, ...] 

2088 

2089else: 

2090 

2091 class AwareDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2093 

2094 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2095 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2097 ) -> core_schema.CoreSchema: 

2098 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2099 # used directly as a type 

2100 return core_schema.datetime_schema(tz_constraint='aware') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2101 else: 

2102 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2103 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2104 schema['tz_constraint'] = 'aware' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2105 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2106 

2107 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2108 return 'AwareDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2109 

2110 class NaiveDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2112 

2113 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2114 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2116 ) -> core_schema.CoreSchema: 

2117 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2118 # used directly as a type 

2119 return core_schema.datetime_schema(tz_constraint='naive') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2120 else: 

2121 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2122 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2123 schema['tz_constraint'] = 'naive' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2124 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2125 

2126 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2127 return 'NaiveDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2128 

2129 class PastDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2131 

2132 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2133 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2135 ) -> core_schema.CoreSchema: 

2136 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2137 # used directly as a type 

2138 return core_schema.datetime_schema(now_op='past') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2139 else: 

2140 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2141 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2142 schema['now_op'] = 'past' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2143 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2144 

2145 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2146 return 'PastDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2147 

2148 class FutureDatetime: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2150 

2151 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2152 def __get_pydantic_core_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2154 ) -> core_schema.CoreSchema: 

2155 if cls is source: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2156 # used directly as a type 

2157 return core_schema.datetime_schema(now_op='future') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2158 else: 

2159 schema = handler(source) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2160 _check_annotated_type(schema['type'], 'datetime', cls.__name__) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2161 schema['now_op'] = 'future' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2162 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2163 

2164 def __repr__(self) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2165 return 'FutureDatetime' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2166 

2167 

2168# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

2169 

2170 

2171class EncoderProtocol(Protocol): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2172 """Protocol for encoding and decoding data to and from bytes.""" 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2173 

2174 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2175 def decode(cls, data: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2176 """Decode the data using the encoder. 

2177 

2178 Args: 

2179 data: The data to decode. 

2180 

2181 Returns: 

2182 The decoded data. 

2183 """ 

2184 ... 

2185 

2186 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2187 def encode(cls, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2188 """Encode the data using the encoder. 

2189 

2190 Args: 

2191 value: The data to encode. 

2192 

2193 Returns: 

2194 The encoded data. 

2195 """ 

2196 ... 

2197 

2198 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2199 def get_json_format(cls) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2201 

2202 Returns: 

2203 The JSON format for the encoded data. 

2204 """ 

2205 ... 

2206 

2207 

2208class Base64Encoder(EncoderProtocol): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2210 

2211 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2212 def decode(cls, data: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2214 

2215 Args: 

2216 data: The data to decode. 

2217 

2218 Returns: 

2219 The decoded data. 

2220 """ 

2221 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2222 return base64.decodebytes(data) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2223 except ValueError as e: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

2225 

2226 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2227 def encode(cls, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2229 

2230 Args: 

2231 value: The data to encode. 

2232 

2233 Returns: 

2234 The encoded data. 

2235 """ 

2236 return base64.encodebytes(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2237 

2238 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2239 def get_json_format(cls) -> Literal['base64']: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2241 

2242 Returns: 

2243 The JSON format for the encoded data. 

2244 """ 

2245 return 'base64' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2246 

2247 

2248class Base64UrlEncoder(EncoderProtocol): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2249 """URL-safe Base64 encoder.""" 

2250 

2251 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2252 def decode(cls, data: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2254 

2255 Args: 

2256 data: The data to decode. 

2257 

2258 Returns: 

2259 The decoded data. 

2260 """ 

2261 try: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2262 return base64.urlsafe_b64decode(data) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2263 except ValueError as e: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

2265 

2266 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2267 def encode(cls, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2269 

2270 Args: 

2271 value: The data to encode. 

2272 

2273 Returns: 

2274 The encoded data. 

2275 """ 

2276 return base64.urlsafe_b64encode(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2277 

2278 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2279 def get_json_format(cls) -> Literal['base64url']: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2281 

2282 Returns: 

2283 The JSON format for the encoded data. 

2284 """ 

2285 return 'base64url' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2286 

2287 

2288@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2289class EncodedBytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2291 

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

2293 

2294 ```py 

2295 from typing_extensions import Annotated 

2296 

2297 from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError 

2298 

2299 class MyEncoder(EncoderProtocol): 

2300 @classmethod 

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

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

2303 raise ValueError('Cannot decode data') 

2304 return data[13:] 

2305 

2306 @classmethod 

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

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

2309 

2310 @classmethod 

2311 def get_json_format(cls) -> str: 

2312 return 'my-encoder' 

2313 

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

2315 

2316 class Model(BaseModel): 

2317 my_encoded_bytes: MyEncodedBytes 

2318 

2319 # Initialize the model with encoded data 

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

2321 

2322 # Access decoded value 

2323 print(m.my_encoded_bytes) 

2324 #> b'some bytes' 

2325 

2326 # Serialize into the encoded form 

2327 print(m.model_dump()) 

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

2329 

2330 # Validate encoded data 

2331 try: 

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

2333 except ValidationError as e: 

2334 print(e) 

2335 ''' 

2336 1 validation error for Model 

2337 my_encoded_bytes 

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

2339 ''' 

2340 ``` 

2341 """ 

2342 

2343 encoder: type[EncoderProtocol] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2344 

2345 def __get_pydantic_json_schema__( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2347 ) -> JsonSchemaValue: 

2348 field_schema = handler(core_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2349 field_schema.update(type='string', format=self.encoder.get_json_format()) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2350 return field_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2351 

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

2353 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2354 function=self.decode, 

2355 schema=core_schema.bytes_schema(), 

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

2357 ) 

2358 

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

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

2361 

2362 Args: 

2363 data: The data to decode. 

2364 

2365 Returns: 

2366 The decoded data. 

2367 """ 

2368 return self.encoder.decode(data) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2369 

2370 def encode(self, value: bytes) -> bytes: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2372 

2373 Args: 

2374 value: The data to encode. 

2375 

2376 Returns: 

2377 The encoded data. 

2378 """ 

2379 return self.encoder.encode(value) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2380 

2381 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2382 return hash(self.encoder) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2383 

2384 

2385@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2386class EncodedStr(EncodedBytes): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2388 

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

2390 

2391 ```py 

2392 from typing_extensions import Annotated 

2393 

2394 from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError 

2395 

2396 class MyEncoder(EncoderProtocol): 

2397 @classmethod 

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

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

2400 raise ValueError('Cannot decode data') 

2401 return data[13:] 

2402 

2403 @classmethod 

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

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

2406 

2407 @classmethod 

2408 def get_json_format(cls) -> str: 

2409 return 'my-encoder' 

2410 

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

2412 

2413 class Model(BaseModel): 

2414 my_encoded_str: MyEncodedStr 

2415 

2416 # Initialize the model with encoded data 

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

2418 

2419 # Access decoded value 

2420 print(m.my_encoded_str) 

2421 #> some str 

2422 

2423 # Serialize into the encoded form 

2424 print(m.model_dump()) 

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

2426 

2427 # Validate encoded data 

2428 try: 

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

2430 except ValidationError as e: 

2431 print(e) 

2432 ''' 

2433 1 validation error for Model 

2434 my_encoded_str 

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

2436 ''' 

2437 ``` 

2438 """ 

2439 

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

2441 return core_schema.with_info_after_validator_function( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2442 function=self.decode_str, 

2443 schema=super(EncodedStr, self).__get_pydantic_core_schema__(source=source, handler=handler), # noqa: UP008 

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

2445 ) 

2446 

2447 def decode_str(self, data: bytes, _: core_schema.ValidationInfo) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2449 

2450 Args: 

2451 data: The data to decode. 

2452 

2453 Returns: 

2454 The decoded data. 

2455 """ 

2456 return data.decode() 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2457 

2458 def encode_str(self, value: str) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2460 

2461 Args: 

2462 value: The data to encode. 

2463 

2464 Returns: 

2465 The encoded data. 

2466 """ 

2467 return super(EncodedStr, self).encode(value=value.encode()).decode() # noqa: UP008 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2468 

2469 def __hash__(self) -> int: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2470 return hash(self.encoder) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2471 

2472 

2473Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2475 

2476Note: 

2477 Under the hood, `Base64Bytes` use standard library `base64.encodebytes` and `base64.decodebytes` functions. 

2478 

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

2480 decoding. 

2481 

2482```py 

2483from pydantic import Base64Bytes, BaseModel, ValidationError 

2484 

2485class Model(BaseModel): 

2486 base64_bytes: Base64Bytes 

2487 

2488# Initialize the model with base64 data 

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

2490 

2491# Access decoded value 

2492print(m.base64_bytes) 

2493#> b'This is the way' 

2494 

2495# Serialize into the base64 form 

2496print(m.model_dump()) 

2497#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5\n'} 

2498 

2499# Validate base64 data 

2500try: 

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

2502except ValidationError as e: 

2503 print(e) 

2504 ''' 

2505 1 validation error for Model 

2506 base64_bytes 

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

2508 ''' 

2509``` 

2510""" 

2511Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2513 

2514Note: 

2515 Under the hood, `Base64Bytes` use standard library `base64.encodebytes` and `base64.decodebytes` functions. 

2516 

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

2518 decoding. 

2519 

2520```py 

2521from pydantic import Base64Str, BaseModel, ValidationError 

2522 

2523class Model(BaseModel): 

2524 base64_str: Base64Str 

2525 

2526# Initialize the model with base64 data 

2527m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y') 

2528 

2529# Access decoded value 

2530print(m.base64_str) 

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

2532 

2533# Serialize into the base64 form 

2534print(m.model_dump()) 

2535#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y\n'} 

2536 

2537# Validate base64 data 

2538try: 

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

2540except ValidationError as e: 

2541 print(e) 

2542 ''' 

2543 1 validation error for Model 

2544 base64_str 

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

2546 ''' 

2547``` 

2548""" 

2549Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2551 

2552Note: 

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

2554 functions. 

2555 

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

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

2558 

2559```py 

2560from pydantic import Base64UrlBytes, BaseModel 

2561 

2562class Model(BaseModel): 

2563 base64url_bytes: Base64UrlBytes 

2564 

2565# Initialize the model with base64 data 

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

2567print(m) 

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

2569``` 

2570""" 

2571Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2573 

2574Note: 

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

2576 functions. 

2577 

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

2579 

2580```py 

2581from pydantic import Base64UrlStr, BaseModel 

2582 

2583class Model(BaseModel): 

2584 base64url_str: Base64UrlStr 

2585 

2586# Initialize the model with base64 data 

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

2588print(m) 

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

2590``` 

2591""" 

2592 

2593 

2594__getattr__ = getattr_migration(__name__) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2595 

2596 

2597@_dataclasses.dataclass(**_internal_dataclass.slots_true) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2598class GetPydanticSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2599 """Usage docs: https://docs.pydantic.dev/2.8/concepts/types/#using-getpydanticschema-to-reduce-boilerplate 

2600 

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

2602 

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

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

2605 

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

2607 ```python 

2608 from typing import Any 

2609 

2610 from typing_extensions import Annotated 

2611 

2612 from pydantic import BaseModel, GetPydanticSchema 

2613 

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

2615 

2616 class Model(BaseModel): 

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

2618 

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

2620 #> 'abc' 

2621 ``` 

2622 """ 

2623 

2624 get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2625 get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2626 

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

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

2629 

2630 if not TYPE_CHECKING: 2630 ↛ 2642line 2630 didn't jump to line 2642 because the condition on line 2630 was always true1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2632 

2633 def __getattr__(self, item: str) -> Any: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2635 if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2636 return self.get_pydantic_core_schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2637 elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: 2637 ↛ 2638line 2637 didn't jump to line 2638 because the condition on line 2637 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2638 return self.get_pydantic_json_schema 

2639 else: 

2640 return object.__getattribute__(self, item) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2641 

2642 __hash__ = object.__hash__ 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2643 

2644 

2645@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2646class Tag: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2648 

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

2650 

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

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

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

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

2655 

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

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

2658 

2659 ```py 

2660 from typing import Any, Union 

2661 

2662 from typing_extensions import Annotated, Literal 

2663 

2664 from pydantic import BaseModel, Discriminator, Tag 

2665 

2666 class Pie(BaseModel): 

2667 time_to_cook: int 

2668 num_ingredients: int 

2669 

2670 class ApplePie(Pie): 

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

2672 

2673 class PumpkinPie(Pie): 

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

2675 

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

2677 if isinstance(v, dict): 

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

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

2680 

2681 class ThanksgivingDinner(BaseModel): 

2682 dessert: Annotated[ 

2683 Union[ 

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

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

2686 ], 

2687 Discriminator(get_discriminator_value), 

2688 ] 

2689 

2690 apple_variation = ThanksgivingDinner.model_validate( 

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

2692 ) 

2693 print(repr(apple_variation)) 

2694 ''' 

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

2696 ''' 

2697 

2698 pumpkin_variation = ThanksgivingDinner.model_validate( 

2699 { 

2700 'dessert': { 

2701 'filling': 'pumpkin', 

2702 'time_to_cook': 40, 

2703 'num_ingredients': 6, 

2704 } 

2705 } 

2706 ) 

2707 print(repr(pumpkin_variation)) 

2708 ''' 

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

2710 ''' 

2711 ``` 

2712 

2713 !!! note 

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

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

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

2717 

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

2719 

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

2721 """ 

2722 

2723 tag: str 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2724 

2725 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2726 schema = handler(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2727 metadata = schema.setdefault('metadata', {}) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2728 assert isinstance(metadata, dict) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2729 metadata[_core_utils.TAGGED_UNION_TAG_KEY] = self.tag 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2730 return schema 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2731 

2732 

2733@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2734class Discriminator: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2735 """Usage docs: https://docs.pydantic.dev/2.8/concepts/unions/#discriminated-unions-with-callable-discriminator 

2736 

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

2738 

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

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

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

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

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

2744 

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

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

2747 

2748 ```py 

2749 from typing import Any, Union 

2750 

2751 from typing_extensions import Annotated, Literal 

2752 

2753 from pydantic import BaseModel, Discriminator, Tag 

2754 

2755 class Pie(BaseModel): 

2756 time_to_cook: int 

2757 num_ingredients: int 

2758 

2759 class ApplePie(Pie): 

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

2761 

2762 class PumpkinPie(Pie): 

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

2764 

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

2766 if isinstance(v, dict): 

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

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

2769 

2770 class ThanksgivingDinner(BaseModel): 

2771 dessert: Annotated[ 

2772 Union[ 

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

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

2775 ], 

2776 Discriminator(get_discriminator_value), 

2777 ] 

2778 

2779 apple_variation = ThanksgivingDinner.model_validate( 

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

2781 ) 

2782 print(repr(apple_variation)) 

2783 ''' 

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

2785 ''' 

2786 

2787 pumpkin_variation = ThanksgivingDinner.model_validate( 

2788 { 

2789 'dessert': { 

2790 'filling': 'pumpkin', 

2791 'time_to_cook': 40, 

2792 'num_ingredients': 6, 

2793 } 

2794 } 

2795 ) 

2796 print(repr(pumpkin_variation)) 

2797 ''' 

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

2799 ''' 

2800 ``` 

2801 

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

2803 

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

2805 """ 

2806 

2807 discriminator: str | Callable[[Any], Hashable] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2809 

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

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

2812 """ 

2813 custom_error_type: str | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

2815 validation errors. 

2816 """ 

2817 custom_error_message: str | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2818 """Message to use in custom errors.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

2819 custom_error_context: dict[str, int | str | float] | None = None 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2820 """Context to use in custom errors.""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

2821 

2822 def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2823 origin = _typing_extra.get_origin(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2824 if not origin or not _typing_extra.origin_is_union(origin): 2824 ↛ 2825line 2824 didn't jump to line 2825 because the condition on line 2824 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

2826 

2827 if isinstance(self.discriminator, str): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2828 from pydantic import Field 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2829 

2830 return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2831 else: 

2832 original_schema = handler(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2833 return self._convert_schema(original_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2834 

2835 def _convert_schema(self, original_schema: core_schema.CoreSchema) -> core_schema.TaggedUnionSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2836 if original_schema['type'] != 'union': 2836 ↛ 2841line 2836 didn't jump to line 2841 because the condition on line 2836 was never true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

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

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

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

2841 original_schema = core_schema.union_schema([original_schema]) 

2842 

2843 tagged_union_choices = {} 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2844 for i, choice in enumerate(original_schema['choices']): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2845 tag = None 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2846 if isinstance(choice, tuple): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2847 choice, tag = choice 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2848 metadata = choice.get('metadata') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2849 if metadata is not None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2850 metadata_tag = metadata.get(_core_utils.TAGGED_UNION_TAG_KEY) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2851 if metadata_tag is not None: 2851 ↛ 2853line 2851 didn't jump to line 2853 because the condition on line 2851 was always true1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2852 tag = metadata_tag 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2853 if tag is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2854 raise PydanticUserError( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

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

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

2857 ) 

2858 tagged_union_choices[tag] = choice 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2859 

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

2861 custom_error_type = self.custom_error_type 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2862 if custom_error_type is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2863 custom_error_type = original_schema.get('custom_error_type') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2864 

2865 custom_error_message = self.custom_error_message 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2866 if custom_error_message is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2867 custom_error_message = original_schema.get('custom_error_message') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2868 

2869 custom_error_context = self.custom_error_context 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2870 if custom_error_context is None: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2871 custom_error_context = original_schema.get('custom_error_context') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2872 

2873 custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2874 return core_schema.tagged_union_schema( 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2875 tagged_union_choices, 

2876 self.discriminator, 

2877 custom_error_type=custom_error_type, 

2878 custom_error_message=custom_error_message, 

2879 custom_error_context=custom_error_context, 

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

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

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

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

2884 ) 

2885 

2886 

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

2888 

2889 

2890def _get_type_name(x: Any) -> str: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2891 type_ = type(x) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2892 if type_ in _JSON_TYPES: 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2893 return type_.__name__ 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2894 

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

2896 if isinstance(x, int): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2897 return 'int' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2898 if isinstance(x, float): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2899 return 'float' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2900 if isinstance(x, str): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2901 return 'str' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2902 if isinstance(x, list): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2903 return 'list' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2904 if isinstance(x, dict): 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2905 return 'dict' 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2906 

2907 # Fail by returning the type's actual name 

2908 return getattr(type_, '__name__', '<no type name>') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2909 

2910 

2911class _AllowAnyJson: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2912 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2913 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2914 python_schema = handler(source_type) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2915 return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

2916 

2917 

2918if TYPE_CHECKING: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2919 # This seems to only be necessary for mypy 

2920 JsonValue: TypeAlias = Union[ 

2921 List['JsonValue'], 

2922 Dict[str, 'JsonValue'], 

2923 str, 

2924 bool, 

2925 int, 

2926 float, 

2927 None, 

2928 ] 

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

2930 

2931 It may be one of: 

2932 

2933 * `List['JsonValue']` 

2934 * `Dict[str, 'JsonValue']` 

2935 * `str` 

2936 * `bool` 

2937 * `int` 

2938 * `float` 

2939 * `None` 

2940 

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

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

2943 

2944 ```py 

2945 import json 

2946 

2947 from pydantic import BaseModel, JsonValue, ValidationError 

2948 

2949 class Model(BaseModel): 

2950 j: JsonValue 

2951 

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

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

2954 

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

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

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

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

2959 

2960 try: 

2961 Model.model_validate(invalid_json_data) 

2962 except ValidationError as e: 

2963 print(e) 

2964 ''' 

2965 1 validation error for Model 

2966 j.dict.a.dict.b 

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

2968 ''' 

2969 ``` 

2970 """ 

2971 

2972else: 

2973 JsonValue = TypeAliasType( 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2974 'JsonValue', 

2975 Annotated[ 

2976 Union[ 

2977 Annotated[List['JsonValue'], Tag('list')], 

2978 Annotated[Dict[str, 'JsonValue'], Tag('dict')], 

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

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

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

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

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

2984 ], 

2985 Discriminator( 

2986 _get_type_name, 

2987 custom_error_type='invalid-json-value', 

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

2989 ), 

2990 _AllowAnyJson, 

2991 ], 

2992 ) 

2993 

2994 

2995class _OnErrorOmit: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2996 @classmethod 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

2997 def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

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

3000 # or as a standalone validator 

3001 return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') 1zABCbcdefghiDaIJKLjklmnopqEFGHrstuvwxy

3002 

3003 

3004OnErrorOmit = Annotated[T, _OnErrorOmit] 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

3005""" 1bcdefghiajklmnopqMNOPQRSTrstuvwxy

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

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

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

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

3010""" 

3011 

3012 

3013@_dataclasses.dataclass 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

3014class FailFast(_fields.PydanticMetadata, BaseMetadata): 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy

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

3016 

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

3018 

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

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

3021 

3022 ```py 

3023 from typing import List 

3024 from typing_extensions import Annotated 

3025 from pydantic import BaseModel, FailFast, ValidationError 

3026 

3027 class Model(BaseModel): 

3028 x: Annotated[List[int], FailFast()] 

3029 

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

3031 try: 

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

3033 except ValidationError as e: 

3034 print(e) 

3035 ''' 

3036 1 validation error for Model 

3037 x.2 

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

3039 ''' 

3040 ``` 

3041 """ 

3042 

3043 fail_fast: bool = True 1zABCbcdefghiDaIJKLjklmnopqUVMNOPQRSTEFGHrstuvwxy