Compare commits
10 commits
2886109347
...
113e982c1f
Author | SHA1 | Date | |
---|---|---|---|
113e982c1f | |||
9865822c70 | |||
a51a0b430d | |||
fe74caa497 | |||
c0dc1fee23 | |||
309fec0231 | |||
912971d44b | |||
9304378357 | |||
e6be59280f | |||
f1720b9d27 |
48 changed files with 2910 additions and 540 deletions
90
.github/workflows/ci.yml
vendored
90
.github/workflows/ci.yml
vendored
|
@ -8,60 +8,90 @@ on:
|
|||
- '**'
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
COLUMNS: 150
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v5
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
enable-cache: true
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
pip install -r requirements/pyproject.txt && pip install -r requirements/linting.txt
|
||||
- name: Install dependencies
|
||||
run: uv sync --python 3.12 --group lint --all-extras
|
||||
|
||||
- uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: --all-files --verbose
|
||||
env:
|
||||
SKIP: no-commit-to-branch
|
||||
|
||||
test:
|
||||
name: test py${{ matrix.python-version }} on ${{ matrix.os }}
|
||||
name: test py${{ matrix.python-version }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu, macos, windows]
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
|
||||
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v5
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
|
||||
- run: |
|
||||
pip install -r requirements/pyproject.txt && pip install -r requirements/testing.txt
|
||||
- name: Install dependencies
|
||||
run: uv sync --extra all
|
||||
|
||||
- run: pip freeze
|
||||
- name: Make coverage directory
|
||||
run: mkdir coverage
|
||||
|
||||
- run: make test
|
||||
- run: uv run --frozen coverage run -m pytest
|
||||
env:
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-with-deps
|
||||
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
|
||||
|
||||
- run: coverage xml
|
||||
- uses: codecov/codecov-action@v4
|
||||
- name: store coverage files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-${{ matrix.python-version }}
|
||||
path: coverage
|
||||
include-hidden-files: true
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
- name: get coverage files
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: coverage
|
||||
|
||||
- run: uv run --frozen coverage combine coverage
|
||||
|
||||
- run: uv run --frozen coverage report --fail-under 85
|
||||
|
||||
# https://github.com/marketplace/actions/alls-green#why used for branch protection checks
|
||||
check:
|
||||
if: always()
|
||||
needs: [lint, test]
|
||||
needs: [lint, test, coverage]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Decide whether the needed jobs succeeded or failed
|
||||
|
@ -70,7 +100,6 @@ jobs:
|
|||
jobs: ${{ toJSON(needs) }}
|
||||
|
||||
release:
|
||||
name: Release
|
||||
needs: [check]
|
||||
if: "success() && startsWith(github.ref, 'refs/tags/')"
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -82,21 +111,18 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v5
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: install
|
||||
run: pip install -U build
|
||||
enable-cache: true
|
||||
|
||||
- name: check GITHUB_REF matches package version
|
||||
uses: samuelcolvin/check-python-version@v4.1
|
||||
with:
|
||||
version_file_path: pydantic_extra_types/__init__.py
|
||||
|
||||
- name: build
|
||||
run: python -m build
|
||||
- run: uv build
|
||||
|
||||
- name: Upload package to PyPI
|
||||
- name: Publish to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
skip-existing: true
|
||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -4,16 +4,15 @@ venv/
|
|||
.venv/
|
||||
env3*/
|
||||
Pipfile
|
||||
*.lock
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.python-version
|
||||
/build/
|
||||
dist/
|
||||
.cache/
|
||||
.mypy_cache/
|
||||
test.py
|
||||
.coverage
|
||||
.hypothesis
|
||||
/htmlcov/
|
||||
/site/
|
||||
/site.zip
|
||||
|
@ -24,5 +23,4 @@ _build/
|
|||
/sandbox/
|
||||
/.ghtopdep_cache/
|
||||
/worktrees/
|
||||
.ruff_cache/
|
||||
.python-version
|
||||
/.ruff_cache/
|
||||
|
|
|
@ -1,24 +1,33 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: no-commit-to-branch # prevent direct commits to the `main` branch
|
||||
- id: check-yaml
|
||||
args: ['--unsafe']
|
||||
- id: check-toml
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: lint
|
||||
name: Lint
|
||||
entry: make lint
|
||||
types: [python]
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: mypy
|
||||
name: Mypy
|
||||
entry: make mypy
|
||||
types: [python]
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: format
|
||||
name: Format
|
||||
entry: make
|
||||
args: [format]
|
||||
language: system
|
||||
types: [python]
|
||||
pass_filenames: false
|
||||
- id: lint
|
||||
name: Lint
|
||||
entry: make
|
||||
args: [lint]
|
||||
types: [python]
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: Typecheck
|
||||
name: Typecheck
|
||||
entry: make
|
||||
args: [typecheck]
|
||||
types: [python]
|
||||
language: system
|
||||
pass_filenames: false
|
||||
|
|
59
HISTORY.md
59
HISTORY.md
|
@ -2,6 +2,65 @@
|
|||
|
||||
## Latest Changes
|
||||
|
||||
## 2.10.2
|
||||
|
||||
* Add back Python 3.8 support by @Viicos in https://github.com/pydantic/pydantic-extra-types/pull/249
|
||||
* ⬆ Bump astral-sh/setup-uv from 4 to 5 by @dependabot in https://github.com/pydantic/pydantic-extra-types/pull/282
|
||||
* Preserve months when using the Pendulum Duration type by @gareththackeray in https://github.com/pydantic/pydantic-extra-types/pull/283
|
||||
* ✨ Add type checking support and improve type hints across the codebase by @yezz123 in https://github.com/pydantic/pydantic-extra-types/pull/285
|
||||
* 📝 Add additional installation information to README by @oakhan3 in https://github.com/pydantic/pydantic-extra-types/pull/233
|
||||
|
||||
## 2.10.1
|
||||
|
||||
* Allow build with python-ulid 3.0.0 by @sunpoet in https://github.com/pydantic/pydantic-extra-types/pull/225
|
||||
* 🔨 added automatic syntax-upgrade hook ~ pyupgrade by @janas-adam in https://github.com/pydantic/pydantic-extra-types/pull/229
|
||||
* :fire: Revert adding pyupgrade as a hook in pre-commit by @yezz123 in https://github.com/pydantic/pydantic-extra-types/pull/230
|
||||
* isolate url in Currency by @edasubert in https://github.com/pydantic/pydantic-extra-types/pull/235
|
||||
* lower case currency is valid by @edasubert in https://github.com/pydantic/pydantic-extra-types/pull/236
|
||||
* Update SemanticVersion by @viccie30 in https://github.com/pydantic/pydantic-extra-types/pull/237
|
||||
* Epoch - unix timestamp by @commonism in https://github.com/pydantic/pydantic-extra-types/pull/240
|
||||
* :recycle: Migrate Pydantic Extra Types to use uv by @yezz123 in https://github.com/pydantic/pydantic-extra-types/pull/241
|
||||
* ⬆ Bump astral-sh/setup-uv from 3 to 4 by @dependabot in https://github.com/pydantic/pydantic-extra-types/pull/245
|
||||
* ⬆ Bump pre-commit/action from 3.0.0 to 3.0.1 by @dependabot in https://github.com/pydantic/pydantic-extra-types/pull/244
|
||||
* 🔖 Release version 2.10.1 by @yezz123 in https://github.com/pydantic/pydantic-extra-types/pull/246
|
||||
* Fix check python version for release by @hramezani in https://github.com/pydantic/pydantic-extra-types/pull/247
|
||||
|
||||
## 2.10.0
|
||||
|
||||
### Types
|
||||
|
||||
* Add semantic version type by @jbkroner in https://github.com/pydantic/pydantic-extra-types/pull/199
|
||||
* feat: add S3Path by @lucianosrp in https://github.com/pydantic/pydantic-extra-types/pull/206
|
||||
|
||||
### Refactor
|
||||
|
||||
* feature: Improve phone number validator by @mZbZ in https://github.com/pydantic/pydantic-extra-types/pull/202
|
||||
* Feature: Add phone number validator by @mZbZ in https://github.com/pydantic/pydantic-extra-types/pull/203
|
||||
* Domain name string type by @matter1-git in https://github.com/pydantic/pydantic-extra-types/pull/212
|
||||
* Adjust test_json_schema() for Pydantic 2.9 by @musicinmybrain in https://github.com/pydantic/pydantic-extra-types/pull/215
|
||||
* Allow python-ulid 3.0 by @musicinmybrain in https://github.com/pydantic/pydantic-extra-types/pull/222
|
||||
|
||||
### Dependencies
|
||||
|
||||
* ⬆ Bump the python-packages group with 5 updates by @dependabot in https://github.com/pydantic/pydantic-extra-types/pull/201
|
||||
* ✨ deprecate `semver` in favor of `semantic_version` by @07pepa in https://github.com/pydantic/pydantic-extra-types/pull/209
|
||||
* 🔖 Release version 2.10.0 by @yezz123 in https://github.com/pydantic/pydantic-extra-types/pull/224
|
||||
|
||||
## 2.9.0
|
||||
|
||||
### Types
|
||||
|
||||
* Add Semantic version type. PR [#195](https://github.com/pydantic/pydantic-extra-types/pull/195) by [@nikstuckenbrock](https://github.com/nikstuckenbrock)
|
||||
* Add timezone name validation. PR [#193](https://github.com/pydantic/pydantic-extra-types/pull/193) by [@07pepa](https://github.com/07pepa)
|
||||
|
||||
### Refactor
|
||||
|
||||
* Replace try-except block by if-else statement. PR [#192](https://github.com/pydantic/pydantic-extra-types/pull/192) by [@maxsos](https://github.com/maxsos)
|
||||
|
||||
### Dependencies
|
||||
|
||||
* ⬆ Bump the python-packages group with 4 updates. PR [#194](https://github.com/pydantic/pydantic-extra-types/pull/194) by @dependabot
|
||||
|
||||
## 2.8.2
|
||||
|
||||
* 🐛 Preserve timezone information when validating Pendulum DateTimes. [#189](https://github.com/pydantic/pydantic-extra-types/pull/189) by [@chrisguidry
|
||||
|
|
91
Makefile
91
Makefile
|
@ -1,70 +1,53 @@
|
|||
.DEFAULT_GOAL := all
|
||||
sources = pydantic_extra_types tests
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
python -m pip install -U pip
|
||||
pip install -r requirements/all.txt
|
||||
pip install -e .
|
||||
.PHONY: .uv # Check that uv is installed
|
||||
.uv:
|
||||
@uv --version || echo 'Please install uv: https://docs.astral.sh/uv/getting-started/installation/'
|
||||
|
||||
.PHONY: refresh-lockfiles
|
||||
refresh-lockfiles:
|
||||
@echo "Updating requirements/*.txt files using pip-compile"
|
||||
find requirements/ -name '*.txt' ! -name 'all.txt' -type f -delete
|
||||
pip-compile -q --no-emit-index-url --resolver backtracking -o requirements/linting.txt requirements/linting.in
|
||||
pip-compile -q --no-emit-index-url --resolver backtracking -o requirements/testing.txt requirements/testing.in
|
||||
pip-compile -q --no-emit-index-url --resolver backtracking --extra all -o requirements/pyproject.txt pyproject.toml
|
||||
pip install --dry-run -r requirements/all.txt
|
||||
.PHONY: install ## Install the package, dependencies, and pre-commit for local development
|
||||
install: .uv
|
||||
uv sync --frozen --group all --all-extras
|
||||
uv pip install pre-commit
|
||||
pre-commit install --install-hooks
|
||||
|
||||
.PHONY: format
|
||||
.PHONY: rebuild-lockfiles ## Rebuild lockfiles from scratch, updating all dependencies
|
||||
rebuild-lockfiles: .uv
|
||||
uv lock --upgrade
|
||||
|
||||
.PHONY: format # Format the code
|
||||
format:
|
||||
ruff check --fix $(sources)
|
||||
ruff format $(sources)
|
||||
uv run ruff format
|
||||
uv run ruff check --fix --fix-only
|
||||
|
||||
.PHONY: lint
|
||||
.PHONY: lint # Lint the code
|
||||
lint:
|
||||
ruff check $(sources)
|
||||
ruff format --check $(sources)
|
||||
uv run ruff format --check
|
||||
uv run ruff check
|
||||
|
||||
.PHONY: mypy
|
||||
mypy:
|
||||
mypy pydantic_extra_types
|
||||
.PHONY: typecheck # Typecheck the code
|
||||
typecheck:
|
||||
uv run mypy pydantic_extra_types
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
coverage run -m pytest --durations=10
|
||||
uv run pytest
|
||||
|
||||
.PHONY: testcov
|
||||
testcov: test
|
||||
@echo "building coverage html"
|
||||
@coverage html
|
||||
.PHONY: test-all-python # Run tests on Python 3.9 to 3.13
|
||||
test-all-python:
|
||||
UV_PROJECT_ENVIRONMENT=.venv39 uv run --python 3.9 coverage run -p -m pytest
|
||||
UV_PROJECT_ENVIRONMENT=.venv310 uv run --python 3.10 coverage run -p -m pytest
|
||||
UV_PROJECT_ENVIRONMENT=.venv311 uv run --python 3.11 coverage run -p -m pytest
|
||||
UV_PROJECT_ENVIRONMENT=.venv312 uv run --python 3.12 coverage run -p -m pytest
|
||||
UV_PROJECT_ENVIRONMENT=.venv313 uv run --python 3.13 coverage run -p -m pytest
|
||||
@uv run coverage combine
|
||||
@uv run coverage report
|
||||
|
||||
.PHONY: testcov-compile
|
||||
testcov-compile: build-trace test
|
||||
@echo "building coverage html"
|
||||
@coverage html
|
||||
.PHONY: testcov # Run tests and collect coverage data
|
||||
testcov:
|
||||
uv run coverage run -m pytest
|
||||
@uv run coverage report
|
||||
@uv run coverage html
|
||||
|
||||
.PHONY: all
|
||||
all: lint mypy testcov
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf `find . -name __pycache__`
|
||||
rm -f `find . -type f -name '*.py[co]'`
|
||||
rm -f `find . -type f -name '*~'`
|
||||
rm -f `find . -type f -name '.*~'`
|
||||
rm -rf .cache
|
||||
rm -rf .pytest_cache
|
||||
rm -rf .mypy_cache
|
||||
rm -rf htmlcov
|
||||
rm -rf *.egg-info
|
||||
rm -f .coverage
|
||||
rm -f .coverage.*
|
||||
rm -rf build
|
||||
rm -rf dist
|
||||
rm -rf coverage.xml
|
||||
rm -rf .ruff_cache
|
||||
|
||||
.PHONY: pre-commit
|
||||
pre-commit:
|
||||
pre-commit run --all-files --show-diff-on-failure
|
||||
all: format lint testcov
|
||||
|
|
14
README.md
14
README.md
|
@ -8,3 +8,17 @@
|
|||
A place for pydantic types that probably shouldn't exist in the main pydantic lib.
|
||||
|
||||
See [pydantic/pydantic#5012](https://github.com/pydantic/pydantic/issues/5012) for more info.
|
||||
|
||||
## Installation
|
||||
|
||||
Install this library with the desired extras dependencies as listed in [project.optional-dependencies](./pyproject.toml).
|
||||
|
||||
For example, if pendulum support was desired:
|
||||
|
||||
```shell
|
||||
# via uv
|
||||
$ uv add "pydantic-extra-types[pendulum]"
|
||||
|
||||
# via pip
|
||||
$ pip install -U "pydantic-extra-types[pendulum]"
|
||||
```
|
||||
|
|
36
debian/changelog
vendored
36
debian/changelog
vendored
|
@ -1,3 +1,39 @@
|
|||
pydantic-extra-types (2.10.2-1) sid; urgency=medium
|
||||
|
||||
* Uploading to sid.
|
||||
* Merging upstream version 2.10.2.
|
||||
|
||||
-- Daniel Baumann <daniel.baumann@progress-linux.org> Sat, 18 Jan 2025 07:21:36 +0100
|
||||
|
||||
pydantic-extra-types (2.10.1-1) sid; urgency=medium
|
||||
|
||||
* Uploading to sid.
|
||||
* Merging upstream version 2.10.1.
|
||||
* Updating source url in copyright.
|
||||
|
||||
-- Daniel Baumann <daniel.baumann@progress-linux.org> Mon, 09 Dec 2024 05:31:20 +0100
|
||||
|
||||
pydantic-extra-types (2.10.0-1) sid; urgency=medium
|
||||
|
||||
* Uploading to sid.
|
||||
* Merging upstream version 2.10.0.
|
||||
|
||||
-- Daniel Baumann <daniel.baumann@progress-linux.org> Tue, 22 Oct 2024 18:58:21 +0200
|
||||
|
||||
pydantic-extra-types (2.9.0-1) sid; urgency=medium
|
||||
|
||||
* Uploading to sid.
|
||||
* Merging upstream version 2.9.0.
|
||||
|
||||
-- Daniel Baumann <daniel.baumann@progress-linux.org> Sat, 13 Jul 2024 13:08:27 +0200
|
||||
|
||||
pydantic-extra-types (2.8.2-1) sid; urgency=medium
|
||||
|
||||
* Uploading to sid.
|
||||
* Merging upstream version 2.8.2.
|
||||
|
||||
-- Daniel Baumann <daniel.baumann@progress-linux.org> Mon, 17 Jun 2024 11:11:32 +0200
|
||||
|
||||
pydantic-extra-types (2.8.0-1) sid; urgency=medium
|
||||
|
||||
* Uploading to sid.
|
||||
|
|
2
debian/copyright
vendored
2
debian/copyright
vendored
|
@ -1,7 +1,7 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: pydantic-extra-types
|
||||
Upstream-Contact: https://github.com/pydantic/pydantic-extra-types/issues
|
||||
Source: https://github.com/pydantic/pydantic-extra-types/releases
|
||||
Source: https://github.com/pydantic/pydantic-extra-types/tags
|
||||
|
||||
Files: *
|
||||
Copyright: 2023-2024 Samuel Colvin <s@muelcolvin.com> and other contributors
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = '2.8.2'
|
||||
__version__ = '2.10.2'
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""
|
||||
Color definitions are used as per the CSS3
|
||||
"""Color definitions are used as per the CSS3
|
||||
[CSS Color Module Level 3](http://www.w3.org/TR/css3-color/#svg-color) specification.
|
||||
|
||||
A few colors have multiple names referring to the sames colors, eg. `grey` and `gray` or `aqua` and `cyan`.
|
||||
|
@ -26,9 +25,7 @@ HslColorTuple = Union[Tuple[float, float, float], Tuple[float, float, float, flo
|
|||
|
||||
|
||||
class RGBA:
|
||||
"""
|
||||
Internal use only as a representation of a color.
|
||||
"""
|
||||
"""Internal use only as a representation of a color."""
|
||||
|
||||
__slots__ = 'r', 'g', 'b', 'alpha', '_tuple'
|
||||
|
||||
|
@ -67,9 +64,7 @@ rads = 2 * math.pi
|
|||
|
||||
|
||||
class Color(_repr.Representation):
|
||||
"""
|
||||
Represents a color.
|
||||
"""
|
||||
"""Represents a color."""
|
||||
|
||||
__slots__ = '_original', '_rgba'
|
||||
|
||||
|
@ -101,14 +96,11 @@ class Color(_repr.Representation):
|
|||
return field_schema
|
||||
|
||||
def original(self) -> ColorType:
|
||||
"""
|
||||
Original value passed to `Color`.
|
||||
"""
|
||||
"""Original value passed to `Color`."""
|
||||
return self._original
|
||||
|
||||
def as_named(self, *, fallback: bool = False) -> str:
|
||||
"""
|
||||
Returns the name of the color if it can be found in `COLORS_BY_VALUE` dictionary,
|
||||
"""Returns the name of the color if it can be found in `COLORS_BY_VALUE` dictionary,
|
||||
otherwise returns the hexadecimal representation of the color or raises `ValueError`.
|
||||
|
||||
Args:
|
||||
|
@ -123,14 +115,15 @@ class Color(_repr.Representation):
|
|||
"""
|
||||
if self._rgba.alpha is not None:
|
||||
return self.as_hex()
|
||||
rgb = cast(Tuple[int, int, int], self.as_rgb_tuple())
|
||||
try:
|
||||
rgb = cast('tuple[int, int, int]', self.as_rgb_tuple())
|
||||
|
||||
if rgb in COLORS_BY_VALUE:
|
||||
return COLORS_BY_VALUE[rgb]
|
||||
except KeyError as e:
|
||||
else:
|
||||
if fallback:
|
||||
return self.as_hex()
|
||||
else:
|
||||
raise ValueError('no named color found, use fallback=True, as_hex() or as_rgb()') from e
|
||||
raise ValueError('no named color found, use fallback=True, as_hex() or as_rgb()')
|
||||
|
||||
def as_hex(self, format: Literal['short', 'long'] = 'short') -> str:
|
||||
"""Returns the hexadecimal representation of the color.
|
||||
|
@ -151,9 +144,7 @@ class Color(_repr.Representation):
|
|||
return f'#{as_hex}'
|
||||
|
||||
def as_rgb(self) -> str:
|
||||
"""
|
||||
Color as an `rgb(<r>, <g>, <b>)` or `rgba(<r>, <g>, <b>, <a>)` string.
|
||||
"""
|
||||
"""Color as an `rgb(<r>, <g>, <b>)` or `rgba(<r>, <g>, <b>, <a>)` string."""
|
||||
if self._rgba.alpha is None:
|
||||
return f'rgb({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)})'
|
||||
else:
|
||||
|
@ -163,8 +154,7 @@ class Color(_repr.Representation):
|
|||
)
|
||||
|
||||
def as_rgb_tuple(self, *, alpha: bool | None = None) -> ColorTuple:
|
||||
"""
|
||||
Returns the color as an RGB or RGBA tuple.
|
||||
"""Returns the color as an RGB or RGBA tuple.
|
||||
|
||||
Args:
|
||||
alpha: Whether to include the alpha channel. There are three options for this input:
|
||||
|
@ -184,9 +174,7 @@ class Color(_repr.Representation):
|
|||
return r, g, b, self._alpha_float()
|
||||
|
||||
def as_hsl(self) -> str:
|
||||
"""
|
||||
Color as an `hsl(<h>, <s>, <l>)` or `hsl(<h>, <s>, <l>, <a>)` string.
|
||||
"""
|
||||
"""Color as an `hsl(<h>, <s>, <l>)` or `hsl(<h>, <s>, <l>, <a>)` string."""
|
||||
if self._rgba.alpha is None:
|
||||
h, s, li = self.as_hsl_tuple(alpha=False) # type: ignore
|
||||
return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%})'
|
||||
|
@ -195,8 +183,7 @@ class Color(_repr.Representation):
|
|||
return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%}, {round(a, 2)})'
|
||||
|
||||
def as_hsl_tuple(self, *, alpha: bool | None = None) -> HslColorTuple:
|
||||
"""
|
||||
Returns the color as an HSL or HSLA tuple.
|
||||
"""Returns the color as an HSL or HSLA tuple.
|
||||
|
||||
Args:
|
||||
alpha: Whether to include the alpha channel.
|
||||
|
@ -271,8 +258,7 @@ def parse_tuple(value: tuple[Any, ...]) -> RGBA:
|
|||
|
||||
|
||||
def parse_str(value: str) -> RGBA:
|
||||
"""
|
||||
Parse a string representing a color to an RGBA tuple.
|
||||
"""Parse a string representing a color to an RGBA tuple.
|
||||
|
||||
Possible formats for the input string include:
|
||||
|
||||
|
@ -293,11 +279,8 @@ def parse_str(value: str) -> RGBA:
|
|||
ValueError: If the input string cannot be parsed to an RGBA tuple.
|
||||
"""
|
||||
value_lower = value.lower()
|
||||
try:
|
||||
if value_lower in COLORS_BY_NAME:
|
||||
r, g, b = COLORS_BY_NAME[value_lower]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
return ints_to_rgba(r, g, b, None)
|
||||
|
||||
m = re.fullmatch(r_hex_short, value_lower)
|
||||
|
@ -337,8 +320,7 @@ def ints_to_rgba(
|
|||
b: int | str,
|
||||
alpha: float | None = None,
|
||||
) -> RGBA:
|
||||
"""
|
||||
Converts integer or string values for RGB color and an optional alpha value to an `RGBA` object.
|
||||
"""Converts integer or string values for RGB color and an optional alpha value to an `RGBA` object.
|
||||
|
||||
Args:
|
||||
r: An integer or string representing the red color value.
|
||||
|
@ -358,8 +340,7 @@ def ints_to_rgba(
|
|||
|
||||
|
||||
def parse_color_value(value: int | str, max_val: int = 255) -> float:
|
||||
"""
|
||||
Parse the color value provided and return a number between 0 and 1.
|
||||
"""Parse the color value provided and return a number between 0 and 1.
|
||||
|
||||
Args:
|
||||
value: An integer or string color value.
|
||||
|
@ -389,8 +370,7 @@ def parse_color_value(value: int | str, max_val: int = 255) -> float:
|
|||
|
||||
|
||||
def parse_float_alpha(value: None | str | float | int) -> float | None:
|
||||
"""
|
||||
Parse an alpha value checking it's a valid float in the range 0 to 1.
|
||||
"""Parse an alpha value checking it's a valid float in the range 0 to 1.
|
||||
|
||||
Args:
|
||||
value: The input value to parse.
|
||||
|
@ -426,8 +406,7 @@ def parse_float_alpha(value: None | str | float | int) -> float | None:
|
|||
|
||||
|
||||
def parse_hsl(h: str, h_units: str, sat: str, light: str, alpha: float | None = None) -> RGBA:
|
||||
"""
|
||||
Parse raw hue, saturation, lightness, and alpha values and convert to RGBA.
|
||||
"""Parse raw hue, saturation, lightness, and alpha values and convert to RGBA.
|
||||
|
||||
Args:
|
||||
h: The hue value.
|
||||
|
@ -455,8 +434,7 @@ def parse_hsl(h: str, h_units: str, sat: str, light: str, alpha: float | None =
|
|||
|
||||
|
||||
def float_to_255(c: float) -> int:
|
||||
"""
|
||||
Converts a float value between 0 and 1 (inclusive) to an integer between 0 and 255 (inclusive).
|
||||
"""Converts a float value between 0 and 1 (inclusive) to an integer between 0 and 255 (inclusive).
|
||||
|
||||
Args:
|
||||
c: The float value to be converted. Must be between 0 and 1 (inclusive).
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
"""
|
||||
The `pydantic_extra_types.coordinate` module provides the [`Latitude`][pydantic_extra_types.coordinate.Latitude],
|
||||
"""The `pydantic_extra_types.coordinate` module provides the [`Latitude`][pydantic_extra_types.coordinate.Latitude],
|
||||
[`Longitude`][pydantic_extra_types.coordinate.Longitude], and
|
||||
[`Coordinate`][pydantic_extra_types.coordinate.Coordinate] data types.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, ClassVar, Tuple, Type
|
||||
from typing import Any, ClassVar, Tuple
|
||||
|
||||
from pydantic import GetCoreSchemaHandler
|
||||
from pydantic._internal import _repr
|
||||
|
@ -19,12 +20,14 @@ class Latitude(float):
|
|||
from pydantic import BaseModel
|
||||
from pydantic_extra_types.coordinate import Latitude
|
||||
|
||||
|
||||
class Location(BaseModel):
|
||||
latitude: Latitude
|
||||
|
||||
|
||||
location = Location(latitude=41.40338)
|
||||
print(location)
|
||||
#> latitude=41.40338
|
||||
# > latitude=41.40338
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -32,7 +35,7 @@ class Latitude(float):
|
|||
max: ClassVar[float] = 90.00
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: Type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
return core_schema.float_schema(ge=cls.min, le=cls.max)
|
||||
|
||||
|
||||
|
@ -44,12 +47,14 @@ class Longitude(float):
|
|||
|
||||
from pydantic_extra_types.coordinate import Longitude
|
||||
|
||||
|
||||
class Location(BaseModel):
|
||||
longitude: Longitude
|
||||
|
||||
|
||||
location = Location(longitude=2.17403)
|
||||
print(location)
|
||||
#> longitude=2.17403
|
||||
# > longitude=2.17403
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -57,7 +62,7 @@ class Longitude(float):
|
|||
max: ClassVar[float] = 180.00
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: Type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
return core_schema.float_schema(ge=cls.min, le=cls.max)
|
||||
|
||||
|
||||
|
@ -76,11 +81,13 @@ class Coordinate(_repr.Representation):
|
|||
|
||||
from pydantic_extra_types.coordinate import Coordinate
|
||||
|
||||
|
||||
class Location(BaseModel):
|
||||
coordinate: Coordinate
|
||||
|
||||
|
||||
location = Location(coordinate=(41.40338, 2.17403))
|
||||
#> coordinate=Coordinate(latitude=41.40338, longitude=2.17403)
|
||||
# > coordinate=Coordinate(latitude=41.40338, longitude=2.17403)
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -90,7 +97,7 @@ class Coordinate(_repr.Representation):
|
|||
longitude: Longitude
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: Type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
schema_chain = [
|
||||
core_schema.no_info_wrap_validator_function(cls._parse_str, core_schema.str_schema()),
|
||||
core_schema.no_info_wrap_validator_function(
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
"""
|
||||
Country definitions that are based on the [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).
|
||||
"""
|
||||
"""Country definitions that are based on the [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
@ -69,12 +67,14 @@ class CountryAlpha2(str):
|
|||
|
||||
from pydantic_extra_types.country import CountryAlpha2
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
made_in: CountryAlpha2
|
||||
|
||||
|
||||
product = Product(made_in='ES')
|
||||
print(product)
|
||||
#> made_in='ES'
|
||||
# > made_in='ES'
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -126,12 +126,14 @@ class CountryAlpha3(str):
|
|||
|
||||
from pydantic_extra_types.country import CountryAlpha3
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
made_in: CountryAlpha3
|
||||
|
||||
product = Product(made_in="USA")
|
||||
|
||||
product = Product(made_in='USA')
|
||||
print(product)
|
||||
#> made_in='USA'
|
||||
# > made_in='USA'
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -184,12 +186,14 @@ class CountryNumericCode(str):
|
|||
|
||||
from pydantic_extra_types.country import CountryNumericCode
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
made_in: CountryNumericCode
|
||||
|
||||
product = Product(made_in="840")
|
||||
|
||||
product = Product(made_in='840')
|
||||
print(product)
|
||||
#> made_in='840'
|
||||
# > made_in='840'
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -241,12 +245,14 @@ class CountryShortName(str):
|
|||
|
||||
from pydantic_extra_types.country import CountryShortName
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
made_in: CountryShortName
|
||||
|
||||
product = Product(made_in="United States")
|
||||
|
||||
product = Product(made_in='United States')
|
||||
print(product)
|
||||
#> made_in='United States'
|
||||
# > made_in='United States'
|
||||
```
|
||||
"""
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
"""
|
||||
Currency definitions that are based on the [ISO4217](https://en.wikipedia.org/wiki/ISO_4217).
|
||||
"""
|
||||
"""Currency definitions that are based on the [ISO4217](https://en.wikipedia.org/wiki/ISO_4217)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
@ -41,9 +39,11 @@ class ISO4217(str):
|
|||
|
||||
from pydantic_extra_types.currency_code import ISO4217
|
||||
|
||||
|
||||
class Currency(BaseModel):
|
||||
alpha_3: ISO4217
|
||||
|
||||
|
||||
currency = Currency(alpha_3='AED')
|
||||
print(currency)
|
||||
# > alpha_3='AED'
|
||||
|
@ -55,8 +55,7 @@ class ISO4217(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, currency_code: str, _: core_schema.ValidationInfo) -> str:
|
||||
"""
|
||||
Validate a ISO 4217 language code from the provided str value.
|
||||
"""Validate a ISO 4217 language code from the provided str value.
|
||||
|
||||
Args:
|
||||
currency_code: The str value to be validated.
|
||||
|
@ -68,6 +67,7 @@ class ISO4217(str):
|
|||
Raises:
|
||||
PydanticCustomError: If the ISO 4217 currency code is not valid.
|
||||
"""
|
||||
currency_code = currency_code.upper()
|
||||
if currency_code not in cls.allowed_currencies:
|
||||
raise PydanticCustomError(
|
||||
'ISO4217', 'Invalid ISO 4217 currency code. See https://en.wikipedia.org/wiki/ISO_4217'
|
||||
|
@ -98,9 +98,11 @@ class Currency(str):
|
|||
|
||||
from pydantic_extra_types.currency_code import Currency
|
||||
|
||||
|
||||
class currency(BaseModel):
|
||||
alpha_3: Currency
|
||||
|
||||
|
||||
cur = currency(alpha_3='AED')
|
||||
print(cur)
|
||||
# > alpha_3='AED'
|
||||
|
@ -114,8 +116,7 @@ class Currency(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, currency_symbol: str, _: core_schema.ValidationInfo) -> str:
|
||||
"""
|
||||
Validate a subset of the [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) format.
|
||||
"""Validate a subset of the [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) format.
|
||||
It excludes bonds testing codes and precious metals.
|
||||
|
||||
Args:
|
||||
|
@ -128,27 +129,27 @@ class Currency(str):
|
|||
Raises:
|
||||
PydanticCustomError: If the ISO 4217 currency code is not valid or is bond, precious metal or testing code.
|
||||
"""
|
||||
currency_symbol = currency_symbol.upper()
|
||||
if currency_symbol not in cls.allowed_currencies:
|
||||
raise PydanticCustomError(
|
||||
'InvalidCurrency',
|
||||
'Invalid currency code.'
|
||||
' See https://en.wikipedia.org/wiki/ISO_4217. '
|
||||
' See https://en.wikipedia.org/wiki/ISO_4217 . '
|
||||
'Bonds, testing and precious metals codes are not allowed.',
|
||||
)
|
||||
return currency_symbol
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, _: type[Any], __: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the currency subset of the
|
||||
"""Return a Pydantic CoreSchema with the currency subset of the
|
||||
[ISO4217](https://en.wikipedia.org/wiki/ISO_4217) format.
|
||||
It excludes bonds testing codes and precious metals.
|
||||
|
||||
Args:
|
||||
Args:
|
||||
_: The source type.
|
||||
__: The handler to get the CoreSchema.
|
||||
|
||||
Returns:
|
||||
Returns:
|
||||
A Pydantic CoreSchema with the subset of the currency subset of the
|
||||
[ISO4217](https://en.wikipedia.org/wiki/ISO_4217) format.
|
||||
It excludes bonds testing codes and precious metals.
|
||||
|
@ -162,8 +163,7 @@ class Currency(str):
|
|||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Return a Pydantic JSON Schema with subset of the [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) format.
|
||||
"""Return a Pydantic JSON Schema with subset of the [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) format.
|
||||
Excluding bonds testing codes and precious metals.
|
||||
|
||||
Args:
|
||||
|
|
58
pydantic_extra_types/domain.py
Normal file
58
pydantic_extra_types/domain.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
"""The `domain_str` module provides the `DomainStr` data type.
|
||||
This class depends on the `pydantic` package and implements custom validation for domain string format.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from pydantic import GetCoreSchemaHandler
|
||||
from pydantic_core import PydanticCustomError, core_schema
|
||||
|
||||
|
||||
class DomainStr(str):
|
||||
"""A string subclass with custom validation for domain string format."""
|
||||
|
||||
@classmethod
|
||||
def validate(cls, __input_value: Any, _: Any) -> str:
|
||||
"""Validate a domain name from the provided value.
|
||||
|
||||
Args:
|
||||
__input_value: The value to be validated.
|
||||
_: The source type to be converted.
|
||||
|
||||
Returns:
|
||||
str: The parsed domain name.
|
||||
|
||||
"""
|
||||
return cls._validate(__input_value)
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, v: Any) -> DomainStr:
|
||||
if not isinstance(v, str):
|
||||
raise PydanticCustomError('domain_type', 'Value must be a string')
|
||||
|
||||
v = v.strip().lower()
|
||||
if len(v) < 1 or len(v) > 253:
|
||||
raise PydanticCustomError('domain_length', 'Domain must be between 1 and 253 characters')
|
||||
|
||||
pattern = r'^([a-z0-9-]+(\.[a-z0-9-]+)+)$'
|
||||
if not re.match(pattern, v):
|
||||
raise PydanticCustomError('domain_format', 'Invalid domain format')
|
||||
|
||||
return cls(v)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
return core_schema.with_info_before_validator_function(
|
||||
cls.validate,
|
||||
core_schema.str_schema(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetCoreSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
# Cast the return value to dict[str, Any]
|
||||
return dict(handler(schema))
|
97
pydantic_extra_types/epoch.py
Normal file
97
pydantic_extra_types/epoch.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from typing import Any, Callable
|
||||
|
||||
import pydantic_core.core_schema
|
||||
from pydantic import GetJsonSchemaHandler
|
||||
from pydantic.json_schema import JsonSchemaValue
|
||||
from pydantic_core import CoreSchema, core_schema
|
||||
|
||||
EPOCH = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
|
||||
|
||||
|
||||
class _Base(datetime.datetime):
|
||||
TYPE: str = ''
|
||||
SCHEMA: pydantic_core.core_schema.CoreSchema
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(
|
||||
cls, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> JsonSchemaValue:
|
||||
field_schema: dict[str, Any] = {}
|
||||
field_schema.update(type=cls.TYPE, format='date-time')
|
||||
return field_schema
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(
|
||||
cls, source: type[Any], handler: Callable[[Any], CoreSchema]
|
||||
) -> core_schema.CoreSchema:
|
||||
return core_schema.with_info_after_validator_function(
|
||||
cls._validate,
|
||||
cls.SCHEMA,
|
||||
serialization=core_schema.wrap_serializer_function_ser_schema(cls._f, return_schema=cls.SCHEMA),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: Any, _: Any) -> datetime.datetime:
|
||||
return EPOCH + datetime.timedelta(seconds=__input_value)
|
||||
|
||||
@classmethod
|
||||
def _f(cls, value: Any, serializer: Callable[[Any], Any]) -> Any: # pragma: no cover
|
||||
raise NotImplementedError(cls)
|
||||
|
||||
|
||||
class Number(_Base):
|
||||
"""epoch.Number parses unix timestamp as float and converts it to datetime.
|
||||
|
||||
```py
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pydantic_extra_types import epoch
|
||||
|
||||
|
||||
class LogEntry(BaseModel):
|
||||
timestamp: epoch.Number
|
||||
|
||||
|
||||
logentry = LogEntry(timestamp=1.1)
|
||||
print(logentry)
|
||||
# > timestamp=datetime.datetime(1970, 1, 1, 0, 0, 1, 100000, tzinfo=datetime.timezone.utc)
|
||||
```
|
||||
"""
|
||||
|
||||
TYPE = 'number'
|
||||
SCHEMA = core_schema.float_schema()
|
||||
|
||||
@classmethod
|
||||
def _f(cls, value: Any, serializer: Callable[[float], float]) -> float:
|
||||
ts = value.timestamp()
|
||||
return serializer(ts)
|
||||
|
||||
|
||||
class Integer(_Base):
|
||||
"""epoch.Integer parses unix timestamp as integer and converts it to datetime.
|
||||
|
||||
```
|
||||
```py
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pydantic_extra_types import epoch
|
||||
|
||||
class LogEntry(BaseModel):
|
||||
timestamp: epoch.Integer
|
||||
|
||||
logentry = LogEntry(timestamp=1)
|
||||
print(logentry)
|
||||
#> timestamp=datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=datetime.timezone.utc)
|
||||
```
|
||||
"""
|
||||
|
||||
TYPE = 'integer'
|
||||
SCHEMA = core_schema.int_schema()
|
||||
|
||||
@classmethod
|
||||
def _f(cls, value: Any, serializer: Callable[[int], int]) -> int:
|
||||
ts = value.timestamp()
|
||||
return serializer(int(ts))
|
|
@ -1,5 +1,4 @@
|
|||
"""
|
||||
The `pydantic_extra_types.isbn` module provides functionality to recieve and validate ISBN.
|
||||
"""The `pydantic_extra_types.isbn` module provides functionality to recieve and validate ISBN.
|
||||
|
||||
ISBN (International Standard Book Number) is a numeric commercial book identifier which is intended to be unique. This module provides a ISBN type for Pydantic models.
|
||||
"""
|
||||
|
@ -58,16 +57,16 @@ class ISBN(str):
|
|||
class Book(BaseModel):
|
||||
isbn: ISBN
|
||||
|
||||
book = Book(isbn="8537809667")
|
||||
|
||||
book = Book(isbn='8537809667')
|
||||
print(book)
|
||||
#> isbn='9788537809662'
|
||||
# > isbn='9788537809662'
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the ISBN validation.
|
||||
"""Return a Pydantic CoreSchema with the ISBN validation.
|
||||
|
||||
Args:
|
||||
source: The source type to be converted.
|
||||
|
@ -84,8 +83,7 @@ class ISBN(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: Any) -> str:
|
||||
"""
|
||||
Validate a ISBN from the provided str value.
|
||||
"""Validate a ISBN from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -111,7 +109,6 @@ class ISBN(str):
|
|||
Raises:
|
||||
PydanticCustomError: If the ISBN is not valid.
|
||||
"""
|
||||
|
||||
isbn_length = len(value)
|
||||
|
||||
if isbn_length not in (10, 13):
|
||||
|
@ -143,7 +140,6 @@ class ISBN(str):
|
|||
Returns:
|
||||
The converted ISBN or the original value if no conversion is necessary.
|
||||
"""
|
||||
|
||||
if len(value) == 10:
|
||||
base_isbn = f'978{value[:-1]}'
|
||||
isbn13_digit = isbn13_digit_calc(base_isbn)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
"""
|
||||
Language definitions that are based on the [ISO 639-3](https://en.wikipedia.org/wiki/ISO_639-3) & [ISO 639-5](https://en.wikipedia.org/wiki/ISO_639-5).
|
||||
"""
|
||||
"""Language definitions that are based on the [ISO 639-3](https://en.wikipedia.org/wiki/ISO_639-3) & [ISO 639-5](https://en.wikipedia.org/wiki/ISO_639-5)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
@ -22,8 +20,7 @@ except ModuleNotFoundError as e: # pragma: no cover
|
|||
|
||||
@dataclass
|
||||
class LanguageInfo:
|
||||
"""
|
||||
LanguageInfo is a dataclass that contains the language information.
|
||||
"""LanguageInfo is a dataclass that contains the language information.
|
||||
|
||||
Args:
|
||||
alpha2: The language code in the [ISO 639-1 alpha-2](https://en.wikipedia.org/wiki/ISO_639-1) format.
|
||||
|
@ -38,8 +35,7 @@ class LanguageInfo:
|
|||
|
||||
@lru_cache
|
||||
def _languages() -> list[LanguageInfo]:
|
||||
"""
|
||||
Return a list of LanguageInfo objects containing the language information.
|
||||
"""Return a list of LanguageInfo objects containing the language information.
|
||||
|
||||
Returns:
|
||||
A list of LanguageInfo objects containing the language information.
|
||||
|
@ -56,25 +52,19 @@ def _languages() -> list[LanguageInfo]:
|
|||
|
||||
@lru_cache
|
||||
def _index_by_alpha2() -> dict[str, LanguageInfo]:
|
||||
"""
|
||||
Return a dictionary with the language code in the [ISO 639-1 alpha-2](https://en.wikipedia.org/wiki/ISO_639-1) format as the key and the LanguageInfo object as the value.
|
||||
"""
|
||||
"""Return a dictionary with the language code in the [ISO 639-1 alpha-2](https://en.wikipedia.org/wiki/ISO_639-1) format as the key and the LanguageInfo object as the value."""
|
||||
return {language.alpha2: language for language in _languages() if language.alpha2 is not None}
|
||||
|
||||
|
||||
@lru_cache
|
||||
def _index_by_alpha3() -> dict[str, LanguageInfo]:
|
||||
"""
|
||||
Return a dictionary with the language code in the [ISO 639-3 alpha-3](https://en.wikipedia.org/wiki/ISO_639-3) format as the key and the LanguageInfo object as the value.
|
||||
"""
|
||||
"""Return a dictionary with the language code in the [ISO 639-3 alpha-3](https://en.wikipedia.org/wiki/ISO_639-3) format as the key and the LanguageInfo object as the value."""
|
||||
return {language.alpha3: language for language in _languages()}
|
||||
|
||||
|
||||
@lru_cache
|
||||
def _index_by_name() -> dict[str, LanguageInfo]:
|
||||
"""
|
||||
Return a dictionary with the language name as the key and the LanguageInfo object as the value.
|
||||
"""
|
||||
"""Return a dictionary with the language name as the key and the LanguageInfo object as the value."""
|
||||
return {language.name: language for language in _languages()}
|
||||
|
||||
|
||||
|
@ -87,20 +77,21 @@ class LanguageAlpha2(str):
|
|||
|
||||
from pydantic_extra_types.language_code import LanguageAlpha2
|
||||
|
||||
|
||||
class Movie(BaseModel):
|
||||
audio_lang: LanguageAlpha2
|
||||
subtitles_lang: LanguageAlpha2
|
||||
|
||||
|
||||
movie = Movie(audio_lang='de', subtitles_lang='fr')
|
||||
print(movie)
|
||||
#> audio_lang='de' subtitles_lang='fr'
|
||||
# > audio_lang='de' subtitles_lang='fr'
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> LanguageAlpha2:
|
||||
"""
|
||||
Validate a language code in the ISO 639-1 alpha-2 format from the provided str value.
|
||||
"""Validate a language code in the ISO 639-1 alpha-2 format from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -117,8 +108,7 @@ class LanguageAlpha2(str):
|
|||
def __get_pydantic_core_schema__(
|
||||
cls, source: type[Any], handler: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the language code in the ISO 639-1 alpha-2 format validation.
|
||||
"""Return a Pydantic CoreSchema with the language code in the ISO 639-1 alpha-2 format validation.
|
||||
|
||||
Args:
|
||||
source: The source type.
|
||||
|
@ -136,8 +126,7 @@ class LanguageAlpha2(str):
|
|||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Return a Pydantic JSON Schema with the language code in the ISO 639-1 alpha-2 format validation.
|
||||
"""Return a Pydantic JSON Schema with the language code in the ISO 639-1 alpha-2 format validation.
|
||||
|
||||
Args:
|
||||
schema: The Pydantic CoreSchema.
|
||||
|
@ -170,20 +159,21 @@ class LanguageName(str):
|
|||
|
||||
from pydantic_extra_types.language_code import LanguageName
|
||||
|
||||
|
||||
class Movie(BaseModel):
|
||||
audio_lang: LanguageName
|
||||
subtitles_lang: LanguageName
|
||||
|
||||
|
||||
movie = Movie(audio_lang='Dutch', subtitles_lang='Mandarin Chinese')
|
||||
print(movie)
|
||||
#> audio_lang='Dutch' subtitles_lang='Mandarin Chinese'
|
||||
# > audio_lang='Dutch' subtitles_lang='Mandarin Chinese'
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> LanguageName:
|
||||
"""
|
||||
Validate a language name from the provided str value.
|
||||
"""Validate a language name from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -200,8 +190,7 @@ class LanguageName(str):
|
|||
def __get_pydantic_core_schema__(
|
||||
cls, source: type[Any], handler: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the language name validation.
|
||||
"""Return a Pydantic CoreSchema with the language name validation.
|
||||
|
||||
Args:
|
||||
source: The source type.
|
||||
|
@ -236,9 +225,11 @@ class ISO639_3(str):
|
|||
|
||||
from pydantic_extra_types.language_code import ISO639_3
|
||||
|
||||
|
||||
class Language(BaseModel):
|
||||
alpha_3: ISO639_3
|
||||
|
||||
|
||||
lang = Language(alpha_3='ssr')
|
||||
print(lang)
|
||||
# > alpha_3='ssr'
|
||||
|
@ -250,8 +241,7 @@ class ISO639_3(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> ISO639_3:
|
||||
"""
|
||||
Validate a ISO 639-3 language code from the provided str value.
|
||||
"""Validate a ISO 639-3 language code from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -273,8 +263,7 @@ class ISO639_3(str):
|
|||
def __get_pydantic_core_schema__(
|
||||
cls, _: type[Any], __: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the ISO 639-3 language code validation.
|
||||
"""Return a Pydantic CoreSchema with the ISO 639-3 language code validation.
|
||||
|
||||
Args:
|
||||
_: The source type.
|
||||
|
@ -293,8 +282,7 @@ class ISO639_3(str):
|
|||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Return a Pydantic JSON Schema with the ISO 639-3 language code validation.
|
||||
"""Return a Pydantic JSON Schema with the ISO 639-3 language code validation.
|
||||
|
||||
Args:
|
||||
schema: The Pydantic CoreSchema.
|
||||
|
@ -318,9 +306,11 @@ class ISO639_5(str):
|
|||
|
||||
from pydantic_extra_types.language_code import ISO639_5
|
||||
|
||||
|
||||
class Language(BaseModel):
|
||||
alpha_3: ISO639_5
|
||||
|
||||
|
||||
lang = Language(alpha_3='gem')
|
||||
print(lang)
|
||||
# > alpha_3='gem'
|
||||
|
@ -333,8 +323,7 @@ class ISO639_5(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> ISO639_5:
|
||||
"""
|
||||
Validate a ISO 639-5 language code from the provided str value.
|
||||
"""Validate a ISO 639-5 language code from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -356,8 +345,7 @@ class ISO639_5(str):
|
|||
def __get_pydantic_core_schema__(
|
||||
cls, _: type[Any], __: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the ISO 639-5 language code validation.
|
||||
"""Return a Pydantic CoreSchema with the ISO 639-5 language code validation.
|
||||
|
||||
Args:
|
||||
_: The source type.
|
||||
|
@ -376,8 +364,7 @@ class ISO639_5(str):
|
|||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Return a Pydantic JSON Schema with the ISO 639-5 language code validation.
|
||||
"""Return a Pydantic JSON Schema with the ISO 639-5 language code validation.
|
||||
|
||||
Args:
|
||||
schema: The Pydantic CoreSchema.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""
|
||||
The MAC address module provides functionality to parse and validate MAC addresses in different
|
||||
"""The MAC address module provides functionality to parse and validate MAC addresses in different
|
||||
formats, such as IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet format.
|
||||
"""
|
||||
|
||||
|
@ -24,16 +23,15 @@ class MacAddress(str):
|
|||
mac_address: MacAddress
|
||||
|
||||
|
||||
network = Network(mac_address="00:00:5e:00:53:01")
|
||||
network = Network(mac_address='00:00:5e:00:53:01')
|
||||
print(network)
|
||||
#> mac_address='00:00:5e:00:53:01'
|
||||
# > mac_address='00:00:5e:00:53:01'
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the MAC address validation.
|
||||
"""Return a Pydantic CoreSchema with the MAC address validation.
|
||||
|
||||
Args:
|
||||
source: The source type to be converted.
|
||||
|
@ -50,8 +48,7 @@ class MacAddress(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: Any) -> str:
|
||||
"""
|
||||
Validate a MAC Address from the provided str value.
|
||||
"""Validate a MAC Address from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -65,9 +62,7 @@ class MacAddress(str):
|
|||
|
||||
@staticmethod
|
||||
def validate_mac_address(value: bytes) -> str:
|
||||
"""
|
||||
Validate a MAC Address from the provided byte value.
|
||||
"""
|
||||
"""Validate a MAC Address from the provided byte value."""
|
||||
if len(value) < 14:
|
||||
raise PydanticCustomError(
|
||||
'mac_address_len',
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""
|
||||
The `pydantic_extra_types.payment` module provides the
|
||||
"""The `pydantic_extra_types.payment` module provides the
|
||||
[`PaymentCardNumber`][pydantic_extra_types.payment.PaymentCardNumber] data type.
|
||||
"""
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
"""
|
||||
Native Pendulum DateTime object implementation. This is a copy of the Pendulum DateTime object, but with a Pydantic
|
||||
"""Native Pendulum DateTime object implementation. This is a copy of the Pendulum DateTime object, but with a Pydantic
|
||||
CoreSchema implementation. This allows Pydantic to validate the DateTime object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
try:
|
||||
from pendulum import Date as _Date
|
||||
from pendulum import DateTime as _DateTime
|
||||
|
@ -13,7 +14,7 @@ except ModuleNotFoundError as e: # pragma: no cover
|
|||
'The `pendulum_dt` module requires "pendulum" to be installed. You can install it with "pip install pendulum".'
|
||||
) from e
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Any, List, Type
|
||||
from typing import Any
|
||||
|
||||
from pydantic import GetCoreSchemaHandler
|
||||
from pydantic_core import PydanticCustomError, core_schema
|
||||
|
@ -30,29 +31,29 @@ class DateTimeSettings(type):
|
|||
|
||||
|
||||
class DateTime(_DateTime, metaclass=DateTimeSettings):
|
||||
"""
|
||||
A `pendulum.DateTime` object. At runtime, this type decomposes into pendulum.DateTime automatically.
|
||||
"""A `pendulum.DateTime` object. At runtime, this type decomposes into pendulum.DateTime automatically.
|
||||
This type exists because Pydantic throws a fit on unknown types.
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from pydantic_extra_types.pendulum_dt import DateTime
|
||||
|
||||
|
||||
class test_model(BaseModel):
|
||||
dt: DateTime
|
||||
|
||||
|
||||
print(test_model(dt='2021-01-01T00:00:00+00:00'))
|
||||
|
||||
#> test_model(dt=DateTime(2021, 1, 1, 0, 0, 0, tzinfo=FixedTimezone(0, name="+00:00")))
|
||||
# > test_model(dt=DateTime(2021, 1, 1, 0, 0, 0, tzinfo=FixedTimezone(0, name="+00:00")))
|
||||
```
|
||||
"""
|
||||
|
||||
__slots__: List[str] = []
|
||||
__slots__: list[str] = []
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: Type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the Datetime validation
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""Return a Pydantic CoreSchema with the Datetime validation
|
||||
|
||||
Args:
|
||||
source: The source type to be converted.
|
||||
|
@ -64,9 +65,8 @@ class DateTime(_DateTime, metaclass=DateTimeSettings):
|
|||
return core_schema.no_info_wrap_validator_function(cls._validate, core_schema.datetime_schema())
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> 'DateTime':
|
||||
"""
|
||||
Validate the datetime object and return it.
|
||||
def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> DateTime:
|
||||
"""Validate the datetime object and return it.
|
||||
|
||||
Args:
|
||||
value: The value to validate.
|
||||
|
@ -96,29 +96,29 @@ class DateTime(_DateTime, metaclass=DateTimeSettings):
|
|||
|
||||
|
||||
class Date(_Date):
|
||||
"""
|
||||
A `pendulum.Date` object. At runtime, this type decomposes into pendulum.Date automatically.
|
||||
"""A `pendulum.Date` object. At runtime, this type decomposes into pendulum.Date automatically.
|
||||
This type exists because Pydantic throws a fit on unknown types.
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from pydantic_extra_types.pendulum_dt import Date
|
||||
|
||||
|
||||
class test_model(BaseModel):
|
||||
dt: Date
|
||||
|
||||
|
||||
print(test_model(dt='2021-01-01'))
|
||||
|
||||
#> test_model(dt=Date(2021, 1, 1))
|
||||
# > test_model(dt=Date(2021, 1, 1))
|
||||
```
|
||||
"""
|
||||
|
||||
__slots__: List[str] = []
|
||||
__slots__: list[str] = []
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: Type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the Date validation
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""Return a Pydantic CoreSchema with the Date validation
|
||||
|
||||
Args:
|
||||
source: The source type to be converted.
|
||||
|
@ -130,9 +130,8 @@ class Date(_Date):
|
|||
return core_schema.no_info_wrap_validator_function(cls._validate, core_schema.date_schema())
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> 'Date':
|
||||
"""
|
||||
Validate the date object and return it.
|
||||
def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> Date:
|
||||
"""Validate the date object and return it.
|
||||
|
||||
Args:
|
||||
value: The value to validate.
|
||||
|
@ -156,29 +155,29 @@ class Date(_Date):
|
|||
|
||||
|
||||
class Duration(_Duration):
|
||||
"""
|
||||
A `pendulum.Duration` object. At runtime, this type decomposes into pendulum.Duration automatically.
|
||||
"""A `pendulum.Duration` object. At runtime, this type decomposes into pendulum.Duration automatically.
|
||||
This type exists because Pydantic throws a fit on unknown types.
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from pydantic_extra_types.pendulum_dt import Duration
|
||||
|
||||
|
||||
class test_model(BaseModel):
|
||||
delta_t: Duration
|
||||
|
||||
|
||||
print(test_model(delta_t='P1DT25H'))
|
||||
|
||||
#> test_model(delta_t=Duration(days=2, hours=1))
|
||||
# > test_model(delta_t=Duration(days=2, hours=1))
|
||||
```
|
||||
"""
|
||||
|
||||
__slots__: List[str] = []
|
||||
__slots__: list[str] = []
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: Type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the Duration validation
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
"""Return a Pydantic CoreSchema with the Duration validation
|
||||
|
||||
Args:
|
||||
source: The source type to be converted.
|
||||
|
@ -190,9 +189,8 @@ class Duration(_Duration):
|
|||
return core_schema.no_info_wrap_validator_function(cls._validate, core_schema.timedelta_schema())
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> 'Duration':
|
||||
"""
|
||||
Validate the Duration object and return it.
|
||||
def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> Duration:
|
||||
"""Validate the Duration object and return it.
|
||||
|
||||
Args:
|
||||
value: The value to validate.
|
||||
|
@ -201,9 +199,25 @@ class Duration(_Duration):
|
|||
Returns:
|
||||
The validated value or raises a PydanticCustomError.
|
||||
"""
|
||||
# if we are passed an existing instance, pass it straight through.
|
||||
if isinstance(value, (_Duration, timedelta)):
|
||||
return Duration(seconds=value.total_seconds())
|
||||
|
||||
if isinstance(value, _Duration):
|
||||
return Duration(
|
||||
years=value.years,
|
||||
months=value.months,
|
||||
weeks=value.weeks,
|
||||
days=value.remaining_days,
|
||||
hours=value.hours,
|
||||
minutes=value.minutes,
|
||||
seconds=value.remaining_seconds,
|
||||
microseconds=value.microseconds,
|
||||
)
|
||||
|
||||
if isinstance(value, timedelta):
|
||||
return Duration(
|
||||
days=value.days,
|
||||
seconds=value.seconds,
|
||||
microseconds=value.microseconds,
|
||||
)
|
||||
|
||||
try:
|
||||
parsed = parse(value, exact=True)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""
|
||||
The `pydantic_extra_types.phone_numbers` module provides the
|
||||
"""The `pydantic_extra_types.phone_numbers` module provides the
|
||||
[`PhoneNumber`][pydantic_extra_types.phone_numbers.PhoneNumber] data type.
|
||||
|
||||
This class depends on the [phonenumbers] package, which is a Python port of Google's [libphonenumber].
|
||||
|
@ -7,40 +6,36 @@ This class depends on the [phonenumbers] package, which is a Python port of Goog
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, ClassVar, Generator
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import Any, ClassVar
|
||||
|
||||
from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler
|
||||
from pydantic_core import PydanticCustomError, core_schema
|
||||
|
||||
try:
|
||||
import phonenumbers
|
||||
from phonenumbers import PhoneNumber as BasePhoneNumber
|
||||
from phonenumbers.phonenumberutil import NumberParseException
|
||||
except ModuleNotFoundError as e: # pragma: no cover
|
||||
raise RuntimeError(
|
||||
'`PhoneNumber` requires "phonenumbers" to be installed. You can install it with "pip install phonenumbers"'
|
||||
) from e
|
||||
|
||||
GeneratorCallableStr = Generator[Callable[..., str], None, None]
|
||||
|
||||
|
||||
class PhoneNumber(str):
|
||||
"""
|
||||
A wrapper around [phonenumbers](https://pypi.org/project/phonenumbers/) package, which
|
||||
"""A wrapper around [phonenumbers](https://pypi.org/project/phonenumbers/) package, which
|
||||
is a Python port of Google's [libphonenumber](https://github.com/google/libphonenumber/).
|
||||
"""
|
||||
|
||||
supported_regions: list[str] = sorted(phonenumbers.SUPPORTED_REGIONS)
|
||||
"""The supported regions."""
|
||||
supported_formats: list[str] = sorted([f for f in phonenumbers.PhoneNumberFormat.__dict__.keys() if f.isupper()])
|
||||
"""The supported phone number formats."""
|
||||
supported_regions: list[str] = []
|
||||
"""The supported regions. If empty, all regions are supported."""
|
||||
|
||||
default_region_code: ClassVar[str | None] = None
|
||||
"""The default region code to use when parsing phone numbers without an international prefix."""
|
||||
phone_format: str = 'RFC3966'
|
||||
"""The format of the phone number."""
|
||||
min_length: int = 7
|
||||
"""The minimum length of the phone number."""
|
||||
max_length: int = 64
|
||||
"""The maximum length of the phone number."""
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(
|
||||
|
@ -54,7 +49,7 @@ class PhoneNumber(str):
|
|||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
return core_schema.with_info_after_validator_function(
|
||||
cls._validate,
|
||||
core_schema.str_schema(min_length=cls.min_length, max_length=cls.max_length),
|
||||
core_schema.str_schema(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -66,6 +61,12 @@ class PhoneNumber(str):
|
|||
if not phonenumbers.is_valid_number(parsed_number):
|
||||
raise PydanticCustomError('value_error', 'value is not a valid phone number')
|
||||
|
||||
if cls.supported_regions and not any(
|
||||
phonenumbers.is_valid_number_for_region(parsed_number, region_code=region)
|
||||
for region in cls.supported_regions
|
||||
):
|
||||
raise PydanticCustomError('value_error', 'value is not from a supported region')
|
||||
|
||||
return phonenumbers.format_number(parsed_number, getattr(phonenumbers.PhoneNumberFormat, cls.phone_format))
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
|
@ -73,3 +74,108 @@ class PhoneNumber(str):
|
|||
|
||||
def __hash__(self) -> int:
|
||||
return super().__hash__()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PhoneNumberValidator:
|
||||
"""A pydantic before validator for phone numbers using the [phonenumbers](https://pypi.org/project/phonenumbers/) package,
|
||||
a Python port of Google's [libphonenumber](https://github.com/google/libphonenumber/).
|
||||
|
||||
Intended to be used to create custom pydantic data types using the `typing.Annotated` type construct.
|
||||
|
||||
Args:
|
||||
default_region (str | None): The default region code to use when parsing phone numbers without an international prefix.
|
||||
If `None` (default), the region must be supplied in the phone number as an international prefix.
|
||||
number_format (str): The format of the phone number to return. See `phonenumbers.PhoneNumberFormat` for valid values.
|
||||
supported_regions (list[str]): The supported regions. If empty, all regions are supported (default).
|
||||
|
||||
Returns:
|
||||
The formatted phone number.
|
||||
|
||||
Example:
|
||||
MyNumberType = Annotated[
|
||||
Union[str, phonenumbers.PhoneNumber],
|
||||
PhoneNumberValidator()
|
||||
]
|
||||
USNumberType = Annotated[
|
||||
Union[str, phonenumbers.PhoneNumber],
|
||||
PhoneNumberValidator(supported_regions=['US'], default_region='US')
|
||||
]
|
||||
|
||||
class SomeModel(BaseModel):
|
||||
phone_number: MyNumberType
|
||||
us_number: USNumberType
|
||||
"""
|
||||
|
||||
default_region: str | None = None
|
||||
number_format: str = 'RFC3966'
|
||||
supported_regions: Sequence[str] | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.default_region and self.default_region not in phonenumbers.SUPPORTED_REGIONS:
|
||||
raise ValueError(f'Invalid default region code: {self.default_region}')
|
||||
|
||||
if self.number_format not in (
|
||||
number_format
|
||||
for number_format in dir(phonenumbers.PhoneNumberFormat)
|
||||
if not number_format.startswith('_') and number_format.isupper()
|
||||
):
|
||||
raise ValueError(f'Invalid number format: {self.number_format}')
|
||||
|
||||
if self.supported_regions:
|
||||
for supported_region in self.supported_regions:
|
||||
if supported_region not in phonenumbers.SUPPORTED_REGIONS:
|
||||
raise ValueError(f'Invalid supported region code: {supported_region}')
|
||||
|
||||
@staticmethod
|
||||
def _parse(
|
||||
region: str | None,
|
||||
number_format: str,
|
||||
supported_regions: Sequence[str] | None,
|
||||
phone_number: Any,
|
||||
) -> str:
|
||||
if not phone_number:
|
||||
raise PydanticCustomError('value_error', 'value is not a valid phone number')
|
||||
|
||||
if not isinstance(phone_number, (str, BasePhoneNumber)):
|
||||
raise PydanticCustomError('value_error', 'value is not a valid phone number')
|
||||
|
||||
parsed_number = None
|
||||
if isinstance(phone_number, BasePhoneNumber):
|
||||
parsed_number = phone_number
|
||||
else:
|
||||
try:
|
||||
parsed_number = phonenumbers.parse(phone_number, region=region)
|
||||
except NumberParseException as exc:
|
||||
raise PydanticCustomError('value_error', 'value is not a valid phone number') from exc
|
||||
|
||||
if not phonenumbers.is_valid_number(parsed_number):
|
||||
raise PydanticCustomError('value_error', 'value is not a valid phone number')
|
||||
|
||||
if supported_regions and not any(
|
||||
phonenumbers.is_valid_number_for_region(parsed_number, region_code=region) for region in supported_regions
|
||||
):
|
||||
raise PydanticCustomError('value_error', 'value is not from a supported region')
|
||||
|
||||
return phonenumbers.format_number(parsed_number, getattr(phonenumbers.PhoneNumberFormat, number_format))
|
||||
|
||||
def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
return core_schema.no_info_before_validator_function(
|
||||
partial(
|
||||
self._parse,
|
||||
self.default_region,
|
||||
self.number_format,
|
||||
self.supported_regions,
|
||||
),
|
||||
core_schema.str_schema(),
|
||||
)
|
||||
|
||||
def __get_pydantic_json_schema__(
|
||||
self, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
json_schema = handler(schema)
|
||||
json_schema.update({'format': 'phone'})
|
||||
return json_schema
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return super().__hash__()
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
"""
|
||||
The `pydantic_extra_types.routing_number` module provides the
|
||||
"""The `pydantic_extra_types.routing_number` module provides the
|
||||
[`ABARoutingNumber`][pydantic_extra_types.routing_number.ABARoutingNumber] data type.
|
||||
"""
|
||||
|
||||
from typing import Any, ClassVar, Type
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, ClassVar
|
||||
|
||||
from pydantic import GetCoreSchemaHandler
|
||||
from pydantic_core import PydanticCustomError, core_schema
|
||||
|
@ -21,12 +22,14 @@ class ABARoutingNumber(str):
|
|||
|
||||
from pydantic_extra_types.routing_number import ABARoutingNumber
|
||||
|
||||
|
||||
class BankAccount(BaseModel):
|
||||
routing_number: ABARoutingNumber
|
||||
|
||||
|
||||
account = BankAccount(routing_number='122105155')
|
||||
print(account)
|
||||
#> routing_number='122105155'
|
||||
# > routing_number='122105155'
|
||||
```
|
||||
"""
|
||||
|
||||
|
@ -40,7 +43,7 @@ class ABARoutingNumber(str):
|
|||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(
|
||||
cls, source: Type[Any], handler: GetCoreSchemaHandler
|
||||
cls, source: type[Any], handler: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
return core_schema.with_info_after_validator_function(
|
||||
cls._validate,
|
||||
|
@ -53,7 +56,7 @@ class ABARoutingNumber(str):
|
|||
)
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> 'ABARoutingNumber':
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> ABARoutingNumber:
|
||||
return cls(__input_value)
|
||||
|
||||
@classmethod
|
||||
|
|
69
pydantic_extra_types/s3.py
Normal file
69
pydantic_extra_types/s3.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
"""The `pydantic_extra_types.s3` module provides the
|
||||
[`S3Path`][pydantic_extra_types.s3.S3Path] data type.
|
||||
|
||||
A simpleAWS S3 URLs parser.
|
||||
It also provides the `Bucket`, `Key` component.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any, ClassVar
|
||||
|
||||
from pydantic import GetCoreSchemaHandler
|
||||
from pydantic_core import core_schema
|
||||
|
||||
|
||||
class S3Path(str):
|
||||
"""An object representing a valid S3 path.
|
||||
This type also allows you to access the `bucket` and `key` component of the S3 path.
|
||||
It also contains the `last_key` which represents the last part of the path (tipically a file).
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from pydantic_extra_types.s3 import S3Path
|
||||
|
||||
|
||||
class TestModel(BaseModel):
|
||||
path: S3Path
|
||||
|
||||
|
||||
p = 's3://my-data-bucket/2023/08/29/sales-report.csv'
|
||||
model = TestModel(path=p)
|
||||
model
|
||||
|
||||
# > TestModel(path=S3Path('s3://my-data-bucket/2023/08/29/sales-report.csv'))
|
||||
|
||||
model.path.bucket
|
||||
|
||||
# > 'my-data-bucket'
|
||||
```
|
||||
"""
|
||||
|
||||
patt: ClassVar[str] = r'^s3://([^/]+)/(.*?([^/]+)/?)$'
|
||||
|
||||
def __init__(self, value: str) -> None:
|
||||
self.value = value
|
||||
groups: tuple[str, str, str] = re.match(self.patt, self.value).groups() # type: ignore
|
||||
self.bucket: str = groups[0]
|
||||
self.key: str = groups[1]
|
||||
self.last_key: str = groups[2]
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover
|
||||
return self.value
|
||||
|
||||
def __repr__(self) -> str: # pragma: no cover
|
||||
return f'{self.__class__.__name__}({self.value!r})'
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> S3Path:
|
||||
return cls(__input_value)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
|
||||
_, _ = source, handler
|
||||
return core_schema.with_info_after_validator_function(
|
||||
cls._validate,
|
||||
core_schema.str_schema(pattern=cls.patt),
|
||||
field_name=cls.__class__.__name__,
|
||||
)
|
|
@ -1,6 +1,4 @@
|
|||
"""
|
||||
script definitions that are based on the [ISO 15924](https://en.wikipedia.org/wiki/ISO_15924)
|
||||
"""
|
||||
"""script definitions that are based on the [ISO 15924](https://en.wikipedia.org/wiki/ISO_15924)"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
@ -27,9 +25,11 @@ class ISO_15924(str):
|
|||
|
||||
from pydantic_extra_types.language_code import ISO_15924
|
||||
|
||||
|
||||
class Script(BaseModel):
|
||||
alpha_4: ISO_15924
|
||||
|
||||
|
||||
script = Script(alpha_4='Java')
|
||||
print(lang)
|
||||
# > script='Java'
|
||||
|
@ -41,8 +41,7 @@ class ISO_15924(str):
|
|||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> ISO_15924:
|
||||
"""
|
||||
Validate a ISO 15924 language code from the provided str value.
|
||||
"""Validate a ISO 15924 language code from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
|
@ -64,8 +63,7 @@ class ISO_15924(str):
|
|||
def __get_pydantic_core_schema__(
|
||||
cls, _: type[Any], __: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
"""
|
||||
Return a Pydantic CoreSchema with the ISO 639-3 language code validation.
|
||||
"""Return a Pydantic CoreSchema with the ISO 639-3 language code validation.
|
||||
|
||||
Args:
|
||||
_: The source type.
|
||||
|
@ -84,8 +82,7 @@ class ISO_15924(str):
|
|||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Return a Pydantic JSON Schema with the ISO 639-3 language code validation.
|
||||
"""Return a Pydantic JSON Schema with the ISO 639-3 language code validation.
|
||||
|
||||
Args:
|
||||
schema: The Pydantic CoreSchema.
|
||||
|
|
59
pydantic_extra_types/semantic_version.py
Normal file
59
pydantic_extra_types/semantic_version.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
"""SemanticVersion definition that is based on the Semantiv Versioning Specification [semver](https://semver.org/)."""
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
from pydantic import GetJsonSchemaHandler
|
||||
from pydantic.json_schema import JsonSchemaValue
|
||||
from pydantic_core import core_schema
|
||||
|
||||
try:
|
||||
import semver
|
||||
except ModuleNotFoundError as e: # pragma: no cover
|
||||
raise RuntimeError(
|
||||
'The `semantic_version` module requires "semver" to be installed. You can install it with "pip install semver".'
|
||||
) from e
|
||||
|
||||
|
||||
class SemanticVersion(semver.Version):
|
||||
"""Semantic version based on the official [semver thread](https://python-semver.readthedocs.io/en/latest/advanced/combine-pydantic-and-semver.html)."""
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(
|
||||
cls,
|
||||
_source_type: Any,
|
||||
_handler: Callable[[Any], core_schema.CoreSchema],
|
||||
) -> core_schema.CoreSchema:
|
||||
def validate_from_str(value: str) -> SemanticVersion:
|
||||
return cls.parse(value)
|
||||
|
||||
from_str_schema = core_schema.chain_schema(
|
||||
[
|
||||
core_schema.str_schema(),
|
||||
core_schema.no_info_plain_validator_function(validate_from_str),
|
||||
]
|
||||
)
|
||||
|
||||
return core_schema.json_or_python_schema(
|
||||
json_schema=from_str_schema,
|
||||
python_schema=core_schema.union_schema(
|
||||
[
|
||||
core_schema.is_instance_schema(semver.Version),
|
||||
from_str_schema,
|
||||
]
|
||||
),
|
||||
serialization=core_schema.to_string_ser_schema(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(
|
||||
cls, _core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> JsonSchemaValue:
|
||||
return handler(
|
||||
core_schema.str_schema(
|
||||
pattern=r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def validate_from_str(cls, value: str) -> 'SemanticVersion':
|
||||
return cls.parse(value)
|
77
pydantic_extra_types/semver.py
Normal file
77
pydantic_extra_types/semver.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
"""The _VersionPydanticAnnotation class provides functionality to parse and validate Semantic Versioning (SemVer) strings.
|
||||
|
||||
This class depends on the [semver](https://python-semver.readthedocs.io/en/latest/index.html) package.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Callable
|
||||
|
||||
from pydantic import GetJsonSchemaHandler
|
||||
from pydantic.json_schema import JsonSchemaValue
|
||||
from pydantic_core import core_schema
|
||||
from semver import Version
|
||||
from typing_extensions import Annotated
|
||||
|
||||
warnings.warn(
|
||||
'Use from pydantic_extra_types.semver import SemanticVersion instead. Will be removed in 3.0.0.', DeprecationWarning
|
||||
)
|
||||
|
||||
|
||||
class _VersionPydanticAnnotation(Version):
|
||||
"""Represents a Semantic Versioning (SemVer).
|
||||
|
||||
Wraps the `version` type from `semver`.
|
||||
|
||||
Example:
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pydantic_extra_types.semver import _VersionPydanticAnnotation
|
||||
|
||||
|
||||
class appVersion(BaseModel):
|
||||
version: _VersionPydanticAnnotation
|
||||
|
||||
|
||||
app_version = appVersion(version='1.2.3')
|
||||
|
||||
print(app_version.version)
|
||||
# > 1.2.3
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(
|
||||
cls,
|
||||
_source_type: Any,
|
||||
_handler: Callable[[Any], core_schema.CoreSchema],
|
||||
) -> core_schema.CoreSchema:
|
||||
def validate_from_str(value: str) -> Version:
|
||||
return Version.parse(value)
|
||||
|
||||
from_str_schema = core_schema.chain_schema(
|
||||
[
|
||||
core_schema.str_schema(),
|
||||
core_schema.no_info_plain_validator_function(validate_from_str),
|
||||
]
|
||||
)
|
||||
|
||||
return core_schema.json_or_python_schema(
|
||||
json_schema=from_str_schema,
|
||||
python_schema=core_schema.union_schema(
|
||||
[
|
||||
core_schema.is_instance_schema(Version),
|
||||
from_str_schema,
|
||||
]
|
||||
),
|
||||
serialization=core_schema.to_string_ser_schema(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(
|
||||
cls, _core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> JsonSchemaValue:
|
||||
return handler(core_schema.str_schema())
|
||||
|
||||
|
||||
ManifestVersion = Annotated[Version, _VersionPydanticAnnotation]
|
183
pydantic_extra_types/timezone_name.py
Normal file
183
pydantic_extra_types/timezone_name.py
Normal file
|
@ -0,0 +1,183 @@
|
|||
"""Time zone name validation and serialization module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
import warnings
|
||||
from typing import Any, Callable, cast
|
||||
|
||||
from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler
|
||||
from pydantic_core import PydanticCustomError, core_schema
|
||||
|
||||
|
||||
def _is_available(name: str) -> bool:
|
||||
"""Check if a module is available for import."""
|
||||
try:
|
||||
importlib.import_module(name)
|
||||
return True
|
||||
except ModuleNotFoundError: # pragma: no cover
|
||||
return False
|
||||
|
||||
|
||||
def _tz_provider_from_zone_info() -> set[str]: # pragma: no cover
|
||||
"""Get timezones from the zoneinfo module."""
|
||||
from zoneinfo import available_timezones
|
||||
|
||||
return set(available_timezones())
|
||||
|
||||
|
||||
def _tz_provider_from_pytz() -> set[str]: # pragma: no cover
|
||||
"""Get timezones from the pytz module."""
|
||||
from pytz import all_timezones
|
||||
|
||||
return set(all_timezones)
|
||||
|
||||
|
||||
def _warn_about_pytz_usage() -> None:
|
||||
"""Warn about using pytz with Python 3.9 or later."""
|
||||
warnings.warn( # pragma: no cover
|
||||
'Projects using Python 3.9 or later should be using the support now included as part of the standard library. '
|
||||
'Please consider switching to the standard library (zoneinfo) module.'
|
||||
)
|
||||
|
||||
|
||||
def get_timezones() -> set[str]:
|
||||
"""Determine the timezone provider and return available timezones."""
|
||||
if _is_available('zoneinfo') and _is_available('tzdata'): # pragma: no cover
|
||||
return _tz_provider_from_zone_info()
|
||||
elif _is_available('pytz'): # pragma: no cover
|
||||
return _tz_provider_from_pytz()
|
||||
else: # pragma: no cover
|
||||
if sys.version_info[:2] == (3, 8):
|
||||
raise ImportError('No pytz module found. Please install it with "pip install pytz"')
|
||||
raise ImportError('No timezone provider found. Please install tzdata with "pip install tzdata"')
|
||||
|
||||
|
||||
class TimeZoneNameSettings(type):
|
||||
def __new__(cls, name: str, bases: tuple[type, ...], dct: dict[str, Any], **kwargs: Any) -> type[TimeZoneName]:
|
||||
dct['strict'] = kwargs.pop('strict', True)
|
||||
return cast('type[TimeZoneName]', super().__new__(cls, name, bases, dct))
|
||||
|
||||
def __init__(cls, name: str, bases: tuple[type, ...], dct: dict[str, Any], **kwargs: Any) -> None:
|
||||
super().__init__(name, bases, dct)
|
||||
cls.strict = kwargs.get('strict', True)
|
||||
|
||||
|
||||
def timezone_name_settings(**kwargs: Any) -> Callable[[type[TimeZoneName]], type[TimeZoneName]]:
|
||||
def wrapper(cls: type[TimeZoneName]) -> type[TimeZoneName]:
|
||||
cls.strict = kwargs.get('strict', True)
|
||||
return cls
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@timezone_name_settings(strict=True)
|
||||
class TimeZoneName(str):
|
||||
"""TimeZoneName is a custom string subclass for validating and serializing timezone names.
|
||||
|
||||
The TimeZoneName class uses the IANA Time Zone Database for validation.
|
||||
It supports both strict and non-strict modes for timezone name validation.
|
||||
|
||||
|
||||
## Examples:
|
||||
|
||||
Some examples of using the TimeZoneName class:
|
||||
|
||||
### Normal usage:
|
||||
|
||||
```python
|
||||
from pydantic_extra_types.timezone_name import TimeZoneName
|
||||
from pydantic import BaseModel
|
||||
class Location(BaseModel):
|
||||
city: str
|
||||
timezone: TimeZoneName
|
||||
|
||||
loc = Location(city="New York", timezone="America/New_York")
|
||||
print(loc.timezone)
|
||||
|
||||
>> America/New_York
|
||||
|
||||
```
|
||||
|
||||
### Non-strict mode:
|
||||
|
||||
```python
|
||||
|
||||
from pydantic_extra_types.timezone_name import TimeZoneName, timezone_name_settings
|
||||
|
||||
@timezone_name_settings(strict=False)
|
||||
class TZNonStrict(TimeZoneName):
|
||||
pass
|
||||
|
||||
tz = TZNonStrict("america/new_york")
|
||||
|
||||
print(tz)
|
||||
|
||||
>> america/new_york
|
||||
|
||||
```
|
||||
"""
|
||||
|
||||
__slots__: list[str] = []
|
||||
allowed_values: set[str] = set(get_timezones())
|
||||
allowed_values_list: list[str] = sorted(allowed_values)
|
||||
allowed_values_upper_to_correct: dict[str, str] = {val.upper(): val for val in allowed_values}
|
||||
strict: bool
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> TimeZoneName:
|
||||
"""Validate a time zone name from the provided str value.
|
||||
|
||||
Args:
|
||||
__input_value: The str value to be validated.
|
||||
_: The Pydantic ValidationInfo.
|
||||
|
||||
Returns:
|
||||
The validated time zone name.
|
||||
|
||||
Raises:
|
||||
PydanticCustomError: If the timezone name is not valid.
|
||||
"""
|
||||
if __input_value not in cls.allowed_values: # be fast for the most common case
|
||||
if not cls.strict:
|
||||
upper_value = __input_value.strip().upper()
|
||||
if upper_value in cls.allowed_values_upper_to_correct:
|
||||
return cls(cls.allowed_values_upper_to_correct[upper_value])
|
||||
raise PydanticCustomError('TimeZoneName', 'Invalid timezone name.')
|
||||
return cls(__input_value)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(
|
||||
cls, _: type[Any], __: GetCoreSchemaHandler
|
||||
) -> core_schema.AfterValidatorFunctionSchema:
|
||||
"""Return a Pydantic CoreSchema with the timezone name validation.
|
||||
|
||||
Args:
|
||||
_: The source type.
|
||||
__: The handler to get the CoreSchema.
|
||||
|
||||
Returns:
|
||||
A Pydantic CoreSchema with the timezone name validation.
|
||||
"""
|
||||
return core_schema.with_info_after_validator_function(
|
||||
cls._validate,
|
||||
core_schema.str_schema(min_length=1),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(
|
||||
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
|
||||
) -> dict[str, Any]:
|
||||
"""Return a Pydantic JSON Schema with the timezone name validation.
|
||||
|
||||
Args:
|
||||
schema: The Pydantic CoreSchema.
|
||||
handler: The handler to get the JSON Schema.
|
||||
|
||||
Returns:
|
||||
A Pydantic JSON Schema with the timezone name validation.
|
||||
"""
|
||||
json_schema = handler(schema)
|
||||
json_schema.update({'enum': cls.allowed_values_list})
|
||||
return json_schema
|
|
@ -1,5 +1,4 @@
|
|||
"""
|
||||
The `pydantic_extra_types.ULID` module provides the [`ULID`] data type.
|
||||
"""The `pydantic_extra_types.ULID` module provides the [`ULID`] data type.
|
||||
|
||||
This class depends on the [python-ulid] package, which is a validate by the [ULID-spec](https://github.com/ulid/spec#implementations-in-other-languages).
|
||||
"""
|
||||
|
@ -25,8 +24,7 @@ UlidType = Union[str, bytes, int]
|
|||
|
||||
@dataclass
|
||||
class ULID(_repr.Representation):
|
||||
"""
|
||||
A wrapper around [python-ulid](https://pypi.org/project/python-ulid/) package, which
|
||||
"""A wrapper around [python-ulid](https://pypi.org/project/python-ulid/) package, which
|
||||
is a validate by the [ULID-spec](https://github.com/ulid/spec#implementations-in-other-languages).
|
||||
"""
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ path = 'pydantic_extra_types/__init__.py'
|
|||
name = 'pydantic-extra-types'
|
||||
description = 'Extra Pydantic types.'
|
||||
authors = [
|
||||
{name = 'Samuel Colvin', email = 's@muelcolvin.com'},
|
||||
{name = 'Yasser Tahiri', email = 'hello@yezz.me'},
|
||||
{ name = 'Samuel Colvin', email = 's@muelcolvin.com' },
|
||||
{ name = 'Yasser Tahiri', email = 'hello@yezz.me' },
|
||||
]
|
||||
license = 'MIT'
|
||||
readme = 'README.md'
|
||||
|
@ -24,6 +24,7 @@ classifiers = [
|
|||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Programming Language :: Python :: 3.12',
|
||||
'Programming Language :: Python :: 3.13',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
|
@ -38,27 +39,48 @@ classifiers = [
|
|||
'Topic :: Internet',
|
||||
]
|
||||
requires-python = '>=3.8'
|
||||
dependencies = [
|
||||
'pydantic>=2.5.2',
|
||||
]
|
||||
dependencies = ['pydantic>=2.5.2','typing-extensions']
|
||||
dynamic = ['version']
|
||||
|
||||
[project.optional-dependencies]
|
||||
all = [
|
||||
'phonenumbers>=8,<9',
|
||||
'pycountry>=23',
|
||||
'semver>=3.0.2',
|
||||
'python-ulid>=1,<2; python_version<"3.9"',
|
||||
'python-ulid>=1,<3; python_version>="3.9"',
|
||||
'pendulum>=3.0.0,<4.0.0'
|
||||
'python-ulid>=1,<4; python_version>="3.9"',
|
||||
'pendulum>=3.0.0,<4.0.0',
|
||||
'pytz>=2024.1',
|
||||
'semver~=3.0.2',
|
||||
'tzdata>=2024.1',
|
||||
]
|
||||
phonenumbers = ['phonenumbers>=8,<9']
|
||||
pycountry = ['pycountry>=23']
|
||||
semver = ['semver>=3.0.2']
|
||||
python_ulid = [
|
||||
'python-ulid>=1,<2; python_version<"3.9"',
|
||||
'python-ulid>=1,<3; python_version>="3.9"',
|
||||
'python-ulid>=1,<4; python_version>="3.9"',
|
||||
]
|
||||
pendulum = ['pendulum>=3.0.0,<4.0.0']
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"coverage[toml]>=7.6.1",
|
||||
"pytest-pretty>=1.2.0",
|
||||
"dirty-equals>=0.7.1",
|
||||
"pytest>=8.3.2",
|
||||
]
|
||||
lint = [
|
||||
"ruff>=0.7.4",
|
||||
"mypy>=0.910",
|
||||
"annotated-types>=0.7.0",
|
||||
"types-pytz>=2024.1.0.20240417",
|
||||
]
|
||||
extra = [
|
||||
{ include-group = 'dev' },
|
||||
{ include-group = 'lint' },
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = 'https://github.com/pydantic/pydantic-extra-types'
|
||||
Source = 'https://github.com/pydantic/pydantic-extra-types'
|
||||
|
@ -73,14 +95,21 @@ line-length = 120
|
|||
target-version = 'py38'
|
||||
|
||||
[tool.ruff.lint]
|
||||
extend-select = ['Q', 'RUF100', 'C90', 'UP', 'I']
|
||||
flake8-quotes = {inline-quotes = 'single', multiline-quotes = 'double'}
|
||||
isort = { known-first-party = ['pydantic_extra_types', 'tests'] }
|
||||
extend-select = [
|
||||
"Q",
|
||||
"RUF100",
|
||||
"C90",
|
||||
"UP",
|
||||
"I",
|
||||
]
|
||||
flake8-quotes = { inline-quotes = 'single', multiline-quotes = 'double' }
|
||||
isort = {known-first-party = ['pydantic_extra_types', 'tests'] }
|
||||
mccabe = { max-complexity = 14 }
|
||||
pydocstyle = { convention = 'google' }
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = 'single'
|
||||
docstring-code-format = true
|
||||
quote-style = "single"
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
'pydantic_extra_types/color.py' = ['E741']
|
||||
|
@ -109,7 +138,6 @@ exclude_lines = [
|
|||
'@overload',
|
||||
]
|
||||
|
||||
|
||||
[tool.mypy]
|
||||
strict = true
|
||||
plugins = 'pydantic.mypy'
|
||||
|
@ -120,7 +148,8 @@ filterwarnings = [
|
|||
# This ignore will be removed when pycountry will drop py36 & support py311
|
||||
'ignore:::pkg_resources',
|
||||
# This ignore will be removed when pendulum fixes https://github.com/sdispater/pendulum/issues/834
|
||||
'ignore:datetime.datetime.utcfromtimestamp.*:DeprecationWarning'
|
||||
'ignore:datetime.datetime.utcfromtimestamp.*:DeprecationWarning',
|
||||
' ignore:Use from pydantic_extra_types.semver import SemanticVersion instead. Will be removed in 3.0.0.:DeprecationWarning'
|
||||
]
|
||||
|
||||
# configuring https://github.com/pydantic/hooky
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
-r ./pyproject.txt
|
||||
-r ./linting.txt
|
||||
-r ./testing.txt
|
|
@ -1,4 +0,0 @@
|
|||
pre-commit
|
||||
mypy
|
||||
annotated-types
|
||||
ruff
|
|
@ -1,37 +0,0 @@
|
|||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/linting.txt requirements/linting.in
|
||||
#
|
||||
annotated-types==0.7.0
|
||||
# via -r requirements/linting.in
|
||||
cfgv==3.4.0
|
||||
# via pre-commit
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.13.1
|
||||
# via virtualenv
|
||||
identify==2.5.35
|
||||
# via pre-commit
|
||||
mypy==1.10.0
|
||||
# via -r requirements/linting.in
|
||||
mypy-extensions==1.0.0
|
||||
# via mypy
|
||||
nodeenv==1.8.0
|
||||
# via pre-commit
|
||||
platformdirs==4.2.0
|
||||
# via virtualenv
|
||||
pre-commit==3.7.1
|
||||
# via -r requirements/linting.in
|
||||
pyyaml==6.0.1
|
||||
# via pre-commit
|
||||
ruff==0.4.7
|
||||
# via -r requirements/linting.in
|
||||
typing-extensions==4.10.0
|
||||
# via mypy
|
||||
virtualenv==20.25.1
|
||||
# via pre-commit
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
# setuptools
|
|
@ -1,34 +0,0 @@
|
|||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile --extra=all --no-emit-index-url --output-file=requirements/pyproject.txt pyproject.toml
|
||||
#
|
||||
annotated-types==0.7.0
|
||||
# via pydantic
|
||||
pendulum==3.0.0
|
||||
# via pydantic-extra-types (pyproject.toml)
|
||||
phonenumbers==8.13.31
|
||||
# via pydantic-extra-types (pyproject.toml)
|
||||
pycountry==23.12.11
|
||||
# via pydantic-extra-types (pyproject.toml)
|
||||
pydantic==2.6.3
|
||||
# via pydantic-extra-types (pyproject.toml)
|
||||
pydantic-core==2.16.3
|
||||
# via pydantic
|
||||
python-dateutil==2.8.2
|
||||
# via
|
||||
# pendulum
|
||||
# time-machine
|
||||
python-ulid==1.1.0
|
||||
# via pydantic-extra-types (pyproject.toml)
|
||||
six==1.16.0
|
||||
# via python-dateutil
|
||||
time-machine==2.13.0
|
||||
# via pendulum
|
||||
typing-extensions==4.10.0
|
||||
# via
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
tzdata==2024.1
|
||||
# via pendulum
|
|
@ -1,6 +0,0 @@
|
|||
dirty-equals
|
||||
coverage[toml]
|
||||
pytest
|
||||
codecov
|
||||
pytest-cov
|
||||
pytest-pretty
|
|
@ -1,50 +0,0 @@
|
|||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile --no-emit-index-url --output-file=requirements/testing.txt requirements/testing.in
|
||||
#
|
||||
certifi==2024.2.2
|
||||
# via requests
|
||||
charset-normalizer==3.3.2
|
||||
# via requests
|
||||
codecov==2.1.13
|
||||
# via -r requirements/testing.in
|
||||
coverage[toml]==7.5.3
|
||||
# via
|
||||
# -r requirements/testing.in
|
||||
# codecov
|
||||
# pytest-cov
|
||||
dirty-equals==0.7.1.post0
|
||||
# via -r requirements/testing.in
|
||||
idna==3.6
|
||||
# via requests
|
||||
iniconfig==2.0.0
|
||||
# via pytest
|
||||
markdown-it-py==3.0.0
|
||||
# via rich
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
packaging==23.2
|
||||
# via pytest
|
||||
pluggy==1.5.0
|
||||
# via pytest
|
||||
pygments==2.17.2
|
||||
# via rich
|
||||
pytest==8.2.1
|
||||
# via
|
||||
# -r requirements/testing.in
|
||||
# pytest-cov
|
||||
# pytest-pretty
|
||||
pytest-cov==5.0.0
|
||||
# via -r requirements/testing.in
|
||||
pytest-pretty==1.2.0
|
||||
# via -r requirements/testing.in
|
||||
pytz==2024.1
|
||||
# via dirty-equals
|
||||
requests==2.31.0
|
||||
# via codecov
|
||||
rich==13.7.0
|
||||
# via pytest-pretty
|
||||
urllib3==2.2.1
|
||||
# via requests
|
|
@ -189,7 +189,7 @@ def test_json_schema():
|
|||
'type': 'object',
|
||||
}
|
||||
},
|
||||
'properties': {'value': {'allOf': [{'$ref': '#/$defs/Coordinate'}], 'title': 'Value'}},
|
||||
'properties': {'value': {'$ref': '#/$defs/Coordinate', 'title': 'Value'}},
|
||||
'required': ['value'],
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
|
|
|
@ -25,6 +25,12 @@ def test_ISO4217_code_ok(currency: str):
|
|||
assert model.model_dump() == {'currency': currency} # test serialization
|
||||
|
||||
|
||||
@pytest.mark.parametrize('currency', ['USD', 'usd', 'UsD'])
|
||||
def test_ISO4217_code_ok_lower_case(currency: str):
|
||||
model = ISO4217CheckingModel(currency=currency)
|
||||
assert model.currency == currency.upper()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'currency',
|
||||
filter(
|
||||
|
@ -38,6 +44,12 @@ def test_everyday_code_ok(currency: str):
|
|||
assert model.model_dump() == {'currency': currency} # test serialization
|
||||
|
||||
|
||||
@pytest.mark.parametrize('currency', ['USD', 'usd', 'UsD'])
|
||||
def test_everyday_code_ok_lower_case(currency: str):
|
||||
model = CurrencyCheckingModel(currency=currency)
|
||||
assert model.currency == currency.upper()
|
||||
|
||||
|
||||
def test_ISO4217_fails():
|
||||
with pytest.raises(
|
||||
ValidationError,
|
||||
|
@ -56,7 +68,7 @@ def test_forbidden_everyday(forbidden_currency):
|
|||
ValidationError,
|
||||
match=re.escape(
|
||||
'1 validation error for CurrencyCheckingModel\ncurrency\n '
|
||||
'Invalid currency code. See https://en.wikipedia.org/wiki/ISO_4217. '
|
||||
'Invalid currency code. See https://en.wikipedia.org/wiki/ISO_4217 . '
|
||||
'Bonds, testing and precious metals codes are not allowed. '
|
||||
f"[type=InvalidCurrency, input_value='{forbidden_currency}', input_type=str]"
|
||||
),
|
||||
|
|
76
tests/test_domain.py
Normal file
76
tests/test_domain.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
from pydantic_extra_types.domain import DomainStr
|
||||
|
||||
|
||||
class MyModel(BaseModel):
|
||||
domain: DomainStr
|
||||
|
||||
|
||||
valid_domains = [
|
||||
'example.com',
|
||||
'sub.example.com',
|
||||
'sub-domain.example-site.co.uk',
|
||||
'a.com',
|
||||
'x.com',
|
||||
'1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.com', # Multiple subdomains
|
||||
]
|
||||
|
||||
invalid_domains = [
|
||||
'', # Empty string
|
||||
'example', # Missing TLD
|
||||
'.com', # Missing domain name
|
||||
'example.', # Trailing dot
|
||||
'exam ple.com', # Space in domain
|
||||
'exa_mple.com', # Underscore in domain
|
||||
'example.com.', # Trailing dot
|
||||
]
|
||||
|
||||
very_long_domains = [
|
||||
'a' * 249 + '.com', # Just under the limit
|
||||
'a' * 250 + '.com', # At the limit
|
||||
'a' * 251 + '.com', # Just over the limit
|
||||
'sub1.sub2.sub3.sub4.sub5.sub6.sub7.sub8.sub9.sub10.sub11.sub12.sub13.sub14.sub15.sub16.sub17.sub18.sub19.sub20.sub21.sub22.sub23.sub24.sub25.sub26.sub27.sub28.sub29.sub30.sub31.sub32.sub33.extremely-long-domain-name-example-to-test-the-253-character-limit.com',
|
||||
]
|
||||
|
||||
invalid_domain_types = [1, 2, 1.1, 2.1, False, [], {}, None]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('domain', valid_domains)
|
||||
def test_valid_domains(domain: str):
|
||||
try:
|
||||
MyModel.model_validate({'domain': domain})
|
||||
assert len(domain) < 254 and len(domain) > 0
|
||||
except ValidationError:
|
||||
assert len(domain) > 254 or len(domain) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('domain', invalid_domains)
|
||||
def test_invalid_domains(domain: str):
|
||||
try:
|
||||
MyModel.model_validate({'domain': domain})
|
||||
raise Exception(
|
||||
f"This test case has only samples that should raise a ValidationError. This domain '{domain}' did not raise such an exception."
|
||||
)
|
||||
except ValidationError:
|
||||
# An error is expected on this test
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize('domain', very_long_domains)
|
||||
def test_very_long_domains(domain: str):
|
||||
try:
|
||||
MyModel.model_validate({'domain': domain})
|
||||
assert len(domain) < 254 and len(domain) > 0
|
||||
except ValidationError:
|
||||
# An error is expected on this test
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize('domain', invalid_domain_types)
|
||||
def test_invalid_domain_types(domain: Any):
|
||||
with pytest.raises(ValidationError, match='Value must be a string'):
|
||||
MyModel(domain=domain)
|
39
tests/test_epoch.py
Normal file
39
tests/test_epoch.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pydantic_extra_types import epoch
|
||||
|
||||
|
||||
@pytest.mark.parametrize('type_,cls_', [(int, epoch.Integer), (float, epoch.Number)], ids=['integer', 'number'])
|
||||
def test_type(type_, cls_):
|
||||
from pydantic import BaseModel
|
||||
|
||||
class A(BaseModel):
|
||||
epoch: cls_
|
||||
|
||||
now = datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
ts = type_(now.timestamp())
|
||||
a = A.model_validate({'epoch': ts})
|
||||
v = a.model_dump()
|
||||
assert v['epoch'] == ts
|
||||
|
||||
b = A.model_construct(epoch=now)
|
||||
|
||||
v = b.model_dump()
|
||||
assert v['epoch'] == ts
|
||||
|
||||
c = A.model_validate(dict(epoch=ts))
|
||||
v = c.model_dump()
|
||||
assert v['epoch'] == ts
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cls_', [(epoch.Integer), (epoch.Number)], ids=['integer', 'number'])
|
||||
def test_schema(cls_):
|
||||
from pydantic import BaseModel
|
||||
|
||||
class A(BaseModel):
|
||||
dt: cls_
|
||||
|
||||
v = A.model_json_schema()
|
||||
assert (dt := v['properties']['dt'])['type'] == cls_.TYPE and dt['format'] == 'date-time'
|
|
@ -1,23 +1,28 @@
|
|||
from typing import Union
|
||||
|
||||
import pycountry
|
||||
import pytest
|
||||
from pydantic import BaseModel
|
||||
from typing_extensions import Annotated
|
||||
|
||||
import pydantic_extra_types
|
||||
from pydantic_extra_types import epoch
|
||||
from pydantic_extra_types.color import Color
|
||||
from pydantic_extra_types.coordinate import Coordinate, Latitude, Longitude
|
||||
from pydantic_extra_types.country import (
|
||||
CountryAlpha2,
|
||||
CountryAlpha3,
|
||||
CountryNumericCode,
|
||||
CountryShortName,
|
||||
)
|
||||
from pydantic_extra_types.country import CountryAlpha2, CountryAlpha3, CountryNumericCode, CountryShortName
|
||||
from pydantic_extra_types.currency_code import ISO4217, Currency
|
||||
from pydantic_extra_types.domain import DomainStr
|
||||
from pydantic_extra_types.isbn import ISBN
|
||||
from pydantic_extra_types.language_code import ISO639_3, ISO639_5, LanguageAlpha2, LanguageName
|
||||
from pydantic_extra_types.mac_address import MacAddress
|
||||
from pydantic_extra_types.payment import PaymentCardNumber
|
||||
from pydantic_extra_types.pendulum_dt import DateTime
|
||||
from pydantic_extra_types.phone_numbers import PhoneNumber, PhoneNumberValidator
|
||||
from pydantic_extra_types.s3 import S3Path
|
||||
from pydantic_extra_types.script_code import ISO_15924
|
||||
from pydantic_extra_types.semantic_version import SemanticVersion
|
||||
from pydantic_extra_types.semver import _VersionPydanticAnnotation
|
||||
from pydantic_extra_types.timezone_name import TimeZoneName
|
||||
from pydantic_extra_types.ulid import ULID
|
||||
|
||||
languages = [lang.alpha_3 for lang in pycountry.languages]
|
||||
|
@ -35,8 +40,20 @@ everyday_currencies = [
|
|||
|
||||
scripts = [script.alpha_4 for script in pycountry.scripts]
|
||||
|
||||
timezone_names = TimeZoneName.allowed_values_list
|
||||
|
||||
everyday_currencies.sort()
|
||||
|
||||
AnyNumberRFC3966 = Annotated[Union[str, PhoneNumber], PhoneNumberValidator()]
|
||||
USNumberE164 = Annotated[
|
||||
Union[str, PhoneNumber],
|
||||
PhoneNumberValidator(
|
||||
supported_regions=['US'],
|
||||
default_region='US',
|
||||
number_format='E164',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'cls,expected',
|
||||
|
@ -325,6 +342,158 @@ everyday_currencies.sort()
|
|||
'type': 'object',
|
||||
},
|
||||
),
|
||||
(
|
||||
SemanticVersion,
|
||||
{
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
'pattern': r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$',
|
||||
}
|
||||
},
|
||||
'required': ['x'],
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
},
|
||||
),
|
||||
(
|
||||
TimeZoneName,
|
||||
{
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
'enum': timezone_names,
|
||||
'minLength': 1,
|
||||
}
|
||||
},
|
||||
'required': ['x'],
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
},
|
||||
),
|
||||
(
|
||||
_VersionPydanticAnnotation,
|
||||
{
|
||||
'properties': {'x': {'title': 'X', 'type': 'string'}},
|
||||
'required': ['x'],
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
},
|
||||
),
|
||||
(
|
||||
PhoneNumber,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
'format': 'phone',
|
||||
}
|
||||
},
|
||||
'required': ['x'],
|
||||
},
|
||||
),
|
||||
(
|
||||
AnyNumberRFC3966,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
'format': 'phone',
|
||||
}
|
||||
},
|
||||
'required': ['x'],
|
||||
},
|
||||
),
|
||||
(
|
||||
USNumberE164,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
'format': 'phone',
|
||||
}
|
||||
},
|
||||
'required': ['x'],
|
||||
},
|
||||
),
|
||||
(
|
||||
S3Path,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'pattern': '^s3://([^/]+)/(.*?([^/]+)/?)$',
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'x',
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
DomainStr,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'x',
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
epoch.Integer,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'integer',
|
||||
'format': 'date-time',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'x',
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
epoch.Number,
|
||||
{
|
||||
'title': 'Model',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': {
|
||||
'title': 'X',
|
||||
'type': 'number',
|
||||
'format': 'date-time',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'x',
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_json_schema(cls, expected):
|
||||
|
|
|
@ -41,9 +41,7 @@ class DurationModel(BaseModel):
|
|||
],
|
||||
)
|
||||
def test_existing_instance(instance):
|
||||
"""
|
||||
Verifies that constructing a model with an existing pendulum dt doesn't throw.
|
||||
"""
|
||||
"""Verifies that constructing a model with an existing pendulum dt doesn't throw."""
|
||||
model = DtModel(dt=instance)
|
||||
if isinstance(instance, datetime):
|
||||
assert model.dt == pendulum.instance(instance)
|
||||
|
@ -75,9 +73,7 @@ def test_existing_instance(instance):
|
|||
],
|
||||
)
|
||||
def test_pendulum_date_existing_instance(instance):
|
||||
"""
|
||||
Verifies that constructing a model with an existing pendulum date doesn't throw.
|
||||
"""
|
||||
"""Verifies that constructing a model with an existing pendulum date doesn't throw."""
|
||||
model = DateModel(d=instance)
|
||||
if isinstance(instance, datetime):
|
||||
assert model.d == pendulum.instance(instance).date()
|
||||
|
@ -96,14 +92,34 @@ def test_pendulum_date_existing_instance(instance):
|
|||
[
|
||||
pendulum.duration(days=42, hours=13, minutes=37),
|
||||
pendulum.duration(days=-42, hours=13, minutes=37),
|
||||
pendulum.duration(weeks=97),
|
||||
pendulum.duration(days=463),
|
||||
pendulum.duration(milliseconds=90122),
|
||||
pendulum.duration(microseconds=90122),
|
||||
pendulum.duration(
|
||||
years=2,
|
||||
months=3,
|
||||
weeks=19,
|
||||
days=1,
|
||||
hours=25,
|
||||
seconds=732,
|
||||
milliseconds=123,
|
||||
microseconds=1324,
|
||||
),
|
||||
timedelta(days=42, hours=13, minutes=37),
|
||||
timedelta(days=-42, hours=13, minutes=37),
|
||||
timedelta(
|
||||
weeks=19,
|
||||
days=1,
|
||||
hours=25,
|
||||
seconds=732,
|
||||
milliseconds=123,
|
||||
microseconds=1324,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_duration_timedelta__existing_instance(instance):
|
||||
"""
|
||||
Verifies that constructing a model with an existing pendulum duration doesn't throw.
|
||||
"""
|
||||
"""Verifies that constructing a model with an existing pendulum duration doesn't throw."""
|
||||
model = DurationModel(delta_t=instance)
|
||||
|
||||
assert model.delta_t.total_seconds() == instance.total_seconds()
|
||||
|
@ -119,9 +135,7 @@ def test_duration_timedelta__existing_instance(instance):
|
|||
],
|
||||
)
|
||||
def test_pendulum_dt_from_serialized(dt):
|
||||
"""
|
||||
Verifies that building an instance from serialized, well-formed strings decode properly.
|
||||
"""
|
||||
"""Verifies that building an instance from serialized, well-formed strings decode properly."""
|
||||
dt_actual = pendulum.parse(dt)
|
||||
model = DtModel(dt=dt)
|
||||
assert model.dt == dt_actual
|
||||
|
@ -137,8 +151,7 @@ def test_pendulum_dt_from_serialized(dt):
|
|||
],
|
||||
)
|
||||
def test_pendulum_dt_from_serialized_preserves_timezones(dt):
|
||||
"""
|
||||
Verifies that building an instance from serialized, well-formed strings decode
|
||||
"""Verifies that building an instance from serialized, well-formed strings decode
|
||||
properly and preserves the timezone information across all of the Pendulum DateTime
|
||||
properties. Regression test for pydantic/pydantic-extra-types#188.
|
||||
"""
|
||||
|
@ -165,9 +178,7 @@ def test_pendulum_dt_from_serialized_preserves_timezones(dt):
|
|||
],
|
||||
)
|
||||
def test_pendulum_dt_not_strict_from_serialized(dt):
|
||||
"""
|
||||
Verifies that building an instance from serialized, well-formed strings decode properly.
|
||||
"""
|
||||
"""Verifies that building an instance from serialized, well-formed strings decode properly."""
|
||||
dt_actual = pendulum.parse(dt, strict=False)
|
||||
model = DtModelNotStrict(dt=dt)
|
||||
assert model.dt == dt_actual
|
||||
|
@ -200,9 +211,7 @@ def test_pendulum_dt_not_strict_from_serialized(dt):
|
|||
],
|
||||
)
|
||||
def test_pendulum_dt_from_str_unix_timestamp(dt):
|
||||
"""
|
||||
Verifies that building an instance from serialized, well-formed strings decode properly.
|
||||
"""
|
||||
"""Verifies that building an instance from serialized, well-formed strings decode properly."""
|
||||
dt_actual = pendulum.instance(DtTypeAdapter.validate_python(dt))
|
||||
model = DtModel(dt=dt)
|
||||
assert model.dt == dt_actual
|
||||
|
@ -233,21 +242,21 @@ def test_pendulum_dt_from_str_unix_timestamp(dt):
|
|||
],
|
||||
)
|
||||
def test_pendulum_dt_from_str_unix_timestamp_is_utc(dt):
|
||||
"""
|
||||
Verifies that without timezone information, it is coerced to UTC. As in pendulum
|
||||
"""
|
||||
"""Verifies that without timezone information, it is coerced to UTC. As in pendulum"""
|
||||
model = DtModel(dt=dt)
|
||||
assert model.dt.tzinfo.tzname(model.dt) == 'UTC'
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'd',
|
||||
[pendulum.now().date().isoformat(), pendulum.now().to_w3c_string(), pendulum.now().to_iso8601_string()],
|
||||
[
|
||||
pendulum.now().date().isoformat(),
|
||||
pendulum.now().to_w3c_string(),
|
||||
pendulum.now().to_iso8601_string(),
|
||||
],
|
||||
)
|
||||
def test_pendulum_date_from_serialized(d):
|
||||
"""
|
||||
Verifies that building an instance from serialized, well-formed strings decode properly.
|
||||
"""
|
||||
"""Verifies that building an instance from serialized, well-formed strings decode properly."""
|
||||
date_actual = pendulum.parse(d).date()
|
||||
model = DateModel(d=d)
|
||||
assert model.d == date_actual
|
||||
|
@ -266,9 +275,7 @@ def test_pendulum_date_from_serialized(d):
|
|||
],
|
||||
)
|
||||
def test_pendulum_duration_from_serialized(delta_t_str):
|
||||
"""
|
||||
Verifies that building an instance from serialized, well-formed strings decode properly.
|
||||
"""
|
||||
"""Verifies that building an instance from serialized, well-formed strings decode properly."""
|
||||
true_delta_t = pendulum.parse(delta_t_str)
|
||||
model = DurationModel(delta_t=delta_t_str)
|
||||
assert model.delta_t == true_delta_t
|
||||
|
@ -315,39 +322,41 @@ dt_strict.append(pendulum.now().to_iso8601_string()[:5])
|
|||
dt_strict,
|
||||
)
|
||||
def test_pendulum_dt_malformed(dt):
|
||||
"""
|
||||
Verifies that the instance fails to validate if malformed dt is passed.
|
||||
"""
|
||||
"""Verifies that the instance fails to validate if malformed dt is passed."""
|
||||
with pytest.raises(ValidationError):
|
||||
DtModel(dt=dt)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dt', get_invalid_dt_common())
|
||||
def test_pendulum_dt_non_strict_malformed(dt):
|
||||
"""
|
||||
Verifies that the instance fails to validate if malformed dt are passed.
|
||||
"""
|
||||
"""Verifies that the instance fails to validate if malformed dt are passed."""
|
||||
with pytest.raises(ValidationError):
|
||||
DtModelNotStrict(dt=dt)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('invalid_value', [None, 'malformed', pendulum.today().to_iso8601_string()[:5], 'P10Y10M10D'])
|
||||
@pytest.mark.parametrize(
|
||||
'invalid_value',
|
||||
[None, 'malformed', pendulum.today().to_iso8601_string()[:5], 'P10Y10M10D'],
|
||||
)
|
||||
def test_pendulum_date_malformed(invalid_value):
|
||||
"""
|
||||
Verifies that the instance fails to validate if malformed date are passed.
|
||||
"""
|
||||
"""Verifies that the instance fails to validate if malformed date are passed."""
|
||||
with pytest.raises(ValidationError):
|
||||
DateModel(d=invalid_value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'delta_t',
|
||||
[None, 'malformed', pendulum.today().to_iso8601_string()[:5], 42, '12m', '2021-01-01T12:00:00'],
|
||||
[
|
||||
None,
|
||||
'malformed',
|
||||
pendulum.today().to_iso8601_string()[:5],
|
||||
42,
|
||||
'12m',
|
||||
'2021-01-01T12:00:00',
|
||||
],
|
||||
)
|
||||
def test_pendulum_duration_malformed(delta_t):
|
||||
"""
|
||||
Verifies that the instance fails to validate if malformed durations are passed.
|
||||
"""
|
||||
"""Verifies that the instance fails to validate if malformed durations are passed."""
|
||||
with pytest.raises(ValidationError):
|
||||
DurationModel(delta_t=delta_t)
|
||||
|
||||
|
@ -371,3 +380,9 @@ def test_date_type_adapter(input_type: type, value, is_instance: type):
|
|||
assert type(validated) is input_type
|
||||
assert isinstance(validated, input_type)
|
||||
assert isinstance(validated, is_instance)
|
||||
|
||||
|
||||
def test_pendulum_duration_months_are_preserved():
|
||||
m = DurationModel(delta_t=pendulum.Duration(months=1))
|
||||
|
||||
assert m.delta_t.months == 1
|
||||
|
|
|
@ -31,15 +31,21 @@ def test_formats_phone_number() -> None:
|
|||
|
||||
|
||||
def test_supported_regions() -> None:
|
||||
assert 'US' in PhoneNumber.supported_regions
|
||||
assert 'GB' in PhoneNumber.supported_regions
|
||||
assert PhoneNumber.supported_regions == []
|
||||
PhoneNumber.supported_regions = ['US']
|
||||
|
||||
assert Something(phone_number='+1 901 555 1212')
|
||||
|
||||
def test_supported_formats() -> None:
|
||||
assert 'E164' in PhoneNumber.supported_formats
|
||||
assert 'RFC3966' in PhoneNumber.supported_formats
|
||||
assert '__dict__' not in PhoneNumber.supported_formats
|
||||
assert 'to_string' not in PhoneNumber.supported_formats
|
||||
with pytest.raises(ValidationError, match='value is not from a supported region'):
|
||||
Something(phone_number='+44 20 7946 0958')
|
||||
|
||||
USPhoneNumber = PhoneNumber()
|
||||
USPhoneNumber.supported_regions = ['US']
|
||||
assert USPhoneNumber.supported_regions == ['US']
|
||||
assert Something(phone_number='+1 901 555 1212')
|
||||
|
||||
with pytest.raises(ValidationError, match='value is not from a supported region'):
|
||||
Something(phone_number='+44 20 7946 0958')
|
||||
|
||||
|
||||
def test_parse_error() -> None:
|
||||
|
@ -64,20 +70,3 @@ def test_eq() -> None:
|
|||
assert PhoneNumber('555-1212') == '555-1212'
|
||||
assert PhoneNumber('555-1212') != '555-1213'
|
||||
assert PhoneNumber('555-1212') != PhoneNumber('555-1213')
|
||||
|
||||
|
||||
def test_json_schema() -> None:
|
||||
assert Something.model_json_schema() == {
|
||||
'title': 'Something',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'phone_number': {
|
||||
'title': 'Phone Number',
|
||||
'type': 'string',
|
||||
'format': 'phone',
|
||||
'minLength': 7,
|
||||
'maxLength': 64,
|
||||
}
|
||||
},
|
||||
'required': ['phone_number'],
|
||||
}
|
||||
|
|
102
tests/test_phone_numbers_validator.py
Normal file
102
tests/test_phone_numbers_validator.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
from typing import Any, Optional, Union
|
||||
|
||||
import phonenumbers
|
||||
import pytest
|
||||
from phonenumbers import PhoneNumber
|
||||
from pydantic import BaseModel, TypeAdapter, ValidationError
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from pydantic_extra_types.phone_numbers import PhoneNumberValidator
|
||||
|
||||
Number = Annotated[Union[str, PhoneNumber], PhoneNumberValidator()]
|
||||
NANumber = Annotated[
|
||||
Union[str, PhoneNumber],
|
||||
PhoneNumberValidator(
|
||||
supported_regions=['US', 'CA'],
|
||||
default_region='US',
|
||||
),
|
||||
]
|
||||
UKNumber = Annotated[
|
||||
Union[str, PhoneNumber],
|
||||
PhoneNumberValidator(
|
||||
supported_regions=['GB'],
|
||||
default_region='GB',
|
||||
number_format='E164',
|
||||
),
|
||||
]
|
||||
|
||||
number_adapter = TypeAdapter(Number)
|
||||
|
||||
|
||||
class Numbers(BaseModel):
|
||||
phone_number: Optional[Number] = None
|
||||
na_number: Optional[NANumber] = None
|
||||
uk_number: Optional[UKNumber] = None
|
||||
|
||||
|
||||
def test_validator_constructor() -> None:
|
||||
PhoneNumberValidator()
|
||||
PhoneNumberValidator(supported_regions=['US', 'CA'], default_region='US')
|
||||
PhoneNumberValidator(supported_regions=['GB'], default_region='GB', number_format='E164')
|
||||
with pytest.raises(ValueError, match='Invalid default region code: XX'):
|
||||
PhoneNumberValidator(default_region='XX')
|
||||
with pytest.raises(ValueError, match='Invalid number format: XX'):
|
||||
PhoneNumberValidator(number_format='XX')
|
||||
with pytest.raises(ValueError, match='Invalid supported region code: XX'):
|
||||
PhoneNumberValidator(supported_regions=['XX'])
|
||||
|
||||
|
||||
# Note: the 555 area code will result in an invalid phone number
|
||||
def test_valid_phone_number() -> None:
|
||||
Numbers(phone_number='+1 901 555 1212')
|
||||
|
||||
|
||||
def test_when_extension_provided() -> None:
|
||||
Numbers(phone_number='+1 901 555 1212 ext 12533')
|
||||
|
||||
|
||||
def test_when_phonenumber_instance() -> None:
|
||||
phone_number = phonenumbers.parse('+1 901 555 1212', region='US')
|
||||
numbers = Numbers(phone_number=phone_number)
|
||||
assert numbers.phone_number == 'tel:+1-901-555-1212'
|
||||
# Additional validation is still performed on the instance
|
||||
with pytest.raises(ValidationError, match='value is not from a supported region'):
|
||||
Numbers(uk_number=phone_number)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('invalid_number', ['', '123', 12, object(), '55 121'])
|
||||
def test_invalid_phone_number(invalid_number: Any) -> None:
|
||||
# Use a TypeAdapter to test the validation logic for None otherwise
|
||||
# optional fields will not attempt to validate
|
||||
with pytest.raises(ValidationError, match='value is not a valid phone number'):
|
||||
number_adapter.validate_python(invalid_number)
|
||||
|
||||
|
||||
def test_formats_phone_number() -> None:
|
||||
result = Numbers(phone_number='+1 901 555 1212 ext 12533', uk_number='+44 20 7946 0958')
|
||||
assert result.phone_number == 'tel:+1-901-555-1212;ext=12533'
|
||||
assert result.uk_number == '+442079460958'
|
||||
|
||||
|
||||
def test_default_region() -> None:
|
||||
result = Numbers(na_number='901 555 1212')
|
||||
assert result.na_number == 'tel:+1-901-555-1212'
|
||||
with pytest.raises(ValidationError, match='value is not a valid phone number'):
|
||||
Numbers(phone_number='901 555 1212')
|
||||
|
||||
|
||||
def test_supported_regions() -> None:
|
||||
assert Numbers(na_number='+1 901 555 1212')
|
||||
assert Numbers(uk_number='+44 20 7946 0958')
|
||||
with pytest.raises(ValidationError, match='value is not from a supported region'):
|
||||
Numbers(na_number='+44 20 7946 0958')
|
||||
|
||||
|
||||
def test_parse_error() -> None:
|
||||
with pytest.raises(ValidationError, match='value is not a valid phone number'):
|
||||
Numbers(phone_number='555 1212')
|
||||
|
||||
|
||||
def test_parsed_but_not_a_valid_number() -> None:
|
||||
with pytest.raises(ValidationError, match='value is not a valid phone number'):
|
||||
Numbers(phone_number='+1 555-1212')
|
152
tests/test_s3.py
Normal file
152
tests/test_s3.py
Normal file
|
@ -0,0 +1,152 @@
|
|||
import pytest
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
from pydantic_extra_types.s3 import S3Path
|
||||
|
||||
|
||||
class S3Check(BaseModel):
|
||||
path: S3Path
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'raw,bucket,key,last_key',
|
||||
[
|
||||
(
|
||||
's3://my-data-bucket/2023/08/29/sales-report.csv',
|
||||
'my-data-bucket',
|
||||
'2023/08/29/sales-report.csv',
|
||||
'sales-report.csv',
|
||||
),
|
||||
(
|
||||
's3://logs-bucket/app-logs/production/2024/07/01/application-log.txt',
|
||||
'logs-bucket',
|
||||
'app-logs/production/2024/07/01/application-log.txt',
|
||||
'application-log.txt',
|
||||
),
|
||||
(
|
||||
's3://backup-storage/user_data/john_doe/photos/photo-2024-08-15.jpg',
|
||||
'backup-storage',
|
||||
'user_data/john_doe/photos/photo-2024-08-15.jpg',
|
||||
'photo-2024-08-15.jpg',
|
||||
),
|
||||
(
|
||||
's3://analytics-bucket/weekly-reports/Q3/2023/week-35-summary.pdf',
|
||||
'analytics-bucket',
|
||||
'weekly-reports/Q3/2023/week-35-summary.pdf',
|
||||
'week-35-summary.pdf',
|
||||
),
|
||||
(
|
||||
's3://project-data/docs/presentations/quarterly_review.pptx',
|
||||
'project-data',
|
||||
'docs/presentations/quarterly_review.pptx',
|
||||
'quarterly_review.pptx',
|
||||
),
|
||||
(
|
||||
's3://my-music-archive/genres/rock/2024/favorite-songs.mp3',
|
||||
'my-music-archive',
|
||||
'genres/rock/2024/favorite-songs.mp3',
|
||||
'favorite-songs.mp3',
|
||||
),
|
||||
(
|
||||
's3://video-uploads/movies/2024/03/action/thriller/movie-trailer.mp4',
|
||||
'video-uploads',
|
||||
'movies/2024/03/action/thriller/movie-trailer.mp4',
|
||||
'movie-trailer.mp4',
|
||||
),
|
||||
(
|
||||
's3://company-files/legal/contracts/contract-2023-09-01.pdf',
|
||||
'company-files',
|
||||
'legal/contracts/contract-2023-09-01.pdf',
|
||||
'contract-2023-09-01.pdf',
|
||||
),
|
||||
(
|
||||
's3://dev-environment/source-code/release_v1.0.2.zip',
|
||||
'dev-environment',
|
||||
'source-code/release_v1.0.2.zip',
|
||||
'release_v1.0.2.zip',
|
||||
),
|
||||
(
|
||||
's3://public-bucket/open-data/geojson/maps/city_boundaries.geojson',
|
||||
'public-bucket',
|
||||
'open-data/geojson/maps/city_boundaries.geojson',
|
||||
'city_boundaries.geojson',
|
||||
),
|
||||
(
|
||||
's3://image-storage/2024/portfolio/shoots/wedding/couple_photo_12.jpg',
|
||||
'image-storage',
|
||||
'2024/portfolio/shoots/wedding/couple_photo_12.jpg',
|
||||
'couple_photo_12.jpg',
|
||||
),
|
||||
(
|
||||
's3://finance-data/reports/2024/Q2/income_statement.xlsx',
|
||||
'finance-data',
|
||||
'reports/2024/Q2/income_statement.xlsx',
|
||||
'income_statement.xlsx',
|
||||
),
|
||||
(
|
||||
's3://training-data/nlp/corpora/english/2023/text_corpus.txt',
|
||||
'training-data',
|
||||
'nlp/corpora/english/2023/text_corpus.txt',
|
||||
'text_corpus.txt',
|
||||
),
|
||||
(
|
||||
's3://ecommerce-backup/2024/transactions/august/orders_2024_08_28.csv',
|
||||
'ecommerce-backup',
|
||||
'2024/transactions/august/orders_2024_08_28.csv',
|
||||
'orders_2024_08_28.csv',
|
||||
),
|
||||
(
|
||||
's3://gaming-assets/3d_models/characters/hero/model_v5.obj',
|
||||
'gaming-assets',
|
||||
'3d_models/characters/hero/model_v5.obj',
|
||||
'model_v5.obj',
|
||||
),
|
||||
(
|
||||
's3://iot-sensor-data/2024/temperature_sensors/sensor_42_readings.csv',
|
||||
'iot-sensor-data',
|
||||
'2024/temperature_sensors/sensor_42_readings.csv',
|
||||
'sensor_42_readings.csv',
|
||||
),
|
||||
(
|
||||
's3://user-uploads/avatars/user123/avatar_2024_08_29.png',
|
||||
'user-uploads',
|
||||
'avatars/user123/avatar_2024_08_29.png',
|
||||
'avatar_2024_08_29.png',
|
||||
),
|
||||
(
|
||||
's3://media-library/podcasts/2023/episode_45.mp3',
|
||||
'media-library',
|
||||
'podcasts/2023/episode_45.mp3',
|
||||
'episode_45.mp3',
|
||||
),
|
||||
(
|
||||
's3://logs-bucket/security/firewall-logs/2024/08/failed_attempts.log',
|
||||
'logs-bucket',
|
||||
'security/firewall-logs/2024/08/failed_attempts.log',
|
||||
'failed_attempts.log',
|
||||
),
|
||||
(
|
||||
's3://data-warehouse/financials/quarterly/2024/Q1/profit_loss.csv',
|
||||
'data-warehouse',
|
||||
'financials/quarterly/2024/Q1/profit_loss.csv',
|
||||
'profit_loss.csv',
|
||||
),
|
||||
(
|
||||
's3://data-warehouse/financials/quarterly/2024/Q1',
|
||||
'data-warehouse',
|
||||
'financials/quarterly/2024/Q1',
|
||||
'Q1',
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_s3(raw: str, bucket: str, key: str, last_key: str):
|
||||
model = S3Check(path=raw)
|
||||
assert model.path == S3Path(raw)
|
||||
assert model.path.bucket == bucket
|
||||
assert model.path.key == key
|
||||
assert model.path.last_key == last_key
|
||||
|
||||
|
||||
def test_wrong_s3():
|
||||
with pytest.raises(ValidationError):
|
||||
S3Check(path='s3/ok')
|
109
tests/test_semantic_version.py
Normal file
109
tests/test_semantic_version.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
import pytest
|
||||
import semver
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
from pydantic_extra_types.semantic_version import SemanticVersion
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', name='SemanticVersionObject')
|
||||
def application_object_fixture():
|
||||
class Application(BaseModel):
|
||||
version: SemanticVersion
|
||||
|
||||
return Application
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'constructor', [str, semver.Version.parse, SemanticVersion.parse], ids=['str', 'semver.Version', 'SemanticVersion']
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
'version',
|
||||
[
|
||||
'0.0.4',
|
||||
'1.2.3',
|
||||
'10.20.30',
|
||||
'1.1.2-prerelease+meta',
|
||||
'1.1.2+meta',
|
||||
'1.1.2+meta-valid',
|
||||
'1.0.0-alpha',
|
||||
'1.0.0-beta',
|
||||
'1.0.0-alpha.beta',
|
||||
'1.0.0-alpha.beta.1',
|
||||
'1.0.0-alpha.1',
|
||||
'1.0.0-alpha0.valid',
|
||||
'1.0.0-alpha.0valid',
|
||||
'1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay',
|
||||
'1.0.0-rc.1+build.1',
|
||||
'2.0.0-rc.1+build.123',
|
||||
'1.2.3-beta',
|
||||
'10.2.3-DEV-SNAPSHOT',
|
||||
'1.2.3-SNAPSHOT-123',
|
||||
'1.0.0',
|
||||
'2.0.0',
|
||||
'1.1.7',
|
||||
'2.0.0+build.1848',
|
||||
'2.0.1-alpha.1227',
|
||||
'1.0.0-alpha+beta',
|
||||
'1.2.3----RC-SNAPSHOT.12.9.1--.12+788',
|
||||
'1.2.3----R-S.12.9.1--.12+meta',
|
||||
'1.2.3----RC-SNAPSHOT.12.9.1--.12',
|
||||
'1.0.0+0.build.1-rc.10000aaa-kk-0.1',
|
||||
'99999999999999999999999.999999999999999999.99999999999999999',
|
||||
'1.0.0-0A.is.legal',
|
||||
],
|
||||
)
|
||||
def test_valid_semantic_version(SemanticVersionObject, constructor, version):
|
||||
application = SemanticVersionObject(version=constructor(version))
|
||||
assert application.version
|
||||
assert application.model_dump() == {'version': version}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'invalid_version',
|
||||
[
|
||||
'',
|
||||
'1',
|
||||
'1.2',
|
||||
'1.2.3-0123',
|
||||
'1.2.3-0123.0123',
|
||||
'1.1.2+.123',
|
||||
'+invalid',
|
||||
'-invalid',
|
||||
'-invalid+invalid',
|
||||
'-invalid.01',
|
||||
'alpha',
|
||||
'alpha.beta',
|
||||
'alpha.beta.1',
|
||||
'alpha.1',
|
||||
'alpha+beta',
|
||||
'alpha_beta',
|
||||
'alpha.',
|
||||
'alpha..',
|
||||
'beta',
|
||||
'1.0.0-alpha_beta',
|
||||
'-alpha.',
|
||||
'1.0.0-alpha..',
|
||||
'1.0.0-alpha..1',
|
||||
'1.0.0-alpha...1',
|
||||
'1.0.0-alpha....1',
|
||||
'1.0.0-alpha.....1',
|
||||
'1.0.0-alpha......1',
|
||||
'1.0.0-alpha.......1',
|
||||
'01.1.1',
|
||||
'1.01.1',
|
||||
'1.1.01',
|
||||
'1.2',
|
||||
'1.2.3.DEV',
|
||||
'1.2-SNAPSHOT',
|
||||
'1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788',
|
||||
'1.2-RC-SNAPSHOT',
|
||||
'-1.0.3-gamma+b7718',
|
||||
'+justmeta',
|
||||
'9.8.7+meta+meta',
|
||||
'9.8.7-whatever+meta+meta',
|
||||
'99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12',
|
||||
],
|
||||
)
|
||||
def test_invalid_semantic_version(SemanticVersionObject, invalid_version):
|
||||
with pytest.raises(ValidationError):
|
||||
SemanticVersionObject(version=invalid_version)
|
21
tests/test_semver.py
Normal file
21
tests/test_semver.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
import pytest
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pydantic_extra_types.semver import _VersionPydanticAnnotation
|
||||
|
||||
|
||||
class SomethingWithAVersion(BaseModel):
|
||||
version: _VersionPydanticAnnotation
|
||||
|
||||
|
||||
def test_valid_semver() -> None:
|
||||
SomethingWithAVersion(version='1.2.3')
|
||||
|
||||
|
||||
def test_valid_semver_with_prerelease() -> None:
|
||||
SomethingWithAVersion(version='1.2.3-alpha.1')
|
||||
|
||||
|
||||
def test_invalid_semver() -> None:
|
||||
with pytest.raises(ValueError):
|
||||
SomethingWithAVersion(version='jim.was.here')
|
209
tests/test_timezone_names.py
Normal file
209
tests/test_timezone_names.py
Normal file
|
@ -0,0 +1,209 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
from pydantic import BaseModel, ValidationError
|
||||
from pydantic_core import PydanticCustomError
|
||||
|
||||
from pydantic_extra_types.timezone_name import TimeZoneName, TimeZoneNameSettings, timezone_name_settings
|
||||
|
||||
has_zone_info = True
|
||||
try:
|
||||
from zoneinfo import available_timezones
|
||||
except ImportError:
|
||||
has_zone_info = False
|
||||
|
||||
pytz_zones_bad = [(zone.lower(), zone) for zone in pytz.all_timezones]
|
||||
pytz_zones_bad.extend([(f' {zone}', zone) for zone in pytz.all_timezones_set])
|
||||
|
||||
|
||||
class TZNameCheck(BaseModel):
|
||||
timezone_name: TimeZoneName
|
||||
|
||||
|
||||
@timezone_name_settings(strict=False)
|
||||
class TZNonStrict(TimeZoneName):
|
||||
pass
|
||||
|
||||
|
||||
class NonStrictTzName(BaseModel):
|
||||
timezone_name: TZNonStrict
|
||||
|
||||
|
||||
@pytest.mark.parametrize('zone', pytz.all_timezones)
|
||||
def test_all_timezones_non_strict_pytz(zone):
|
||||
assert TZNameCheck(timezone_name=zone).timezone_name == zone
|
||||
assert NonStrictTzName(timezone_name=zone).timezone_name == zone
|
||||
|
||||
|
||||
@pytest.mark.parametrize('zone', pytz_zones_bad)
|
||||
def test_all_timezones_pytz_lower(zone):
|
||||
assert NonStrictTzName(timezone_name=zone[0]).timezone_name == zone[1]
|
||||
|
||||
|
||||
def test_fail_non_existing_timezone():
|
||||
with pytest.raises(
|
||||
ValidationError,
|
||||
match=re.escape(
|
||||
'1 validation error for TZNameCheck\n'
|
||||
'timezone_name\n '
|
||||
'Invalid timezone name. '
|
||||
"[type=TimeZoneName, input_value='mars', input_type=str]"
|
||||
),
|
||||
):
|
||||
TZNameCheck(timezone_name='mars')
|
||||
|
||||
with pytest.raises(
|
||||
ValidationError,
|
||||
match=re.escape(
|
||||
'1 validation error for NonStrictTzName\n'
|
||||
'timezone_name\n '
|
||||
'Invalid timezone name. '
|
||||
"[type=TimeZoneName, input_value='mars', input_type=str]"
|
||||
),
|
||||
):
|
||||
NonStrictTzName(timezone_name='mars')
|
||||
|
||||
|
||||
if has_zone_info:
|
||||
zones = list(available_timezones())
|
||||
zones.sort()
|
||||
zones_bad = [(zone.lower(), zone) for zone in zones]
|
||||
|
||||
@pytest.mark.parametrize('zone', zones)
|
||||
def test_all_timezones_zone_info(zone):
|
||||
assert TZNameCheck(timezone_name=zone).timezone_name == zone
|
||||
assert NonStrictTzName(timezone_name=zone).timezone_name == zone
|
||||
|
||||
@pytest.mark.parametrize('zone', zones_bad)
|
||||
def test_all_timezones_zone_info_NonStrict(zone):
|
||||
assert NonStrictTzName(timezone_name=zone[0]).timezone_name == zone[1]
|
||||
|
||||
|
||||
def test_timezone_name_settings_metaclass():
|
||||
class TestStrictTZ(TimeZoneName, strict=True, metaclass=TimeZoneNameSettings):
|
||||
pass
|
||||
|
||||
class TestNonStrictTZ(TimeZoneName, strict=False, metaclass=TimeZoneNameSettings):
|
||||
pass
|
||||
|
||||
assert TestStrictTZ.strict is True
|
||||
assert TestNonStrictTZ.strict is False
|
||||
|
||||
# Test default value
|
||||
class TestDefaultStrictTZ(TimeZoneName, metaclass=TimeZoneNameSettings):
|
||||
pass
|
||||
|
||||
assert TestDefaultStrictTZ.strict is True
|
||||
|
||||
|
||||
def test_timezone_name_validation():
|
||||
valid_tz = 'America/New_York'
|
||||
invalid_tz = 'Invalid/Timezone'
|
||||
|
||||
assert TimeZoneName._validate(valid_tz, None) == valid_tz
|
||||
|
||||
with pytest.raises(PydanticCustomError):
|
||||
TimeZoneName._validate(invalid_tz, None)
|
||||
|
||||
assert TZNonStrict._validate(valid_tz.lower(), None) == valid_tz
|
||||
assert TZNonStrict._validate(f' {valid_tz} ', None) == valid_tz
|
||||
|
||||
with pytest.raises(PydanticCustomError):
|
||||
TZNonStrict._validate(invalid_tz, None)
|
||||
|
||||
|
||||
def test_timezone_name_pydantic_core_schema():
|
||||
schema = TimeZoneName.__get_pydantic_core_schema__(TimeZoneName, None)
|
||||
assert isinstance(schema, dict)
|
||||
assert schema['type'] == 'function-after'
|
||||
assert 'function' in schema
|
||||
assert 'schema' in schema
|
||||
assert schema['schema']['type'] == 'str'
|
||||
assert schema['schema']['min_length'] == 1
|
||||
|
||||
|
||||
def test_timezone_name_pydantic_json_schema():
|
||||
core_schema = TimeZoneName.__get_pydantic_core_schema__(TimeZoneName, None)
|
||||
|
||||
class MockJsonSchemaHandler:
|
||||
def __call__(self, schema):
|
||||
return {'type': 'string'}
|
||||
|
||||
handler = MockJsonSchemaHandler()
|
||||
json_schema = TimeZoneName.__get_pydantic_json_schema__(core_schema, handler)
|
||||
assert 'enum' in json_schema
|
||||
assert isinstance(json_schema['enum'], list)
|
||||
assert len(json_schema['enum']) > 0
|
||||
|
||||
|
||||
def test_timezone_name_repr():
|
||||
tz = TimeZoneName('America/New_York')
|
||||
assert repr(tz) == "'America/New_York'"
|
||||
assert str(tz) == 'America/New_York'
|
||||
|
||||
|
||||
def test_timezone_name_allowed_values():
|
||||
assert isinstance(TimeZoneName.allowed_values, set)
|
||||
assert len(TimeZoneName.allowed_values) > 0
|
||||
assert all(isinstance(tz, str) for tz in TimeZoneName.allowed_values)
|
||||
|
||||
assert isinstance(TimeZoneName.allowed_values_list, list)
|
||||
assert len(TimeZoneName.allowed_values_list) > 0
|
||||
assert all(isinstance(tz, str) for tz in TimeZoneName.allowed_values_list)
|
||||
|
||||
assert isinstance(TimeZoneName.allowed_values_upper_to_correct, dict)
|
||||
assert len(TimeZoneName.allowed_values_upper_to_correct) > 0
|
||||
assert all(
|
||||
isinstance(k, str) and isinstance(v, str) for k, v in TimeZoneName.allowed_values_upper_to_correct.items()
|
||||
)
|
||||
|
||||
|
||||
def test_timezone_name_inheritance():
|
||||
class CustomTZ(TimeZoneName, metaclass=TimeZoneNameSettings):
|
||||
pass
|
||||
|
||||
assert issubclass(CustomTZ, TimeZoneName)
|
||||
assert issubclass(CustomTZ, str)
|
||||
assert isinstance(CustomTZ('America/New_York'), (CustomTZ, TimeZoneName, str))
|
||||
|
||||
|
||||
def test_timezone_name_string_operations():
|
||||
tz = TimeZoneName('America/New_York')
|
||||
assert tz.upper() == 'AMERICA/NEW_YORK'
|
||||
assert tz.lower() == 'america/new_york'
|
||||
assert tz.strip() == 'America/New_York'
|
||||
assert f'{tz} Time' == 'America/New_York Time'
|
||||
assert tz.startswith('America')
|
||||
assert tz.endswith('York')
|
||||
|
||||
|
||||
def test_timezone_name_comparison():
|
||||
tz1 = TimeZoneName('America/New_York')
|
||||
tz2 = TimeZoneName('Europe/London')
|
||||
tz3 = TimeZoneName('America/New_York')
|
||||
|
||||
assert tz1 == tz3
|
||||
assert tz1 != tz2
|
||||
assert tz1 < tz2 # Alphabetical comparison
|
||||
assert tz2 > tz1
|
||||
assert tz1 <= tz3
|
||||
assert tz1 >= tz3
|
||||
|
||||
|
||||
def test_timezone_name_hash():
|
||||
tz1 = TimeZoneName('America/New_York')
|
||||
tz2 = TimeZoneName('America/New_York')
|
||||
tz3 = TimeZoneName('Europe/London')
|
||||
|
||||
assert hash(tz1) == hash(tz2)
|
||||
assert hash(tz1) != hash(tz3)
|
||||
|
||||
tz_set = {tz1, tz2, tz3}
|
||||
assert len(tz_set) == 2
|
||||
|
||||
|
||||
def test_timezone_name_slots():
|
||||
tz = TimeZoneName('America/New_York')
|
||||
with pytest.raises(AttributeError):
|
||||
tz.new_attribute = 'test'
|
828
uv.lock
generated
Normal file
828
uv.lock
generated
Normal file
|
@ -0,0 +1,828 @@
|
|||
version = 1
|
||||
requires-python = ">=3.8"
|
||||
resolution-markers = [
|
||||
"python_full_version < '3.9'",
|
||||
"python_full_version >= '3.9' and python_full_version < '3.13'",
|
||||
"python_full_version >= '3.13'",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.9'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backports-zoneinfo"
|
||||
version = "0.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ad/85/475e514c3140937cf435954f78dedea1861aeab7662d11de232bdaa90655/backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2", size = 74098 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/6d/eca004eeadcbf8bd64cc96feb9e355536147f0577420b44d80c7cac70767/backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987", size = 35816 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/8f/9b1b920a6a95652463143943fa3b8c000cb0b932ab463764a6f2a2416560/backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1", size = 72147 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/ab/3e941e3fcf1b7d3ab3d0233194d99d6a0ed6b24f8f956fc81e47edc8c079/backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9", size = 74033 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/34/5fdb0a3a28841d215c255be8fc60b8666257bb6632193c86fd04b63d4a31/backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328", size = 36803 },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/cc/e27fd6493bbce8dbea7e6c1bc861fe3d3bc22c4f7c81f4c3befb8ff5bfaf/backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6", size = 38967 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/61/eb7ce5ed62bacf21beca4937a90fe32545c91a3c8a42a30c6616d48fc70d/coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", size = 206690 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/73/041928e434442bd3afde5584bdc3f932fb4562b1597629f537387cec6f3d/coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", size = 207127 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/c8/6ca52b5147828e45ad0242388477fdb90df2c6cbb9a441701a12b3c71bc8/coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", size = 235654 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/da/9ac2b62557f4340270942011d6efeab9833648380109e897d48ab7c1035d/coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc", size = 233598 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/23/9e2c114d0178abc42b6d8d5281f651a8e6519abfa0ef460a00a91f80879d/coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", size = 234732 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/7e/a0230756fb133343a52716e8b855045f13342b70e48e8ad41d8a0d60ab98/coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", size = 233816 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/7c/3753c8b40d232b1e5eeaed798c875537cf3cb183fb5041017c1fdb7ec14e/coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", size = 232325 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/e3/818a2b2af5b7573b4b82cf3e9f137ab158c90ea750a8f053716a32f20f06/coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", size = 233418 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/fb/4532b0b0cefb3f06d201648715e03b0feb822907edab3935112b61b885e2/coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", size = 209343 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/25/af337cc7421eca1c187cc9c315f0a755d48e755d2853715bfe8c418a45fa/coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", size = 210136 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/5f/67af7d60d7e8ce61a4e2ddcd1bd5fb787180c8d0ae0fbd073f903b3dd95d/coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", size = 206796 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/0e/e52332389e057daa2e03be1fbfef25bb4d626b37d12ed42ae6281d0a274c/coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", size = 207244 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/cd/766b45fb6e090f20f8927d9c7cb34237d41c73a939358bc881883fd3a40d/coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", size = 239279 },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/6c/a9ccd6fe50ddaf13442a1e2dd519ca805cbe0f1fcd377fba6d8339b98ccb/coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", size = 236859 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/6f/8351b465febb4dbc1ca9929505202db909c5a635c6fdf33e089bbc3d7d85/coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", size = 238549 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/3c/289b81fa18ad72138e6d78c4c11a82b5378a312c0e467e2f6b495c260907/coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", size = 237477 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/1c/aa1efa6459d822bd72c4abc0b9418cf268de3f60eeccd65dc4988553bd8d/coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", size = 236134 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/c8/521c698f2d2796565fe9c789c2ee1ccdae610b3aa20b9b2ef980cc253640/coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", size = 236910 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/30/033e663399ff17dca90d793ee8a2ea2890e7fdf085da58d82468b4220bf7/coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", size = 209348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/05/0d1ccbb52727ccdadaa3ff37e4d2dc1cd4d47f0c3df9eb58d9ec8508ca88/coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", size = 210230 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/d4/300fc921dff243cd518c7db3a4c614b7e4b2431b0d1145c1e274fd99bd70/coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", size = 206983 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/ab/6bf00de5327ecb8db205f9ae596885417a31535eeda6e7b99463108782e1/coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", size = 207221 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/8f/2ead05e735022d1a7f3a0a683ac7f737de14850395a826192f0288703472/coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", size = 240342 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/ef/94043e478201ffa85b8ae2d2c79b4081e5a1b73438aafafccf3e9bafb6b5/coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", size = 237371 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/0f/c890339dd605f3ebc269543247bdd43b703cce6825b5ed42ff5f2d6122c7/coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", size = 239455 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/04/7fd7b39ec7372a04efb0f70c70e35857a99b6a9188b5205efb4c77d6a57a/coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", size = 238924 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/bf/73ce346a9d32a09cf369f14d2a06651329c984e106f5992c89579d25b27e/coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", size = 237252 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/d0/d9e3d554e38beea5a2e22178ddb16587dbcbe9a1ef3211f55733924bf7fa/coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", size = 206674 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/ea/cab2dc248d9f45b2b7f9f1f596a4d75a435cb364437c61b51d2eb33ceb0e/coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", size = 207101 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/6f/f82f9a500c7c5722368978a5390c418d2a4d083ef955309a8748ecaa8920/coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", size = 236554 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/94/d3055aa33d4e7e733d8fa309d9adf147b4b06a82c1346366fc15a2b1d5fa/coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", size = 234440 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/6e/885bcd787d9dd674de4a7d8ec83faf729534c63d05d51d45d4fa168f7102/coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", size = 235889 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/63/df50120a7744492710854860783d6819ff23e482dee15462c9a833cc428a/coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", size = 235142 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/5d/9d0acfcded2b3e9ce1c7923ca52ccc00c78a74e112fc2aee661125b7843b/coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", size = 233805 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/56/50abf070cb3cd9b1dd32f2c88f083aab561ecbffbcd783275cb51c17f11d/coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", size = 234655 },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/ee/b4c246048b8485f85a2426ef4abab88e48c6e80c74e964bea5cd4cd4b115/coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", size = 209296 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/1c/96cf86b70b69ea2b12924cdf7cabb8ad10e6130eab8d767a1099fbd2a44f/coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", size = 210137 },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/d3/d54c5aa83268779d54c86deb39c1c4566e5d45c155369ca152765f8db413/coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", size = 206688 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/fe/137d5dca72e4a258b1bc17bb04f2e0196898fe495843402ce826a7419fe3/coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", size = 207120 },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/5b/a0a796983f3201ff5485323b225d7c8b74ce30c11f456017e23d8e8d1945/coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", size = 235249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/e1/76089d6a5ef9d68f018f65411fcdaaeb0141b504587b901d74e8587606ad/coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", size = 233237 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/6f/eef79b779a540326fee9520e5542a8b428cc3bfa8b7c8f1022c1ee4fc66c/coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", size = 234311 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/e1/656d65fb126c29a494ef964005702b012f3498db1a30dd562958e85a4049/coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", size = 233453 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/6a/45f108f137941a4a1238c85f28fd9d048cc46b5466d6b8dda3aba1bb9d4f/coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", size = 231958 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/e7/47b809099168b8b8c72ae311efc3e88c8d8a1162b3ba4b8da3cfcdb85743/coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", size = 232938 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/80/052222ba7058071f905435bad0ba392cc12006380731c37afaf3fe749b88/coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", size = 209352 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/d8/1b92e0b3adcf384e98770a00ca095da1b5f7b483e6563ae4eb5e935d24a1/coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", size = 210153 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
toml = [
|
||||
{ name = "tomli", marker = "python_full_version <= '3.11'" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirty-equals"
|
||||
version = "0.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pytz", marker = "python_full_version < '3.9'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/17/4c/39c428b7c900b21c8116d89a56b73f6dc14a2455767961b54adfe7c224fe/dirty_equals-0.8.0.tar.gz", hash = "sha256:798db3b9481b9a5024c0e520946507676ed2f0c65317d3e95bdce1a01657cf60", size = 50294 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/cd/8c3ce82cc6b18e149bff3cf8dd50a75316ca093ae706f0c1c4df87f2b88f/dirty_equals-0.8.0-py3-none-any.whl", hash = "sha256:0ef998ba3c395e03cf5eb3cd1c13c26a9a992efa18c0d59c22ba27344519cee1", size = 28217 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-resources"
|
||||
version = "6.4.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "zipp", marker = "python_full_version < '3.9'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.13.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/8c/206de95a27722b5b5a8c85ba3100467bd86299d92a4f71c6b9aa448bfa2f/mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", size = 11020731 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/bb/b31695a29eea76b1569fd28b4ab141a1adc9842edde080d1e8e1776862c7/mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", size = 10184276 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/2d/4a23849729bb27934a0e079c9c1aad912167d875c7b070382a408d459651/mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", size = 12587706 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/c3/d318e38ada50255e22e23353a469c791379825240e71b0ad03e76ca07ae6/mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", size = 13105586 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/25/3918bc64952370c3dbdbd8c82c363804678127815febd2925b7273d9482c/mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", size = 9632318 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/2a/13e9ad339131c0fba5c70584f639005a47088f5eed77081a3d00479df0ca/mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a", size = 10955147 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/39/02929067dc16b72d78109195cfed349ac4ec85f3d52517ac62b9a5263685/mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb", size = 10138373 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/cc/066709bb01734e3dbbd1375749f8789bf9693f8b842344fc0cf52109694f/mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b", size = 12543621 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/a2/124df839025348c7b9877d0ce134832a9249968e3ab36bb826bab0e9a1cf/mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74", size = 13050348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/86/cc94b1e7f7e756a63043cf425c24fb7470013ee1c032180282db75b1b335/mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6", size = 9615311 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/d4/b33ddd40dad230efb317898a2d1c267c04edba73bc5086bf77edeb410fb2/mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", size = 11013906 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/e6/f414bca465b44d01cd5f4a82761e15044bedd1bf8025c5af3cc64518fac5/mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732", size = 10180657 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/e9/fc3865e417722f98d58409770be01afb961e2c1f99930659ff4ae7ca8b7e/mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc", size = 12586394 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/35/f4d8b6d2cb0b3dad63e96caf159419dda023f45a358c6c9ac582ccaee354/mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d", size = 13103591 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/1d/80594aef135f921dd52e142fa0acd19df197690bd0cde42cea7b88cf5aa2/mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24", size = 9634690 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pendulum"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "backports-zoneinfo", marker = "python_full_version < '3.9'" },
|
||||
{ name = "importlib-resources", marker = "python_full_version < '3.9'" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "time-machine", marker = "implementation_name != 'pypy'" },
|
||||
{ name = "tzdata" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/fe/27c7438c6ac8b8f8bef3c6e571855602ee784b85d072efddfff0ceb1cd77/pendulum-3.0.0.tar.gz", hash = "sha256:5d034998dea404ec31fae27af6b22cff1708f830a1ed7353be4d1019bb9f584e", size = 84524 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/2f/2f4719366d16f1e444b4e400d3de5021bc4b09965f97e45c81e08348cbdf/pendulum-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2cf9e53ef11668e07f73190c805dbdf07a1939c3298b78d5a9203a86775d1bfd", size = 362284 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/ff/70a8f47e622e641de15b7ed8a8b66c3aa895fabc182a7d520a0c33ec850e/pendulum-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb551b9b5e6059377889d2d878d940fd0bbb80ae4810543db18e6f77b02c5ef6", size = 352957 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/cd/4e2fb7d071e81a9b07719203fd1d329febaded59981b8709663341f758f4/pendulum-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c58227ac260d5b01fc1025176d7b31858c9f62595737f350d22124a9a3ad82d", size = 335784 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/e5/9fc684c59b6f3425cf597d9489c24c47dc96d391be9eb8c9a3c543cd7646/pendulum-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60fb6f415fea93a11c52578eaa10594568a6716602be8430b167eb0d730f3332", size = 362215 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/ba/4dbb1ae42775010249ba29d01829353a9b59d9c3caf97df14d548a3b7d4c/pendulum-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b69f6b4dbcb86f2c2fe696ba991e67347bcf87fe601362a1aba6431454b46bde", size = 448632 },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/a9/0932bd7cd677bee8bdc9cb898448e47ada0f74e41f434f4ff687d03a3ea9/pendulum-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138afa9c373ee450ede206db5a5e9004fd3011b3c6bbe1e57015395cd076a09f", size = 384881 },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/a9/8c9887ce8bfb8ab0db068ac2f1fe679b713f728c116bd136301c303893cd/pendulum-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:83d9031f39c6da9677164241fd0d37fbfc9dc8ade7043b5d6d62f56e81af8ad2", size = 559554 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/70596b098b97799c78e3fc2f89394decca6f5443cac28c54082daf2d48eb/pendulum-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c2308af4033fa534f089595bcd40a95a39988ce4059ccd3dc6acb9ef14ca44a", size = 558246 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/5e/e646afbd1632bfbacdae79289d7d5879efdeeb5f5e58327bc5c698731107/pendulum-3.0.0-cp310-none-win_amd64.whl", hash = "sha256:9a59637cdb8462bdf2dbcb9d389518c0263799189d773ad5c11db6b13064fa79", size = 293456 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/f0/d60be6058657bf71281eeaa12bee85e87bac18acf6dbb7b5197bb8416537/pendulum-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3725245c0352c95d6ca297193192020d1b0c0f83d5ee6bb09964edc2b5a2d508", size = 362283 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/e5/0f9d8351242ddb119a40b41c0cf1d0c74cc243829eea6811f753a8ecf15f/pendulum-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c035f03a3e565ed132927e2c1b691de0dbf4eb53b02a5a3c5a97e1a64e17bec", size = 352957 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/43/70d0a08e5d6ca434ba139d19ec2a4847b0a3e461fbb82e680a9b6a4237ef/pendulum-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597e66e63cbd68dd6d58ac46cb7a92363d2088d37ccde2dae4332ef23e95cd00", size = 335784 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/a3/7d4c0b3f57bf7b543da9088a78a6bd6c786808ca4098bd5db649fdf9f6a2/pendulum-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99a0f8172e19f3f0c0e4ace0ad1595134d5243cf75985dc2233e8f9e8de263ca", size = 362217 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/03/8c451d569e7f4d9898f155e793f46970eed256c5ae353ecb355584890d8a/pendulum-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77d8839e20f54706aed425bec82a83b4aec74db07f26acd039905d1237a5e1d4", size = 448630 },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/3a/5e36479e199a034adcf6a1a95c691f0a2781ea55b9ac3bcb887e2f97d82b/pendulum-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde30e8146292b059020fbc8b6f8fd4a60ae7c5e6f0afef937bbb24880bdf01", size = 384882 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/25/beff911dda686e0cf169bc3dbe5d10416b376a6dde94eb1bf04aa4035409/pendulum-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:660434a6fcf6303c4efd36713ca9212c753140107ee169a3fc6c49c4711c2a05", size = 559556 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e8/f2aaa470adb6c720645f9f9ef30d5b223407ee327e12c6127eccf4218cb8/pendulum-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dee9e5a48c6999dc1106eb7eea3e3a50e98a50651b72c08a87ee2154e544b33e", size = 558249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/19/c13307ea8504d2c02c63c9dffdae1cefbd068b636ec7b18ccf2ec064d246/pendulum-3.0.0-cp311-none-win_amd64.whl", hash = "sha256:d4cdecde90aec2d67cebe4042fd2a87a4441cc02152ed7ed8fb3ebb110b94ec4", size = 293463 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/36/252d48610295c11c0f18e791dcc133d38c545b0bd19a5c3981652a9acb3c/pendulum-3.0.0-cp311-none-win_arm64.whl", hash = "sha256:773c3bc4ddda2dda9f1b9d51fe06762f9200f3293d75c4660c19b2614b991d83", size = 288057 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/37/17c8f0e7481a32f21b9002dd68912a8813f2c1d77b984e00af56eb9ae31b/pendulum-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:409e64e41418c49f973d43a28afe5df1df4f1dd87c41c7c90f1a63f61ae0f1f7", size = 362284 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/e6/08f462f6ea87e2159f19b43ff88231d26e02bda31c10bcb29290a617ace4/pendulum-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a38ad2121c5ec7c4c190c7334e789c3b4624798859156b138fcc4d92295835dc", size = 352964 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/29/b6877f6b53b91356c2c56d19ddab17b165ca994ad1e57b32c089e79f3fb5/pendulum-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fde4d0b2024b9785f66b7f30ed59281bd60d63d9213cda0eb0910ead777f6d37", size = 335848 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/77/62ca666f30b2558342deadda26290a575459a7b59248ea1e978b84175227/pendulum-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2c5675769fb6d4c11238132962939b960fcb365436b6d623c5864287faa319", size = 362215 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/29/ce37593f5ea51862c60dadf4e863d604f954478b3abbcc60a14dc05e242c/pendulum-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8af95e03e066826f0f4c65811cbee1b3123d4a45a1c3a2b4fc23c4b0dff893b5", size = 448673 },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/6a/68a8c7b8f1977d89aabfd0e2becb0921e5515dfb365097e98a522334a151/pendulum-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2165a8f33cb15e06c67070b8afc87a62b85c5a273e3aaa6bc9d15c93a4920d6f", size = 384891 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/e6/edd699300f47a3c53c0d8ed26e905b9a31057c3646211e58cc540716a440/pendulum-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ad5e65b874b5e56bd942546ea7ba9dd1d6a25121db1c517700f1c9de91b28518", size = 559558 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/97/95a44aa5e1763d3a966551ed0e12f56508d8dfcc60e1f0395909b6a08626/pendulum-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17fe4b2c844bbf5f0ece69cfd959fa02957c61317b2161763950d88fed8e13b9", size = 558240 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/91/fcd992eb36b77ab43f2cf44307b72c01a6fbb27f55c1bb2d4af30e9a6cb7/pendulum-3.0.0-cp312-none-win_amd64.whl", hash = "sha256:78f8f4e7efe5066aca24a7a57511b9c2119f5c2b5eb81c46ff9222ce11e0a7a5", size = 293456 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/60/ba8aa296ca6d76603d58146b4a222cd99e7da33831158b8c00240a896a56/pendulum-3.0.0-cp312-none-win_arm64.whl", hash = "sha256:28f49d8d1e32aae9c284a90b6bb3873eee15ec6e1d9042edd611b22a94ac462f", size = 288054 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/76/65e2e5c8fc7443c13cb50e87c52ab177a2660bd1f978b87de6962b309e07/pendulum-3.0.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:6a881d9c2a7f85bc9adafcfe671df5207f51f5715ae61f5d838b77a1356e8b7b", size = 362597 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/8d/d922528d8a5ec22e1247773a66467eb971a20194d9aa7740c3449f61094a/pendulum-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7762d2076b9b1cb718a6631ad6c16c23fc3fac76cbb8c454e81e80be98daa34", size = 353380 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/45/a3657c80bc86c31817dbe1646ef9a170aa2c5a5b1f55ff15ec82557f9509/pendulum-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8e36a8130819d97a479a0e7bf379b66b3b1b520e5dc46bd7eb14634338df8c", size = 336154 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/7e/0b4d36b0210261b6c709640a6dd67dd9c720c3a5c3d8041d6d05f568ba2b/pendulum-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dc843253ac373358ffc0711960e2dd5b94ab67530a3e204d85c6e8cb2c5fa10", size = 362743 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/b7/b31a9b353b63d131bddceb2fa3477fd1c6bd322793d91f7f0c7607f91c94/pendulum-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a78ad3635d609ceb1e97d6aedef6a6a6f93433ddb2312888e668365908c7120", size = 448992 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/e0/8d31270e49e85b28bc035c1d6c418b5842d2f63dcbbc32c8043be5fc1e16/pendulum-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a137e9e0d1f751e60e67d11fc67781a572db76b2296f7b4d44554761049d6", size = 385164 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/a2/4959088e14ef065f9c3700d3cb202b3aec0fc130f0b661d92c1465cb5a51/pendulum-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c95984037987f4a457bb760455d9ca80467be792236b69d0084f228a8ada0162", size = 559786 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/7f/93b13e1d98e654cf13c885546337e6b487c9c1b41de384fd05b21272c851/pendulum-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d29c6e578fe0f893766c0d286adbf0b3c726a4e2341eba0917ec79c50274ec16", size = 558443 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/9a/9c96f12c48d5e9e6056358907d691fd35f3f47a468185762b340721fa690/pendulum-3.0.0-cp38-none-win_amd64.whl", hash = "sha256:deaba8e16dbfcb3d7a6b5fabdd5a38b7c982809567479987b9c89572df62e027", size = 293520 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/05/49db61d1d0a951526575d36cd571ce389f9c08b7625579e28a0ada5ed842/pendulum-3.0.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b11aceea5b20b4b5382962b321dbc354af0defe35daa84e9ff3aae3c230df694", size = 362545 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/e7/783425867db5df0a9661c2e91d1bd052a0636aee65634e9d758e7b53527e/pendulum-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a90d4d504e82ad236afac9adca4d6a19e4865f717034fc69bafb112c320dcc8f", size = 353300 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/75/15411992749dd450bb365ae6cc0173480a1411b80cc0a9fdc7d548d254ce/pendulum-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:825799c6b66e3734227756fa746cc34b3549c48693325b8b9f823cb7d21b19ac", size = 336118 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/64/14f8cc3147c8ee8339ca37058259134c38092829f85076aa14b5437bf546/pendulum-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad769e98dc07972e24afe0cff8d365cb6f0ebc7e65620aa1976fcfbcadc4c6f3", size = 362600 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/c9/d7d20ffa63b0d154f59536dcd2c6361afebc6e44a76ca34131d492624299/pendulum-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6fc26907eb5fb8cc6188cc620bc2075a6c534d981a2f045daa5f79dfe50d512", size = 449101 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/aa/2d6846d7f382262d894902d3cf8ee66b02aee3bab2910db0004ca0f9ef18/pendulum-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c717eab1b6d898c00a3e0fa7781d615b5c5136bbd40abe82be100bb06df7a56", size = 385208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/1c/ad9726d5e1d85c5ba24f9021baf5f6f39ef18e94fa851a7c9231adca9e75/pendulum-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3ddd1d66d1a714ce43acfe337190be055cdc221d911fc886d5a3aae28e14b76d", size = 559851 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/1c/e13764e578f646a1b50faad8045bb05a755e5a913854c89a0e7dd4caaa19/pendulum-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:822172853d7a9cf6da95d7b66a16c7160cb99ae6df55d44373888181d7a06edc", size = 558520 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/4f/6c8569ba60b933c726f6c0051519167d9f9167e49d03c6074b57bb4c204a/pendulum-3.0.0-cp39-none-win_amd64.whl", hash = "sha256:840de1b49cf1ec54c225a2a6f4f0784d50bd47f68e41dc005b7f67c7d5b5f3ae", size = 293746 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/7f/24d8c167937d663a9cf6d5fc5e87a87bfa320c3f002d4fbbc7bd5ff3b6f8/pendulum-3.0.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3b1f74d1e6ffe5d01d6023870e2ce5c2191486928823196f8575dcc786e107b1", size = 362388 },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/e1/33775ee68f8bbb0da967dfd818706ee69e0a054f663ee6111d5c7639f67a/pendulum-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:729e9f93756a2cdfa77d0fc82068346e9731c7e884097160603872686e570f07", size = 353062 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/1b/c3e399148c0d69c2c84c2eda45cd3580990b13f36d0c96516591bf4def56/pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e586acc0b450cd21cbf0db6bae386237011b75260a3adceddc4be15334689a9a", size = 335871 },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/6b/23dde8bd3fb78f693b81bd8fc67769b2a461918d51ed6ddf486a1a97e199/pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7944ffc1f0099a79ff468ee9630c73f8c7835cd76fdb57ef7320e6a409df4", size = 384859 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/1b/a3e0387f586d6121a15e6d02f7ae8cc3cd1ebb136fd243c1c191136ed518/pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fa30af36bd8e50686846bdace37cf6707bdd044e5cb6e1109acbad3277232e04", size = 559441 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/23/91dea81265d5d11af0cd5053ca76730cc2c5ac14085c9a923d448e74c67f/pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:440215347b11914ae707981b9a57ab9c7b6983ab0babde07063c6ee75c0dc6e7", size = 558189 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/8a/166625d30f927e800e99f3f6556d8b3f4ad952c62d6a774844d73542b84b/pendulum-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:314c4038dc5e6a52991570f50edb2f08c339debdf8cea68ac355b32c4174e820", size = 293657 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/ff/83ce5b98c29d86d6afb951f9b73f0a1e4248fd74ea0f9104e3814d0fa479/pendulum-3.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c134ba2f0571d0b68b83f6972e2307a55a5a849e7dac8505c715c531d2a8795", size = 362442 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/c5/464ec6a334102bbcd4428d13ead2180e87b56da27a782a2ba2c15376120d/pendulum-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:385680812e7e18af200bb9b4a49777418c32422d05ad5a8eb85144c4a285907b", size = 353100 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/5a/4fb3a04cab1bf1c304c2d00d7d0f063e09776ac58a9a9c341a77e097ae08/pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eec91cd87c59fb32ec49eb722f375bd58f4be790cae11c1b70fac3ee4f00da0", size = 335919 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/a9/752c29e4ae27aa2e51940861a8c803e0966d16b5cca65229ef106426059b/pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4386bffeca23c4b69ad50a36211f75b35a4deb6210bdca112ac3043deb7e494a", size = 384928 },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/23/2816c02e5b3ce4006c186353a859ba2f7834e7ffc8ab61c95d71dfd10a91/pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dfbcf1661d7146d7698da4b86e7f04814221081e9fe154183e34f4c5f5fa3bf8", size = 559525 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/73/0b740805f94e7fa0915d7ae00d51a3676ca4c10401aa43ca611778075b4d/pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:04a1094a5aa1daa34a6b57c865b25f691848c61583fb22722a4df5699f6bf74c", size = 558323 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/b0/73581fe1755213a5a33b9f91c72a4d0705bbe3e7f19413b0af4878c73d70/pendulum-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5b0ec85b9045bd49dd3a3493a5e7ddfd31c36a2a60da387c419fa04abcaecb23", size = 293471 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/1c/69adbf18071d9c5571bed60aa881d76380d5121a7adc8c765375def08506/pendulum-3.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0a15b90129765b705eb2039062a6daf4d22c4e28d1a54fa260892e8c3ae6e157", size = 362376 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/18/2c0d556f1a6832fa4c5c1d466ec179087d250e654f6fa8c5723f6377c7d8/pendulum-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bb8f6d7acd67a67d6fedd361ad2958ff0539445ef51cbe8cd288db4306503cd0", size = 353041 },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/a6/951ff1930b796b272c9a372f0307c9e7f6b3ef9267972f404ee16bf32fd2/pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd69b15374bef7e4b4440612915315cc42e8575fcda2a3d7586a0d88192d0c88", size = 335877 },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/b3/2bb091f05d1e94bc20549c2318d65606f704fb881728cc2f6bf146037443/pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc00f8110db6898360c53c812872662e077eaf9c75515d53ecc65d886eec209a", size = 384858 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/51/b49eed0f7c23e7fb1a6affc482f6cc6fbf0bb76a2156c792a97646cd513e/pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:83a44e8b40655d0ba565a5c3d1365d27e3e6778ae2a05b69124db9e471255c4a", size = 559448 },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/24/65427759911ec8823e728a40fa86fa8e70f275d0eb036c14c631366f1213/pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1a3604e9fbc06b788041b2a8b78f75c243021e0f512447806a6d37ee5214905d", size = 558185 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/8b/f3ac476c70a39818a56dd24144cc2bee276e7a5fe3d254ba5238769224c8/pendulum-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:92c307ae7accebd06cbae4729f0ba9fa724df5f7d91a0964b1b972a22baa482b", size = 293645 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phonenumbers"
|
||||
version = "8.13.50"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/55/bf/6d62a014a43e1e485185b9652ef309f8ce8998f65c9a1b7d4b89c46cb76b/phonenumbers-8.13.50.tar.gz", hash = "sha256:e05ac6fb7b98c6d719a87ea895b9fc153673b4a51f455ec9afaf557ef4629da6", size = 2297710 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/d4/2011babd77b9709dd80f89aa74611fdace859e0571cd9e79ba3f95902441/phonenumbers-8.13.50-py2.py3-none-any.whl", hash = "sha256:bb95dbc0d9979c51f7ad94bcd780784938958861fbb4b75a2fe39ccd3d58954a", size = 2583092 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycountry"
|
||||
version = "24.6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "importlib-resources", marker = "python_full_version < '3.9'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/76/57/c389fa68c50590881a75b7883eeb3dc15e9e73a0fdc001cdd45c13290c92/pycountry-24.6.1.tar.gz", hash = "sha256:b61b3faccea67f87d10c1f2b0fc0be714409e8fcdcc1315613174f6466c10221", size = 6043910 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/ec/1fb891d8a2660716aadb2143235481d15ed1cbfe3ad669194690b0604492/pycountry-24.6.1-py3-none-any.whl", hash = "sha256:f1a4fb391cd7214f8eefd39556d740adcc233c778a27f8942c8dca351d6ce06f", size = 6335189 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.9.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "pydantic-core" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.23.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/8b/d3ae387f66277bd8104096d6ec0a145f4baa2966ebb2cad746c0920c9526/pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", size = 1867835 },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/76/f68272e4c3a7df8777798282c5e47d508274917f29992d84e1898f8908c7/pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", size = 1776689 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/69/5f945b4416f42ea3f3bc9d2aaec66c76084a6ff4ff27555bf9415ab43189/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", size = 1800748 },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/ab/891a7b0054bcc297fb02d44d05c50e68154e31788f2d9d41d0b72c89fdf7/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", size = 1806469 },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/7c/6e3fa122075d78f277a8431c4c608f061881b76c2b7faca01d317ee39b5d/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", size = 2002246 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/6f/22d5692b7ab63fc4acbc74de6ff61d185804a83160adba5e6cc6068e1128/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", size = 2659404 },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/ac/1e647dc1121c028b691028fa61a4e7477e6aeb5132628fde41dd34c1671f/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", size = 2053940 },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/75/984740c17f12c3ce18b5a2fcc4bdceb785cce7df1511a4ce89bca17c7e2d/pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", size = 1921437 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/74/13c5f606b64d93f0721e7768cd3e8b2102164866c207b8cd6f90bb15d24f/pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", size = 1966129 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/03/9c4aa5919457c7b57a016c1ab513b1a926ed9b2bb7915bf8e506bf65c34b/pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", size = 2110908 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/2c/053d33f029c5dc65e5cf44ff03ceeefb7cce908f8f3cca9265e7f9b540c8/pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", size = 1735278 },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/81/7dfe464eca78d76d31dd661b04b5f2036ec72ea8848dd87ab7375e185c23/pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", size = 1917453 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/30/890a583cd3f2be27ecf32b479d5d615710bb926d92da03e3f7838ff3e58b/pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", size = 1865160 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/9a/b634442e1253bc6889c87afe8bb59447f106ee042140bd57680b3b113ec7/pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", size = 1776777 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/9a/7816295124a6b08c24c96f9ce73085032d8bcbaf7e5a781cd41aa910c891/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", size = 1799244 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/8f/89c1405176903e567c5f99ec53387449e62f1121894aa9fc2c4fdc51a59b/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607", size = 1805307 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/a5/1a194447d0da1ef492e3470680c66048fef56fc1f1a25cafbea4bc1d1c48/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", size = 2000663 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/a5/1df8541651de4455e7d587cf556201b4f7997191e110bca3b589218745a5/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", size = 2655941 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/31/a3899b5ce02c4316865e390107f145089876dff7e1dfc770a231d836aed8/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", size = 2052105 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/aa/98e190f8745d5ec831f6d5449344c48c0627ac5fed4e5340a44b74878f8e/pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", size = 1919967 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/35/b6e00b6abb2acfee3e8f85558c02a0822e9a8b2f2d812ea8b9079b118ba0/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", size = 1964291 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/46/7bee6d32b69191cd649bbbd2361af79c472d72cb29bb2024f0b6e350ba06/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", size = 2109666 },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/ef/7b34f1b122a81b68ed0a7d0e564da9ccdc9a2924c8d6c6b5b11fa3a56970/pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", size = 1732940 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/76/37b7e76c645843ff46c1d73e046207311ef298d3f7b2f7d8f6ac60113071/pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", size = 1916804 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/3f/790c72662823955c4803487bcda8dfce5a9e2ddcaf709f7993e12ede29fd/pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", size = 1867828 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/f6/6ceeeb0005fabdf3f99a7fa1be52db41c328b438ebfa88f7b3f2815fb157/pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", size = 1748962 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/08/c1c49218a87c6e079730fed0357a5883c2f6fbf43e9da0eb2501384e0975/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", size = 1800821 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/92/e8f4de3453a3446ca2da5dc5d636fbd644dc9923f74812cfb63549df79ee/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", size = 1805527 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/06/cb8891f40d4b1d5744c24a3082e3031b16727fdc927cf4dc6bbe2fb9e9a3/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", size = 2002267 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/3b/7d2ab72afa3deb18baeb6c3373ad3181922da541bfae63aecbef51a9fadc/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", size = 2654837 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/a4/229432a701acd98575b88ccaff82e8435c75c44cb30522004afb263e3756/pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", size = 2054177 },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/bd/4a40a83e476af0a86e1f57559dd324b922b5e60faaa866de400efe033ca1/pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", size = 1920918 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/98/857e2bdae80432efff030812add720d6797b63c790f13e123c8274a3337b/pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", size = 1965814 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/87/cacb1152a821340e11f870e0fbd6613c2f05278dab5def47c7818eac1a22/pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", size = 2111058 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/ce/a3bd2de2582be6e5b187218896cac734377fcc8d5a54f98b83d710125ef0/pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", size = 1734749 },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/c8/e6ed2172bb2594a256c7756a70109fa31ab80d1cebb9003ad6c54e10c0d1/pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", size = 1920302 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/04/2580b2deaae37b3e30fc30c54298be938b973990b23612d6b61c7bdd01c7/pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", size = 1868200 },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/6e/e311bd0751505350f0cdcee3077841eb1f9253c5a1ddbad048cd9fbf7c6e/pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", size = 1749316 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/b4/95b5eb47c6dc8692508c3ca04a1f8d6f0884c9dacb34cf3357595cbe73be/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", size = 1800880 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/79/41c4f817acd7f42d94cd1e16526c062a7b089f66faed4bd30852314d9a66/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", size = 1807077 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/53/d13d1eb0a97d5c06cf7a225935d471e9c241afd389a333f40c703f214973/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", size = 2002859 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/7d/6b8a1eff453774b46cac8c849e99455b27167971a003212f668e94bc4c9c/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", size = 2661437 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/ea/8820f57f0b46e6148ee42d8216b15e8fe3b360944284bbc705bf34fac888/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", size = 2054404 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/36/d4ae869e473c3c7868e1cd1e2a1b9e13bce5cd1a7d287f6ac755a0b1575e/pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", size = 1921680 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/f8/eed5c65b80c4ac4494117e2101973b45fc655774ef647d17dde40a70f7d2/pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", size = 1966093 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/c8/1d42ce51d65e571ab53d466cae83434325a126811df7ce4861d9d97bee4b/pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", size = 2111437 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/c9/7fea9d13383c2ec6865919e09cffe44ab77e911eb281b53a4deaafd4c8e8/pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", size = 1735049 },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/95/dd7045c4caa2b73d0bf3b989d66b23cfbb7a0ef14ce99db15677a000a953/pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", size = 1920180 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/a9/5d582eb3204464284611f636b55c0a7410d748ff338756323cb1ce721b96/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", size = 1857135 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/57/faf36290933fe16717f97829eabfb1868182ac495f99cf0eda9f59687c9d/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", size = 1740583 },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/7c/d99e3513dc191c4fec363aef1bf4c8af9125d8fa53af7cb97e8babef4e40/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", size = 1793637 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/18/812222b6d18c2d13eebbb0f7cdc170a408d9ced65794fdb86147c77e1982/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", size = 1941963 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/36/c1f3642ac3f05e6bb4aec3ffc399fa3f84895d259cf5f0ce3054b7735c29/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", size = 1915332 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/ca/9c0854829311fb446020ebb540ee22509731abad886d2859c855dd29b904/pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", size = 1957926 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/1c/7836b67c42d0cd4441fcd9fafbf6a027ad4b79b6559f80cf11f89fd83648/pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", size = 2100342 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/f9/b6bcaf874f410564a78908739c80861a171788ef4d4f76f5009656672dfe/pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", size = 1920344 },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/fd/ac9cdfaaa7cf2d32590b807d900612b39acb25e5527c3c7e482f0553025b/pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", size = 1857850 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/fe/038f4b2bcae325ea643c8ad353191187a4c92a9c3b913b139289a6f2ef04/pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", size = 1740265 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/14/b215c9c3cbd1edaaea23014d4b3304260823f712d3fdee52549b19b25d62/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", size = 1793912 },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/de/2c3ad79b63ba564878cbce325be725929ba50089cd5156f89ea5155cb9b3/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", size = 1942870 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/55/c222af19e4644c741b3f3fe4fd8bbb6b4cdca87d8a49258b61cf7826b19e/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", size = 1915610 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/7a/9a8760692a6f76bb54bcd43f245ff3d8b603db695899bbc624099c00af80/pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", size = 1958403 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/91/9b03166feb914bb5698e2f6499e07c2617e2eebf69f9374d0358d7eb2009/pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", size = 2101154 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/d9/1d7ecb98318da4cb96986daaf0e20d66f1651d0aeb9e2d4435b916ce031d/pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", size = 1920855 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-extra-types"
|
||||
version = "2.10.1"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
all = [
|
||||
{ name = "pendulum" },
|
||||
{ name = "phonenumbers" },
|
||||
{ name = "pycountry" },
|
||||
{ name = "python-ulid" },
|
||||
{ name = "pytz" },
|
||||
{ name = "semver" },
|
||||
{ name = "tzdata" },
|
||||
]
|
||||
pendulum = [
|
||||
{ name = "pendulum" },
|
||||
]
|
||||
phonenumbers = [
|
||||
{ name = "phonenumbers" },
|
||||
]
|
||||
pycountry = [
|
||||
{ name = "pycountry" },
|
||||
]
|
||||
python-ulid = [
|
||||
{ name = "python-ulid" },
|
||||
]
|
||||
semver = [
|
||||
{ name = "semver" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "coverage", extra = ["toml"] },
|
||||
{ name = "dirty-equals" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-pretty" },
|
||||
]
|
||||
extra = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "coverage", extra = ["toml"] },
|
||||
{ name = "dirty-equals" },
|
||||
{ name = "mypy" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-pretty" },
|
||||
{ name = "ruff" },
|
||||
{ name = "types-pytz" },
|
||||
]
|
||||
lint = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "mypy" },
|
||||
{ name = "ruff" },
|
||||
{ name = "types-pytz" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "pendulum", marker = "extra == 'all'", specifier = ">=3.0.0,<4.0.0" },
|
||||
{ name = "pendulum", marker = "extra == 'pendulum'", specifier = ">=3.0.0,<4.0.0" },
|
||||
{ name = "phonenumbers", marker = "extra == 'all'", specifier = ">=8,<9" },
|
||||
{ name = "phonenumbers", marker = "extra == 'phonenumbers'", specifier = ">=8,<9" },
|
||||
{ name = "pycountry", marker = "extra == 'all'", specifier = ">=23" },
|
||||
{ name = "pycountry", marker = "extra == 'pycountry'", specifier = ">=23" },
|
||||
{ name = "pydantic", specifier = ">=2.5.2" },
|
||||
{ name = "python-ulid", marker = "python_full_version >= '3.9' and extra == 'all'", specifier = ">=1,<4" },
|
||||
{ name = "python-ulid", marker = "python_full_version >= '3.9' and extra == 'python-ulid'", specifier = ">=1,<4" },
|
||||
{ name = "python-ulid", marker = "python_full_version < '3.9' and extra == 'all'", specifier = ">=1,<2" },
|
||||
{ name = "python-ulid", marker = "python_full_version < '3.9' and extra == 'python-ulid'", specifier = ">=1,<2" },
|
||||
{ name = "pytz", marker = "extra == 'all'", specifier = ">=2024.1" },
|
||||
{ name = "semver", marker = "extra == 'all'", specifier = "~=3.0.2" },
|
||||
{ name = "semver", marker = "extra == 'all'", specifier = ">=3.0.2" },
|
||||
{ name = "semver", marker = "extra == 'semver'", specifier = ">=3.0.2" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "tzdata", marker = "extra == 'all'", specifier = ">=2024.1" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "coverage", extras = ["toml"], specifier = ">=7.6.1" },
|
||||
{ name = "dirty-equals", specifier = ">=0.7.1" },
|
||||
{ name = "pytest", specifier = ">=8.3.2" },
|
||||
{ name = "pytest-pretty", specifier = ">=1.2.0" },
|
||||
]
|
||||
extra = [
|
||||
{ name = "annotated-types", specifier = ">=0.7.0" },
|
||||
{ name = "coverage", extras = ["toml"], specifier = ">=7.6.1" },
|
||||
{ name = "dirty-equals", specifier = ">=0.7.1" },
|
||||
{ name = "mypy", specifier = ">=0.910" },
|
||||
{ name = "pytest", specifier = ">=8.3.2" },
|
||||
{ name = "pytest-pretty", specifier = ">=1.2.0" },
|
||||
{ name = "ruff", specifier = ">=0.7.4" },
|
||||
{ name = "types-pytz", specifier = ">=2024.1.0.20240417" },
|
||||
]
|
||||
lint = [
|
||||
{ name = "annotated-types", specifier = ">=0.7.0" },
|
||||
{ name = "mypy", specifier = ">=0.910" },
|
||||
{ name = "ruff", specifier = ">=0.7.4" },
|
||||
{ name = "types-pytz", specifier = ">=2024.1.0.20240417" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-pretty"
|
||||
version = "1.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pytest" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a5/18/30ad0408295f3157f7a4913f0eaa51a0a377ebad0ffa51ff239e833c6c72/pytest_pretty-1.2.0.tar.gz", hash = "sha256:105a355f128e392860ad2c478ae173ff96d2f03044692f9818ff3d49205d3a60", size = 6542 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/fe/d44d391312c1b8abee2af58ee70fabb1c00b6577ac4e0bdf25b70c1caffb/pytest_pretty-1.2.0-py3-none-any.whl", hash = "sha256:6f79122bf53864ae2951b6c9e94d7a06a87ef753476acd4588aeac018f062036", size = 6180 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "six" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-ulid"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e8/8b/0580d8ee0a73a3f3869488856737c429cbaa08b63c3506275f383c4771a8/python-ulid-1.1.0.tar.gz", hash = "sha256:5fb5e4a91db8ca93e8938a613360b3def299b60d41f847279a8c39c9b2e9c65e", size = 19992 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/89/8e/c30b08ee9b8dc9b4a10e782c2a7fd5de55388201ddebfe0f7ab99dfbb349/python_ulid-1.1.0-py3-none-any.whl", hash = "sha256:88c952f6be133dbede19c907d72d26717d2691ec8421512b573144794d891e24", size = 9360 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2024.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3a/31/3c70bf7603cc2dca0f19bdc53b4537a797747a58875b552c8c413d963a3f/pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", size = 319692 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b2/d6/a2373f3ba7180ddb44420d2a9d1f1510e1a4d162b3d27282bedcb09c8da9/ruff-0.8.0.tar.gz", hash = "sha256:a7ccfe6331bf8c8dad715753e157457faf7351c2b69f62f32c165c2dbcbacd44", size = 3276537 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/77/e889ee3ce7fd8baa3ed1b77a03b9fb8ec1be68be1418261522fd6a5405e0/ruff-0.8.0-py3-none-linux_armv6l.whl", hash = "sha256:fcb1bf2cc6706adae9d79c8d86478677e3bbd4ced796ccad106fd4776d395fea", size = 10518283 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/c8/0a47de01edf19fb22f5f9b7964f46a68d0bdff20144d134556ffd1ba9154/ruff-0.8.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:295bb4c02d58ff2ef4378a1870c20af30723013f441c9d1637a008baaf928c8b", size = 10317691 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/17/9885e4a0eeae07abd2a4ebabc3246f556719f24efa477ba2739146c4635a/ruff-0.8.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b1f1c76b47c18fa92ee78b60d2d20d7e866c55ee603e7d19c1e991fad933a9a", size = 9940999 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/cd/46b6f7043597eb318b5f5482c8ae8f5491cccce771e85f59d23106f2d179/ruff-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb0d4f250a7711b67ad513fde67e8870109e5ce590a801c3722580fe98c33a99", size = 10772437 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/87/afc95aeb8bc78b1d8a3461717a4419c05aa8aa943d4c9cbd441630f85584/ruff-0.8.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e55cce9aa93c5d0d4e3937e47b169035c7e91c8655b0974e61bb79cf398d49c", size = 10299156 },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/fa/04c647bb809c4d65e8eae1ed1c654d9481b21dd942e743cd33511687b9f9/ruff-0.8.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f4cd64916d8e732ce6b87f3f5296a8942d285bbbc161acee7fe561134af64f9", size = 11325819 },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/26/7dad6e7d833d391a8a1afe4ee70ca6f36c4a297d3cca83ef10e83e9aacf3/ruff-0.8.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c5c1466be2a2ebdf7c5450dd5d980cc87c8ba6976fb82582fea18823da6fa362", size = 12023927 },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/a0/be5296dda6428ba8a13bda8d09fbc0e14c810b485478733886e61597ae2b/ruff-0.8.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2dabfd05b96b7b8f2da00d53c514eea842bff83e41e1cceb08ae1966254a51df", size = 11589702 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/3f/7602eb11d2886db545834182a9dbe500b8211fcbc9b4064bf9d358bbbbb4/ruff-0.8.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:facebdfe5a5af6b1588a1d26d170635ead6892d0e314477e80256ef4a8470cf3", size = 12782936 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/5d/083181bdec4ec92a431c1291d3fff65eef3ded630a4b55eb735000ef5f3b/ruff-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a8e86bae0dbd749c815211ca11e3a7bd559b9710746c559ed63106d382bd9c", size = 11138488 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/23/c12cdef58413cee2436d6a177aa06f7a366ebbca916cf10820706f632459/ruff-0.8.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:85e654f0ded7befe2d61eeaf3d3b1e4ef3894469cd664ffa85006c7720f1e4a2", size = 10744474 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/61/a12f3b81520083cd7c5caa24ba61bb99fd1060256482eff0ef04cc5ccd1b/ruff-0.8.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:83a55679c4cb449fa527b8497cadf54f076603cc36779b2170b24f704171ce70", size = 10369029 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/2a/c013f4f3e4a54596c369cee74c24870ed1d534f31a35504908b1fc97017a/ruff-0.8.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:812e2052121634cf13cd6fddf0c1871d0ead1aad40a1a258753c04c18bb71bbd", size = 10867481 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/f7/685b1e1d42a3e94ceb25eab23c70bdd8c0ab66a43121ef83fe6db5a58756/ruff-0.8.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:780d5d8523c04202184405e60c98d7595bdb498c3c6abba3b6d4cdf2ca2af426", size = 11237117 },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/20/401132c0908e8837625e3b7e32df9962e7cd681a4df1e16a10e2a5b4ecda/ruff-0.8.0-py3-none-win32.whl", hash = "sha256:5fdb6efecc3eb60bba5819679466471fd7d13c53487df7248d6e27146e985468", size = 8783511 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/5c/4d800fca7854f62ad77f2c0d99b4b585f03e2d87a6ec1ecea85543a14a3c/ruff-0.8.0-py3-none-win_amd64.whl", hash = "sha256:582891c57b96228d146725975fbb942e1f30a0c4ba19722e692ca3eb25cc9b4f", size = 9559876 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/bc/cc8a6a5ca4960b226dc15dd8fb511dd11f2014ff89d325c0b9b9faa9871f/ruff-0.8.0-py3-none-win_arm64.whl", hash = "sha256:ba93e6294e9a737cd726b74b09a6972e36bb511f9a102f1d9a7e1ce94dd206a6", size = 8939733 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "3.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/41/6c/a536cc008f38fd83b3c1b98ce19ead13b746b5588c9a0cb9dd9f6ea434bc/semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc", size = 214988 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/77/0cc7a8a3bc7e53d07e8f47f147b92b0960e902b8254859f4aee5c4d7866b/semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4", size = 17099 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-machine"
|
||||
version = "2.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "python-dateutil" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/82d358c4d53555f031c2343d1c235b56b9f3b0a60ac3adc555778fe87506/time_machine-2.15.0.tar.gz", hash = "sha256:ebd2e63baa117ded04b978813fcd1279d3fc6be2149c9cac75c716b6f1db774c", size = 25067 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/67/47/35413db37da55865fdbf60649bcb948cc2559f420ef4e91e77e4e24c71b8/time_machine-2.15.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:892d016789b59950989b2db188dcd46cf16d34e8daf2343e33b679b0c5fd1001", size = 20779 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/c3/fda6d2336737d0331eb55357db1dc916af14c4fda77c69ad8b3733b003c4/time_machine-2.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4428bdae507996aa3fdeb4727bca09e26306fa64a502e7335207252684516cbf", size = 17040 },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/e1/71200f24d668e5183e875a08ba5e557b6107c1b7d57fa6d54ac24ad10234/time_machine-2.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0302568338c8bd333ed0698231dbb781b70ead1a5579b4ac734b9bf88313229f", size = 34811 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/2f/4b9289ea07978ad5c3469c872c7eeadf5f5b3a1dcebe2fb274c2486fc220/time_machine-2.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18fc4740073e67071472c48355775ec6d1b93af5c675524b7de2474e0dcd8741", size = 32820 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/9e/9f838c91d2248d716281af60dfea4131438c6ad6d7405ebc6e47f8c25c3b/time_machine-2.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:768d33b484a35da93731cc99bdc926b539240a78673216cdc6306833d9072350", size = 34635 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/10/1048b5ba6de55779563f005de5fbfb764727bf9678ad7701cea480b3816c/time_machine-2.15.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:73a8c8160d2a170dadcad5b82fb5ee53236a19cec0996651cf4d21da0a2574d5", size = 34326 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/82/6b4df8e5abf754b0ccceeb59fa32486d28c65f67d4ada37ff8b1e9f52006/time_machine-2.15.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:09fd839a321a92aa8183206c383b9725eaf4e0a28a70e4cb87db292b352eeefb", size = 32639 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/07/95e380c46136252401d97f613782a10061b3c11b61edaeb78e83aedc1a88/time_machine-2.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:838a6d117739f1ae6ecc45ec630fa694f41a85c0d07b1f3b1db2a6cc52c1808b", size = 34021 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/0c/6595fa82bd70bc7e8065bfc6534e51a27c18978f7c158d6392c979cace2c/time_machine-2.15.0-cp310-cp310-win32.whl", hash = "sha256:d24d2ec74923b49bce7618e3e7762baa6be74e624d9829d5632321de102bf386", size = 19413 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/3d/cb3c1cecfeb4b6423302ee1b2863617390500f67526f0fc1fb5641db05f6/time_machine-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:95c8e7036cf442480d0bf6f5fde371e1eb6dbbf5391d7bdb8db73bd8a732b538", size = 20280 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/aa/96aaac88738369fba43d5cb076bb09290b1a2cbd84210bcc0a9a519c7970/time_machine-2.15.0-cp310-cp310-win_arm64.whl", hash = "sha256:660810cd27a8a94cb5e845e8f28a95e70b01ff0c45466d394c4a0cba5a0ae279", size = 18392 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/54/829ab196c3306eb4cee95e3c8e7d004e15877b36479de5d2ecc72fc1d3d4/time_machine-2.15.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:674097dd54a0bbd555e7927092c74428c4c07268ad52bca38cfccc3214707e50", size = 20448 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/48/a06f8c7db768db501a60210a48f3d37b7b3d65ca85aa8dc08147eb204b4a/time_machine-2.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4e83fd6112808d1d14d1a57397c6fa3bd71bb2f3b8800036e12366e3680819b9", size = 16897 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/f8/73265927e3da54a417536dc3d8c9aad806b62b8133099a7ee12661aba1a3/time_machine-2.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b095a1de40ca1afaeae8df3f45e26b645094a1912e6e6871e725fcf06ecdb74a", size = 32789 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/a4/bcf8ad40a4c6973a67aba5df7ed704dc34256835fb074cfb4d4caa0f93a5/time_machine-2.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4601fe7a6b74c6fd9207e614d9db2a20dd4befd4d314677a0feac13a67189707", size = 30911 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/87/a6de1b187f5468781e0e722c877323625227151cc8ffff363a7391b01149/time_machine-2.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:245ef73f9927b7d4909d554a6a0284dbc5dee9730adea599e430b37c9e9fa203", size = 32644 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/1f/7378d5a032467891a1005e546532223b97c53440c6359b1133696a5cb1ef/time_machine-2.15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:704abc7f3403584cca9c01c5809812e0bd70632ea4251389fae4f45e11aad94f", size = 32472 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/14/2fab61ad2c9a831925bce3d5e341fa2108ba062c2de0c190569e1ee6a1c9/time_machine-2.15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6425001e50a0c82108caed438233066cea04d42a8fc9c49bfcf081a5b96e5b4e", size = 30882 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/01/f5146b9956b548072000a87f3eb8dbb2591ada1516a5d889aa12b373948f/time_machine-2.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5d4073b754f90b19f28d036ec5143d3fca3a75e4d4241d78790a6178b00bb373", size = 32176 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/09/8a8488e6d3faf3cb68d078f27ca94aa3ba1bc08d5f804265c590208a70f5/time_machine-2.15.0-cp311-cp311-win32.whl", hash = "sha256:8817b0f7d7830215261b18db83c9c3ef1da6bb64da5c292d7c70b9a46e5a6745", size = 19305 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/33/d8411b197a08eedb3ce086022cdf4faf1f15738607a2d943fd5286f57fdd/time_machine-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:ddad27a62df2ea47b7b483009fbfcf167a71d702cbd8e2eefd9ddc1c93146658", size = 20210 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/f5/e9b5d7be612403e570a42af5c2823506877e726f77f2d6ff272d72d0aed3/time_machine-2.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:6f021aa2dbd8fbfe54d3fa2258518129108b7496922b3bcff2cf5991078eec67", size = 18278 },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/47/46bf332f4ecd7f35e197131b9c23daa39423cf71b814e36e9d5df3cf2380/time_machine-2.15.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a22f47c34ee1fcf7d93a8c5c93135499aac879d9d5d8f820bd28571a30fdabcd", size = 20436 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/36/9990f16868ffdefe6b5aecfdfbcb11718230e414ca61a887fbee884f70e5/time_machine-2.15.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b684f8ecdeacd6baabc17b15ac1b054ca62029193e6c5367ef00b3516671de80", size = 16926 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/2d/007955a0899cd079a400bc204c03edc76274de2471d94ca235ff587a6eba/time_machine-2.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f7add997684bc6141e1c80f6ba0c38ffe316ba277a4074e61b1b7b4f5a172bf", size = 17157 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/e2/66d26450f9bfd1b019abdefbf0c62e760efc8992c7bf88d6c18f7ea6b94a/time_machine-2.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31af56399bf7c9ef76a3f7b6d9471dffa8f06ee373c194a374b69523f9061de9", size = 34005 },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/2c/dc2c42200aee6b47a55274d984736f7507ecfbfd0345114ec511ec444bef/time_machine-2.15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b94cba3edfc54bcb3ab5be616a2f50fa48be438e5af970824efdf882d1bc31", size = 31926 },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/59/10d8faecbd233b0da831eb9973c3e650c83fb3d443edb607b6b26c9688ac/time_machine-2.15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3862dda89bdb05f9d521b08fdcb24b19a7dd9f559ae324f4301ba7a07b6eea64", size = 33685 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/a4/702ad9e328cbc7b3f1833dee4886d0994e52bc2d9640effa64bccc7740fa/time_machine-2.15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1790481a6b9ce38888f22ce30710244067898c3ac4805a0e061e381f3db3506", size = 33609 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/9d/6009d28ad395a45b5bb91af31616494b4e61d6d9df252d0e5933cd3aa8f1/time_machine-2.15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a731c03bc00552ee6cc685a59616d36003124e7e04c6ddf65c2c47f1c3d85480", size = 31737 },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/22/b55df08cf48d46af93ee2f4310dd88c8519bc5f98afd24af57a81a5d5272/time_machine-2.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e6776840aea3ff5ab6924b50117957da62db51b109b3b491c0d5817a804b1a8e", size = 33253 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/d7/bb5e92f0b0268cd13baad874d82b0e964a847cf52740464abeec48dc1642/time_machine-2.15.0-cp312-cp312-win32.whl", hash = "sha256:9479530e3fce65f6149058071fa4df8150025f15b43b103445f619842981a87c", size = 19369 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/33/276537ba292fc7ee67e6aef7566b2a6b313dbc4d479e5e80eed43094ef48/time_machine-2.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f3ab4185c1f72010846ca9fccb08349e23a2b52982a18d9870e848ce9f1c86", size = 20219 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/0e/e8b75032248f59a2bc5c125d3a41242b1e577caa07585c42b22373d6466d/time_machine-2.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:c0473dfa8f17c6a9a250b2bd6a5b62af3aa7d22518f701649115f1085d5e35ab", size = 18297 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/a1/ebe212530628aa29a86a771ca77cb2d1ead667382cfa89a3fb849e3f0108/time_machine-2.15.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f50f10058b884d45cd8a50423bf561b1f9f9df7058abeb8b318700c8bcf4bb54", size = 20492 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/0d/2a19951729e50d8809e161e533585c0be5ae39c0cf40140877353847b9b5/time_machine-2.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:df6f618b98f0848fd8d07039541e10f23db679d8283f8719e870a98e1ef8e639", size = 16961 },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/eb/33cf2173758b128f55c880c492e17b70f6c325e7bee879f9b0171cfe02a0/time_machine-2.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52468a0784544eba708c0ae6bc5e8c5dcfd685495a60f7f74028662c984bd9cd", size = 34051 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/23/da9a7935a7be952ab6163caf976b6bad049f6e117f3a396ecc381b077cb6/time_machine-2.15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c08800c28160f4d32ca510128b4e201a43c813e7a2dd53178fa79ebe050eba13", size = 31966 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/0d/a8e3cbd91ffa98b0fa50b6e29d03151f37aa04cca4dd658e33cdf2b4731e/time_machine-2.15.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65d395211736d9844537a530287a7c64b9fda1d353e899a0e1723986a0859154", size = 33727 },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/53/c084031980706517cfbae9f462e455d61c7cbf9b66a8a83bcc5b79d00836/time_machine-2.15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b177d334a35bf2ce103bfe4e0e416e4ee824dd33386ea73fa7491c17cc61897", size = 33690 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/30/5c87e8709ba00c893faf8a9bddf06abf317fdc6103fe78bdf99c53ab444f/time_machine-2.15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9a6a9342fae113b12aab42c790880c549d9ba695b8deff27ee08096eedd67569", size = 31809 },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/7b/92ac7c556cd123bf8b23dbae3cf4a273c276110b87d0c4b5600c2cec8e70/time_machine-2.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bcbb25029ee8756f10c6473cea5ef21707a1d9a8752cdf29fad3a5f34aa4a313", size = 33325 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/71/36c74bab3d4e4385d31610b367da1535a36d17358df058e0920a7510e17c/time_machine-2.15.0-cp313-cp313-win32.whl", hash = "sha256:29b988b1f09f2a083b12b6b054787b799ae91ee15bb0e9de3e48f880e4d68674", size = 19397 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/69/ea5976c43a673894f2fa85a05b28a610b474472f393e59722a6946f7070b/time_machine-2.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:d828721dcbcb94b904a6b25df67c2513ecd24cd9e36694f38b9f0fa71c7c6103", size = 20242 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/c8/26367d0b8dfaf7445576fe0051bff61b8f5be752e7bf3e8807ed7fa3a343/time_machine-2.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:008bd668d933b1a029c81805bcdc0132390c2545b103cf8e6709e3adbc37989d", size = 18337 },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/54/eeac8568cad4f3eb255cc78f1fa2c36147afd3fcba770283bf2b2a188b33/time_machine-2.15.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e99689f6c6b9ca6e2fc7a75d140e38c5a7985dab61fe1f4e506268f7e9844e05", size = 20674 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/82/488341de4c03c0856aaf5db74f2a8fe18dcc7657401334c54c4aa6cb0fc6/time_machine-2.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:671e88a6209a1cf415dc0f8c67d2b2d3b55b436cc63801a518f9800ebd752959", size = 16990 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/cc/0ca559e71be4eb05917d02364f4d356351b31dd0d6ff3c4c86fa4de0a03e/time_machine-2.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b2d28daf4cabc698aafb12135525d87dc1f2f893cbd29a8a6fe0d8d36d1342c", size = 35501 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/a0/14905a5feecc6d2e87ebe6dd2b044358422836ed173071cdc1245aa5ec88/time_machine-2.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cd9f057457d12604be18b623bcd5ae7d0b917ad66cb510ee1135d5f123666e2", size = 33430 },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/a4/282b65b4d835dfd7b863777cc4206bec375285bda884dc22bd1264716f6a/time_machine-2.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97dc6793e512a62ba9eab250134a2e67372c16ae9948e73d27c2ef355356e2e1", size = 35366 },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/8e/f7db3f641f1ff86b98594c9cf8d71c8d292cc2bde06c1369ce4745494cc5/time_machine-2.15.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0630a32e9ebcf2fac3704365b31e271fef6eabd6fedfa404cd8dbd244f7fc84d", size = 34373 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/9f/8c8ac57ccb29e692e0940e58515a9afb844d2d11b7f057a0fe153bfe4877/time_machine-2.15.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:617c9a92d8d8f60d5ef39e76596620503752a09f834a218e5b83be352fdd6c91", size = 32667 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/e7/f0c6f9507b0bbfdec54d256b6efc9417ae1a01ce6320c2a42235b807cf86/time_machine-2.15.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3f7eadd820e792de33a9ec91f8178a2b9088e4e8b9a166953419ddc4ec5f7cfe", size = 34070 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/82/ac2d8343db8dade1372457d7a5694f069882d9eac110ddce2643ef0501aa/time_machine-2.15.0-cp38-cp38-win32.whl", hash = "sha256:b7b647684eb2e1fd1e5e6b101249d5fe9d6117c117b5e336ad8dd75af48d2d1f", size = 19396 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/12/ac7bb1e932536fce359e021a62c2a5a30c4e470293d6f8b2fb47077562dc/time_machine-2.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b48abd7745caec1a78a16a048966cde14ff6ccb04d471a7201532648d3f77d14", size = 20266 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/bf/d9689e1fa669e575c3ed57bf4f9205a9b5fbe703dc7ef89ba5ce9aa39a38/time_machine-2.15.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c2b1c91b437133c672e374857eccb1dd2c2d9f8477ae3b35138382d5ef19846", size = 20775 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/4b/4314a7882b470c52cd527601107b1163e19d37fb1eb31eea0f8d73d0b178/time_machine-2.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:79bf1ef6850182e09d86e61fa31717da56014a3b2234afb025fca1f2a43ac07b", size = 17037 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/b8/adf2f8b8e10f6f5e498b0cddd103f6520144af53fb27b5a01eca50812a92/time_machine-2.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:658ea8477fa020f08435fb7277635eb0b50cd5206b9d4cbe10e9a5466b01f855", size = 34511 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/86/fda41a9e8115fd377f2d4d15c91a414f75cb8f2cd7f8bde974855a0f381f/time_machine-2.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c947135750d20f35acac290c34f1acf5771fc166a3fbc0e3816a97c756aaa5f5", size = 32533 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/7e/1e2e69fee659f00715f12392cabea1920245504862eab2caac6e3f30de5b/time_machine-2.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dee3a0dd1866988c49a5d00564404db9bcdf49ca92f9c4e8b6c99609d64e698", size = 34348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/da/8db2df73ebe9f23af25b05f1720b108a145805a8c83d5ff8248e2d3cbcfa/time_machine-2.15.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c596920d6017702a36e3a43fd8110a84e87d6229f30b84bd5640cbae9b5145da", size = 34081 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/c7/9202404f8885257c09c98d3e5186b989b6b482a2983dc24c81bd0333e668/time_machine-2.15.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:014589d0edd4aa14f8d63985745565e8cbbe48461d6c004a96000b47f6b44e78", size = 32357 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/79/482a69c31259c3c2efcd9e73ea4a0a4d315103836c1667875612288bca28/time_machine-2.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5ff655716cd13a242eef8cf5d368074e8b396ff86508a5933e7cff4f2b3eb3c2", size = 33742 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/39/89725d12a3552bb9113528d8f9aa7188e1660b377b74e7d72e8ab5eeff06/time_machine-2.15.0-cp39-cp39-win32.whl", hash = "sha256:1168eebd7af7e6e3e2fd378c16ca917b97dd81c89a1f1f9e1daa985c81699d90", size = 19410 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/0c/50e86c4a7b72d2bdc658492b13e804f933814f86f34c4350758d1ab87586/time_machine-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:c344eb09fcfbf71e5b5847d4f188fec98e1c3a976125ef571eac5f1c39e7a5e5", size = 20281 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/4d/f8ad3b0c50a268a9ea766c9533866bba6a7717a5324c84e356abb7347fa4/time_machine-2.15.0-cp39-cp39-win_arm64.whl", hash = "sha256:899f1a856b3bebb82b6cbc3c0014834b583b83f246b28e462a031ec1b766130b", size = 18387 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1e/e4/1b6cbcc82d8832dd0ce34767d5c560df8a3547ad8cbc427f34601415930a/tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8", size = 16622 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/de/f7/4da0ffe1892122c9ea096c57f64c2753ae5dd3ce85488802d11b0992cc6d/tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391", size = 13750 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-pytz"
|
||||
version = "2024.2.0.20241003"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/d0/73aa3063a9ef9881bd7103cb4ae379bfd8fafda0e86b01b694d676313a4b/types-pytz-2024.2.0.20241003.tar.gz", hash = "sha256:575dc38f385a922a212bac00a7d6d2e16e141132a3c955078f4a4fd13ed6cb44", size = 5474 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/86/60/2a2977ce0f91255bbb668350b127a801a06ad37c326a2e5bfd52f03e0784/types_pytz-2024.2.0.20241003-py3-none-any.whl", hash = "sha256:3e22df1336c0c6ad1d29163c8fda82736909eb977281cb823c57f8bae07118b7", size = 5245 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2024.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e1/34/943888654477a574a86a98e9896bae89c7aa15078ec29f490fef2f1e5384/tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", size = 193282 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.20.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200 },
|
||||
]
|
Loading…
Add table
Reference in a new issue