diff --git a/.github/workflows/lint-and-type-check.yml b/.github/workflows/lint-and-type-check.yml index b92704d..f1d52d7 100644 --- a/.github/workflows/lint-and-type-check.yml +++ b/.github/workflows/lint-and-type-check.yml @@ -46,8 +46,11 @@ jobs: enable-cache: false python-version: "3.13" + - name: Install project + run: uv sync --all-extras + - name: Run mypy - run: uv run mypy . + run: uv run mypy - name: Run ruff lint run: uv run ruff check . diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e9a8c47..d80f5f5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -49,13 +49,17 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Install the project - run: uv sync --all-extras + - name: Run tests without extras + run: uv run coverage run -m pytest -vv - - name: Run tests and generate coverage - run: | - uv run coverage run -m pytest -vv - uv run coverage xml + - name: Run tests with extras + run: uv run --all-extras coverage run --append -m pytest -vv + + - name: Show coverage + run: uv run coverage report -m + + - name: Generate coverage + run: uv run coverage xml - name: Upload coverage to Codecov uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 diff --git a/.gitignore b/.gitignore index 1ecb682..51cd689 100644 --- a/.gitignore +++ b/.gitignore @@ -160,5 +160,4 @@ cython_debug/ #.idea/ .coverage -_media.gql test.py diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 0000000..75cb831 --- /dev/null +++ b/NOTES.md @@ -0,0 +1,94 @@ +A small notes file to keep track of the behaviors and quirks of different +archive formats, or the libraries I’m using for them, that I’ve discovered +during development. + +I often found myself repeatedly testing various operations on each library to +see how they behave, and then weeks later, I would forget the results and do +it all over again. So I decided it is worth writing it all down in one place. + +## Reading Non-Files (e.g., directories) + +| Archive Type | Behavior when attempting to read a directory | +| ------------------ | -------------------------------------------- | +| tarfile.TarFile | Returns `None` | +| zipfile.ZipFile | Returns empty `b""` | +| rarfile.RarFile | Raises `io.UnsupportedOperation` | +| py7zr.SevenZipFile | Raises `KeyError` | + +I find returning empty bytes unacceptable, since you can no longer tell +apart an empty file and a directory. So I am left with either returning +`None` or raising an Exception. I ended up going with an Exception (I think +I'll call it `ArchiveMemberNotAFileError`) because 2 out of 4 libraries do +it and it seems the most "correct" behavior to me. Reading a directory is +an error (pathlib will also raise if you try reading a directory with +`.read_bytes()`) and it should be treated as such. + +## Trailing `/` in Directory Names: Who Cares? + +1. `tarfile.TarFile` + + - A trailing `/` doesn’t matter. + - Methods like `getmember(name)` automatically strip it (See: [`tarfile.py#L2059`](https://github.com/python/cpython/blob/be388836c0d4a970e83ca5540c512d94afd13435/Lib/tarfile.py#L2059)). + - `getnames()` and `TarInfo.name` never include the trailing `/`. + +2. `zipfile.ZipFile` + + - A trailing `/` is significant. + - `getinfo(name)` requires the exact directory name; omitting the `/` raises a `KeyError`. + - `namelist()` and `ZipInfo.filename` preserve the trailing `/`. + +3. `py7zr.SevenZipFile` + + - Behaves much like `tarfile.TarFile`. + - `getinfo(name)` strips the trailing slash (See: [`py7zr.py#L944`](https://github.com/miurahr/py7zr/blob/9a5a5b9bc39bc0afaac60f3cc7ee6842bd167f35/py7zr/py7zr.py#L944)): + - `namelist()` and `FileInfo.filename` do not include trailing `/`. + +4. `rarfile.RarFile` + - Strips trailing `/` for lookups (See: [`rarfile.py#L1093`](https://github.com/markokr/rarfile/blob/db1df339574e76dafb8457e848a09c3c074b03a0/rarfile.py#L1093)). + - But `getinfo().filename` and `namelist()` keep the trailing `/`. + +### Summary + +| Archive Type | `/` Stripped for Lookup | `/` Preserved in Listing | +| ------------------ | ----------------------- | ------------------------ | +| tarfile.TarFile | ✅ Yes | ❌ No | +| zipfile.ZipFile | ❌ No | ✅ Yes | +| py7zr.SevenZipFile | ✅ Yes | ❌ No | +| rarfile.RarFile | ✅ Yes | ✅ Yes | + +For `ArchiveFile`, I cannot simply discard the trailing `/` +because `zipfile.ZipFile` requires it. Under the hood, +names are normalized for lookups so that calls like: + +```python +archive_file.get_member("foo/bar/") +``` + +will work regardless of the archive format. + +However, normalization alone doesn’t solve everything. +Consider this snippet: + +```python +member = archive_file.get_member("foo/bar/") +assert "foo/bar/" in archive_file.get_names() +assert member.name == "foo/bar/" +``` + +The goal is for this code to pass consistently, +no matter which archive format is used. This is achieved by: + +1. Normalizing lookups according to the preferences of the underlying archive format. + - For example, `/` is stripped for SevenZipFile, but kept for ZipFile. + +2. Preserving trailing `/` in listings so that checks like: + + ```python + "foo/bar/" in archive_file.get_names() + archive_file.get_member("foo/bar/").name == "foo/bar/" + ``` + work reliably. For formats that discard the `/` (TarFile and SevenZipFile), we add it back in. + +Not doing this would force users to know the details of the +underlying archive format just to perform a simple check +which would be tedious and error-prone. diff --git a/justfile b/justfile new file mode 100644 index 0000000..410c5b2 --- /dev/null +++ b/justfile @@ -0,0 +1,16 @@ +set shell := ["sh", "-c"] + +default: lint test + +lint: + uv run ruff check . --fix + uv run ruff format . + uv run mypy + +test *args: + rm -f .coverage + uv sync --locked + uv run coverage run -m pytest {{args}} + uv sync --all-extras --locked + uv run coverage run --append -m pytest {{args}} + uv run coverage report -m diff --git a/mkdocs.yml b/mkdocs.yml index 21e1ba5..3c87867 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ repo_url: https://github.com/Ravencentric/archivefile edit_uri: edit/main/docs/ theme: + language: en icon: repo: fontawesome/brands/github edit: material/pencil diff --git a/pyproject.toml b/pyproject.toml index 813ad63..3878ff3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,34 +7,30 @@ requires-python = ">=3.10" readme = "README.md" license = "Unlicense" keywords = [ - "archive", - "archivefile", - "zipfile", - "tarfile", - "sevenzip", - "rarfile", + "archive", + "archivefile", + "zipfile", + "tarfile", + "sevenzip", + "7z", + "rarfile", ] classifiers = [ - "License :: OSI Approved :: The Unlicense (Unlicense)", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Topic :: System :: Archiving", - "Topic :: System :: Archiving :: Compression", - "Typing :: Typed", -] -dependencies = [ - "rarfile>=4.2", - "py7zr>=0.21.1", - "pydantic>=2.8.2", - "typing-extensions>=4.12.2", + "License :: OSI Approved :: The Unlicense (Unlicense)", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: System :: Archiving", + "Topic :: System :: Archiving :: Compression", + "Typing :: Typed", ] +dependencies = [] [project.optional-dependencies] -bigtree = ["bigtree>=0.19.3"] -rich = ["rich>=13.7.1"] -all = ["bigtree>=0.19.3", "rich>=13.7.1"] +rar = ["rarfile>=4.2"] +7z = ["py7zr>=1.0.0"] [project.urls] Repository = "https://github.com/Ravencentric/archivefile" @@ -46,11 +42,13 @@ docs = [ "mkdocs-material>=9.5.50", "mkdocstrings[python]>=0.27.0", ] -test = [ - "coverage[toml]>=7.6.10", - "pytest>=8.3.4", +test = ["coverage[toml]>=7.6.10", "pytest>=8.3.4"] +lint = [ + "mypy>=1.16.0", + "ruff>=0.11.12", + "typing-extensions>=4.12.2", + { include-group = "test" }, ] -lint = ["mypy>=1.16.0", "ruff>=0.11.12", { include-group = "test" }] dev = [ { include-group = "docs" }, { include-group = "test" }, @@ -61,36 +59,63 @@ dev = [ line-length = 120 [tool.ruff.lint] -extend-select = ["I"] +extend-select = [ + "I", # https://docs.astral.sh/ruff/rules/#isort-i + "RUF", # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf + "UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up + "N", # https://docs.astral.sh/ruff/rules/#pep8-naming-n + "D4", # https://docs.astral.sh/ruff/rules/#pydocstyle-d + "B", # https://docs.astral.sh/ruff/rules/#flake8-bugbear-b + "FBT", # https://docs.astral.sh/ruff/rules/#flake8-boolean-trap-fbt + "C4", # https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 + "EM", # https://docs.astral.sh/ruff/rules/#flake8-errmsg-em + "ISC", # https://docs.astral.sh/ruff/rules/multi-line-implicit-string-concatenation/ + "PIE", # https://docs.astral.sh/ruff/rules/#flake8-pie-pie + "RET", # https://docs.astral.sh/ruff/rules/#flake8-raise-rse + "PL", # https://docs.astral.sh/ruff/rules/#pylint-pl + "E", # https://docs.astral.sh/ruff/rules/#pycodestyle-e-w + "W", # https://docs.astral.sh/ruff/rules/#pycodestyle-e-w + "FURB", # https://docs.astral.sh/ruff/rules/#refurb-furb + "TC", # https://docs.astral.sh/ruff/rules/#flake8-type-checking-tc + "TID253", # https://docs.astral.sh/ruff/rules/banned-module-level-imports/ +] fixable = ["ALL"] +[tool.ruff.lint.flake8-tidy-imports] +# These modules are optional dependencies, +# so we don't want to import them at the module level +banned-module-level-imports = ["py7zr", "rarfile"] + +[tool.ruff.lint.extend-per-file-ignores] +"tests/*" = ["D", "FBT", "PL", "C416"] + [tool.ruff.lint.isort] required-imports = ["from __future__ import annotations"] +[tool.ruff.format] +docstring-code-format = true + [tool.mypy] strict = true pretty = true +files = ["src/**/*.py", "tests/**/*.py"] +enable_error_code = ["ignore-without-code"] [[tool.mypy.overrides]] module = ["rarfile"] ignore_missing_imports = true [tool.pytest.ini_options] -filterwarnings = ["ignore::DeprecationWarning:tarfile"] - -[tool.coverage.run] -omit = ["src/archivefile/_version.py", "tests/*"] +addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"] +filterwarnings = ["error"] +log_cli_level = "INFO" +testpaths = ["tests"] [tool.coverage.report] exclude_also = [ - "if TYPE_CHECKING:", # Only used for type-hints - "raise NotImplementedError", # Can't test what's not implemented - "def print_table", # Function that pretty much calls another third party function - "def print_tree", # Function that pretty much calls another third party function - "def __repr__", # For debugging + "if TYPE_CHECKING:", # Only used for type-hints ] - [build-system] requires = ["hatchling"] build-backend = "hatchling.build" diff --git a/src/archivefile/__init__.py b/src/archivefile/__init__.py index 06533d7..f24850c 100644 --- a/src/archivefile/__init__.py +++ b/src/archivefile/__init__.py @@ -1,17 +1,20 @@ from __future__ import annotations -from archivefile._core import ArchiveFile -from archivefile._enums import CompressionType -from archivefile._models import ArchiveMember -from archivefile._utils import is_archive -from archivefile._version import Version, _get_version - -__version__ = _get_version() -__version_tuple__ = Version(*[int(i) for i in __version__.split(".")]) +from ._core import ArchiveFile, is_archive +from ._errors import ( + ArchiveFileError, + ArchiveMemberNotAFileError, + ArchiveMemberNotFoundError, + UnsupportedArchiveFormatError, +) +from ._models import ArchiveMember __all__ = [ "ArchiveFile", + "ArchiveFileError", "ArchiveMember", + "ArchiveMemberNotAFileError", + "ArchiveMemberNotFoundError", + "UnsupportedArchiveFormatError", "is_archive", - "CompressionType", ] diff --git a/src/archivefile/_adapters/_base.py b/src/archivefile/_adapters/_base.py deleted file mode 100644 index bea63d8..0000000 --- a/src/archivefile/_adapters/_base.py +++ /dev/null @@ -1,152 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Any, Protocol, overload - -if TYPE_CHECKING: - from types import TracebackType - - from archivefile._enums import CompressionType - from archivefile._models import ArchiveMember - from archivefile._types import ( - CollectionOf, - CompressionLevel, - ErrorHandler, - OpenArchiveMode, - SortBy, - StrPath, - TableStyle, - TreeStyle, - ) - from typing_extensions import Generator, Self - - -class BaseArchiveAdapter(Protocol): - """ - A base protocol that can be inherited from to implement more adapters. - Refer to `src/archivefile/_core.py` for documentation of every method and property. - """ - - # fmt: off - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - # fmt: on - - def __init__( - self, - file: StrPath, - mode: OpenArchiveMode | str = "r", - *, - password: str | None = None, - compression_type: CompressionType | None = None, - compression_level: CompressionLevel | int | None = None, - **kwargs: Any, - ) -> None: ... - - def __enter__(self) -> Self: ... - - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None - ) -> None: ... - - @property - def file(self) -> Path: ... - - @property - def mode(self) -> OpenArchiveMode: ... - - @property - def password(self) -> str | None: ... - - @property - def compression_type(self) -> CompressionType | None: ... - - @property - def compression_level(self) -> CompressionLevel | None: ... - - @property - def adapter(self) -> str: ... - - def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: ... - - def get_members(self) -> Generator[ArchiveMember]: ... - - def get_names(self) -> tuple[str, ...]: ... - - def print_tree( - self, - *, - max_depth: int = 0, - style: TreeStyle = "const", - ) -> None: ... - - def print_table( - self, - *, - title: str | None = None, - style: TableStyle = "markdown", - sort_by: SortBy = "name", - descending: bool = False, - **kwargs: Any, - ) -> None: ... - - def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Path.cwd()) -> Path: ... - - def extractall( - self, *, destination: StrPath = Path.cwd(), members: CollectionOf[StrPath | ArchiveMember] | None = None - ) -> Path: ... - - def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: ... - - def read_text( - self, - member: StrPath | ArchiveMember, - *, - encoding: str = "utf-8", - errors: ErrorHandler = "strict", - ) -> str: ... - - def write( - self, - file: StrPath, - *, - arcname: StrPath | None = None, - ) -> None: ... - - def write_text( - self, - data: str, - *, - arcname: StrPath, - ) -> None: ... - - def write_bytes( - self, - data: bytes, - *, - arcname: StrPath, - ) -> None: ... - - def writeall( - self, - dir: StrPath, - *, - root: StrPath | None = None, - glob: str = "*", - recursive: bool = True, - ) -> None: ... - - def close(self) -> None: ... - - def __repr__(self) -> str: - password = '"********"' if self.password else None - return f'{self.__class__.__name__}("{self.file}", "{self.mode}", password={password})' diff --git a/src/archivefile/_adapters/_rar.py b/src/archivefile/_adapters/_rar.py deleted file mode 100644 index b0d5135..0000000 --- a/src/archivefile/_adapters/_rar.py +++ /dev/null @@ -1,280 +0,0 @@ -from __future__ import annotations - -from datetime import datetime -from pathlib import Path -from typing import TYPE_CHECKING, Any, overload - -from archivefile._adapters._base import BaseArchiveAdapter -from archivefile._models import ArchiveMember -from archivefile._utils import get_member_name, realpath -from rarfile import NoRarEntry, RarFile - -if TYPE_CHECKING: - from types import TracebackType - - from archivefile._enums import CompressionType - from archivefile._types import ( - CollectionOf, - CompressionLevel, - ErrorHandler, - OpenArchiveMode, - SortBy, - StrPath, - TableStyle, - TreeStyle, - ) - from rarfile import RarInfo - from typing_extensions import Generator, Self - - -class RarFileAdapter(BaseArchiveAdapter): - # fmt: off - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - # fmt: on - - def __init__( - self, - file: StrPath, - mode: OpenArchiveMode | str = "r", - *, - password: str | None = None, - compression_type: CompressionType | None = None, - compression_level: CompressionLevel | int | None = None, - **kwargs: Any, - ) -> None: - self._file = realpath(file) - self._mode = mode[0] - self._password = password - - if self._mode == "r": - self._rarfile = RarFile(self._file, mode=self._mode, **kwargs) - else: - raise NotImplementedError('Cannot write to a rar file. Rar files only support mode="r"!') - - def __enter__(self) -> Self: - return self - - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None - ) -> None: - self._rarfile.close() - - @property - def file(self) -> Path: - return self._file - - @property - def mode(self) -> OpenArchiveMode: - return self._mode # type: ignore - - @property - def password(self) -> str | None: - return self._password - - @property - def compression_type(self) -> CompressionType | None: - # RarFile doesn't support writing, so this will always be None - return None - - @property - def compression_level(self) -> CompressionLevel | None: - # RarFile doesn't support writing, so this will always be None - return None - - @property - def adapter(self) -> str: - return self.__class__.__name__ - - def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: - name = get_member_name(member) - - try: - # ZipFile and TarFile raise KeyError but RarFile raises it's own NoRarEntry - # So for consistency's sake, we'll also raise KeyError here - rarinfo: RarInfo = self._rarfile.getinfo(name) - except NoRarEntry: - raise KeyError(f"{name} not found in {self._file}") - - is_dir = True if rarinfo.filename.endswith("/") else False - return ArchiveMember( - name=rarinfo.filename, - size=rarinfo.file_size, - compressed_size=rarinfo.compress_size, - datetime=datetime(*rarinfo.date_time), - checksum=rarinfo.CRC, - is_dir=is_dir, - is_file=not is_dir, - ) - - def get_members(self) -> Generator[ArchiveMember]: - for rarinfo in self._rarfile.infolist(): - yield ArchiveMember( - name=rarinfo.filename, - size=rarinfo.file_size, - compressed_size=rarinfo.compress_size, - datetime=datetime(*rarinfo.date_time), - checksum=rarinfo.CRC, - is_dir=True if rarinfo.filename.endswith("/") else False, - is_file=False if rarinfo.filename.endswith("/") else True, - ) - - def get_names(self) -> tuple[str, ...]: - return tuple(self._rarfile.namelist()) - - def print_tree( - self, - *, - max_depth: int = 0, - style: TreeStyle = "const", - ) -> None: - try: - from bigtree.tree.construct import list_to_tree - except ModuleNotFoundError: - raise ModuleNotFoundError("The 'print_tree()' method requires the 'bigtree' dependency.") - - paths = [f"{self.file.name}/{member}" for member in self.get_names()] - tree = list_to_tree(paths) # type: ignore - tree.show(max_depth=max_depth, style=style) - - def print_table( - self, - *, - title: str | None = None, - style: TableStyle = "markdown", - sort_by: SortBy = "name", - descending: bool = False, - **kwargs: Any, - ) -> None: - try: - from rich import box as RichBox - from rich import print as richprint - from rich.table import Table as RichTable - except ModuleNotFoundError: - raise ModuleNotFoundError("The 'print_table()' method requires the 'rich' dependency.") - - if title is None: - title = self.file.name - - members = self.get_members() - table = RichTable(title=title, box=getattr(RichBox, style.upper()), **kwargs) - table.add_column("Name", no_wrap=True) - table.add_column("Date modified", no_wrap=True) - table.add_column("Type", no_wrap=True) - table.add_column("Size", no_wrap=True) - table.add_column("Compressed Size", no_wrap=True) - for member in sorted(members, key=lambda member: getattr(member, sort_by), reverse=descending): - table.add_row( - member.name, - member.datetime.isoformat(), - "File" if member.is_file else "Folder", - member.size.human_readable(), - member.compressed_size.human_readable(), - ) - richprint(table) - - def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Path.cwd()) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - name = get_member_name(member) - - try: - # ZipFile and TarFile raise KeyError but RarFile raises it's own NoRarEntry - # So for consistency's sake, we'll also raise KeyError here - self._rarfile.extract(member=name, path=destination, pwd=self._password) - except NoRarEntry: - raise KeyError(f"{name} not found in {self._file}") - - return destination / name - - def extractall( - self, *, destination: StrPath = Path.cwd(), members: CollectionOf[StrPath | ArchiveMember] | None = None - ) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - names: set[str] = set() - if members: - all_members = self._rarfile.namelist() - for member in members: - name = get_member_name(member) - if name in all_members: - names.add(name) - else: - raise KeyError(f"{name} not found in {self._file}") - - self._rarfile.extractall(path=destination, members=names, pwd=self._password) - return destination - - def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: - name = get_member_name(member) - - if name.endswith("/"): - return b"" - - try: - # ZipFile and TarFile raise KeyError but RarFile raises it's own NoRarEntry - # So for consistency's sake, we'll also raise KeyError here - return self._rarfile.read(name, pwd=self._password) # type: ignore - except NoRarEntry: - raise KeyError(f"{name} not found in {self._file}") - - def read_text( - self, - member: StrPath | ArchiveMember, - *, - encoding: str = "utf-8", - errors: ErrorHandler = "strict", - ) -> str: - return self.read_bytes(member).decode(encoding, errors) - - def write( - self, - file: StrPath, - *, - arcname: StrPath | None = None, - ) -> None: - raise NotImplementedError('Cannot write to a rar file. Rar files only support mode="r"!') - - def write_text( - self, - data: str, - *, - arcname: StrPath, - ) -> None: - raise NotImplementedError('Cannot write to a rar file. Rar files only support mode="r"!') - - def write_bytes( - self, - data: bytes, - *, - arcname: StrPath, - ) -> None: - raise NotImplementedError('Cannot write to a rar file. Rar files only support mode="r"!') - - def writeall( - self, - dir: StrPath, - *, - root: StrPath | None = None, - glob: str = "*", - recursive: bool = True, - ) -> None: - raise NotImplementedError('Cannot write to a rar file. Rar files only support mode="r"!') - - def close(self) -> None: - self._rarfile.close() - - def __repr__(self) -> str: - password = '"********"' if self.password else None - return f'{self.__class__.__name__}("{self.file}", "{self.mode}", password={password})' diff --git a/src/archivefile/_adapters/_sevenzip.py b/src/archivefile/_adapters/_sevenzip.py deleted file mode 100644 index d1dd37d..0000000 --- a/src/archivefile/_adapters/_sevenzip.py +++ /dev/null @@ -1,350 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Any, overload - -from archivefile._adapters._base import BaseArchiveAdapter -from archivefile._models import ArchiveMember -from archivefile._utils import get_member_name, realpath -from py7zr import SevenZipFile - -if TYPE_CHECKING: - from types import TracebackType - - from archivefile._enums import CompressionType - from archivefile._types import ( - CollectionOf, - CompressionLevel, - ErrorHandler, - OpenArchiveMode, - SortBy, - StrPath, - TableStyle, - TreeStyle, - ) - from typing_extensions import Generator, Self - - -class SevenZipFileAdapter(BaseArchiveAdapter): - # fmt: off - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - # fmt: on - - def __init__( - self, - file: StrPath, - mode: OpenArchiveMode | str = "r", - *, - password: str | None = None, - compression_type: CompressionType | None = None, - compression_level: CompressionLevel | int | None = None, - **kwargs: Any, - ) -> None: - self._file = realpath(file) - self._mode = mode[0] - self._password = password - - # Bit of a hack to support 'x' and 'a' modes properly - if self._mode == "x": - if self._file.exists(): - # SevenZipFile doesn't support mode='x' - # open for exclusive creation, failing if the file already exists - # see: https://github.com/miurahr/py7zr/issues/587 - raise FileExistsError(self._file) - else: - # 'x' and 'w' are equivalent if the file doesn't exist - self._mode = "w" - - if self._mode == "a" and not self._file.exists(): - # SevenZipFile only supports mode='a' on existing files - # Since 'a' is equivalent to 'w' in this case (i.e, when archive file doesn't already exist) - # We can just set it to 'w' - self._mode = "w" - - self._sevenzipfile = SevenZipFile(self._file, mode=self._mode, password=self._password, **kwargs) - - def __enter__(self) -> Self: - return self - - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None - ) -> None: - self._sevenzipfile.close() # type: ignore - - @property - def file(self) -> Path: - return self._file - - @property - def mode(self) -> OpenArchiveMode: - return self._mode # type: ignore - - @property - def password(self) -> str | None: - return self._password - - @property - def compression_type(self) -> CompressionType | None: - # SevenZipFile doesn't support this, so this will always be None. - # Only ZipFile supports this - return None - - @property - def compression_level(self) -> CompressionLevel | None: - # SevenZipFile doesn't support this, so this will always be None. - # Only ZipFile supports this - return None - - @property - def adapter(self) -> str: - return self.__class__.__name__ - - def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: - # Unlike the rest, SevenZip member directories do not end with `/`, so we need to strip it out - # i.e, `spam/eggs/` in a ZipFile is equivalent to `spam/eggs` in SevenZipFile - name = get_member_name(member).removesuffix("/") - - # SevenZipFile doesn't have an equivalent for `get_member` like the rest, so we hand craft it instead - # https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#first_true - sevenzipinfo = next(filter(lambda mem: mem.filename == name, self._sevenzipfile.list()), None) - - # ZipFile and TarFile raise KeyError - # So for consistency (and because I like KeyError over None), we'll also raise KeyError here - if sevenzipinfo is None: - raise KeyError(f"{name} not found in {self._file}") - - return ArchiveMember( - name=sevenzipinfo.filename, - size=sevenzipinfo.uncompressed, - # Sometimes sevenzip can return 0 for compressed size when there's no compression - # in that case we simply return the uncompressed size instead. - compressed_size=sevenzipinfo.compressed or sevenzipinfo.uncompressed, - datetime=sevenzipinfo.creationtime, - checksum=sevenzipinfo.crc32, - is_dir=sevenzipinfo.is_directory, - is_file=not sevenzipinfo.is_directory, - ) - - def get_members(self) -> Generator[ArchiveMember]: - for sevenzipinfo in self._sevenzipfile.list(): - yield ArchiveMember( - name=sevenzipinfo.filename, - size=sevenzipinfo.uncompressed, - # Sometimes sevenzip can return 0 for compressed size when there's no compression - # in that case we simply return the uncompressed size instead. - compressed_size=sevenzipinfo.compressed or sevenzipinfo.uncompressed, - datetime=sevenzipinfo.creationtime, - checksum=sevenzipinfo.crc32, - is_dir=sevenzipinfo.is_directory, - is_file=not sevenzipinfo.is_directory, - ) - - def get_names(self) -> tuple[str, ...]: - return tuple(self._sevenzipfile.getnames()) - - def print_tree( - self, - *, - max_depth: int = 0, - style: TreeStyle = "const", - ) -> None: - try: - from bigtree.tree.construct import list_to_tree - except ModuleNotFoundError: # pragma: no cover - raise ModuleNotFoundError("The 'print_tree()' method requires the 'bigtree' dependency.") - - paths = [f"{self.file.name}/{member}" for member in self.get_names()] - tree = list_to_tree(paths) # type: ignore - tree.show(max_depth=max_depth, style=style) - - def print_table( - self, - *, - title: str | None = None, - style: TableStyle = "markdown", - sort_by: SortBy = "name", - descending: bool = False, - **kwargs: Any, - ) -> None: - try: - from rich import box as RichBox - from rich import print as richprint - from rich.table import Table as RichTable - except ModuleNotFoundError: # pragma: no cover - raise ModuleNotFoundError("The 'print_table()' method requires the 'rich' dependency.") - - if title is None: - title = self.file.name - - members = self.get_members() - table = RichTable(title=title, box=getattr(RichBox, style.upper()), **kwargs) - table.add_column("Name", no_wrap=True) - table.add_column("Date modified", no_wrap=True) - table.add_column("Type", no_wrap=True) - table.add_column("Size", no_wrap=True) - table.add_column("Compressed Size", no_wrap=True) - for member in sorted(members, key=lambda member: getattr(member, sort_by), reverse=descending): - table.add_row( - member.name, - member.datetime.isoformat(), - "File" if member.is_file else "Folder", - member.size.human_readable(), - member.compressed_size.human_readable(), - ) - richprint(table) - - def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Path.cwd()) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - # Unlike the rest, SevenZip member directories do not end with `/`, so we need to strip it out - # i.e, `spam/eggs/` in a ZipFile is equivalent to `spam/eggs` in SevenZipFile - name = get_member_name(member).removesuffix("/") - - if name in self.get_names(): - self._sevenzipfile.extract(path=destination, targets=[name], recursive=True) - else: - # ZipFile and TarFile raise KeyError but SevenZipFile does nothing - # So for consistency's sake, we'll also raise KeyError here - raise KeyError(f"{name} not found in {self._file}") - - self._sevenzipfile.reset() - return destination / name - - def extractall( - self, *, destination: StrPath = Path.cwd(), members: CollectionOf[StrPath | ArchiveMember] | None = None - ) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - names: set[str] = set() - if members: - all_members = self._sevenzipfile.getnames() - for member in members: - # Unlike the rest, SevenZip member directories do not end with `/`, so we need to strip it out - # i.e, `spam/eggs/` in a ZipFile is equivalent to `spam/eggs` in SevenZipFile - name = get_member_name(member).removesuffix("/") - if name in all_members: - names.add(name) - else: - raise KeyError(f"{name} not found in {self._file}") - - if names: - self._sevenzipfile.extract(path=destination, targets=names, recursive=True) - else: - self._sevenzipfile.extractall(path=destination) - - self._sevenzipfile.reset() - return destination - - def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: - # Unlike the rest, SevenZip member directories do not end with `/`, so we need to strip it out - # i.e, `spam/eggs/` in a ZipFile is equivalent to `spam/eggs` in SevenZipFile - name = get_member_name(member).removesuffix("/") - - if name not in self._sevenzipfile.getnames(): - raise KeyError(f"{name} not found in {self._file}") - - data = self._sevenzipfile.read(targets=[name]) - self._sevenzipfile.reset() - - match data: - case dict(): - if fileobj := data.get(name): - return fileobj.read() # type: ignore - else: - return b"" - case _: # pragma: no cover - # We need this because SevenZipFile.read is typed as `dict | None` - # but this case will never actually happen. - # I couldn't get SevenZipFile to return anything but a dict, - # so I'm assuming it's some edge case. - return b"" - - def read_text( - self, - member: StrPath | ArchiveMember, - *, - encoding: str = "utf-8", - errors: ErrorHandler = "strict", - ) -> str: - return self.read_bytes(member).decode(encoding, errors) - - def write( - self, - file: StrPath, - *, - arcname: StrPath | None = None, - ) -> None: - file = realpath(file) - - match arcname: - case None: - arcname = file.name - case Path(): - arcname = arcname.relative_to(arcname.anchor).as_posix() - - if not file.is_file(): - raise ValueError(f"The specified file '{file}' either does not exist or is not a regular file!") - - self._sevenzipfile.write(file, arcname=arcname) - - def write_text( - self, - data: str, - *, - arcname: StrPath, - ) -> None: - self._sevenzipfile.writestr(data=data, arcname=get_member_name(arcname)) - - def write_bytes( - self, - data: bytes, - *, - arcname: StrPath, - ) -> None: - self._sevenzipfile.writestr(data=data, arcname=get_member_name(arcname)) - - def writeall( - self, - dir: StrPath, - *, - root: StrPath | None = None, - glob: str = "*", - recursive: bool = True, - ) -> None: - dir = realpath(dir) - - if not dir.is_dir(): - raise ValueError(f"The specified file '{dir}' either does not exist or is not a regular directory!") - - if root is None: - root = dir.parent - else: - root = realpath(root) - - if not dir.is_relative_to(root): - raise ValueError(f"{dir} must be relative to {root}") - - files = dir.rglob(glob) if recursive else dir.glob(glob) - - for file in files: - arcname = file.relative_to(root) - self.write(file, arcname=arcname) - - def close(self) -> None: - self._sevenzipfile.close() # type: ignore - - def __repr__(self) -> str: - password = '"********"' if self.password else None - return f'{self.__class__.__name__}("{self.file}", "{self.mode}", password={password})' diff --git a/src/archivefile/_adapters/_tar.py b/src/archivefile/_adapters/_tar.py deleted file mode 100644 index ccda728..0000000 --- a/src/archivefile/_adapters/_tar.py +++ /dev/null @@ -1,287 +0,0 @@ -from __future__ import annotations - -import tarfile -from io import BytesIO -from pathlib import Path -from typing import TYPE_CHECKING, Any, overload - -from archivefile._adapters._base import BaseArchiveAdapter -from archivefile._models import ArchiveMember -from archivefile._utils import get_member_name, realpath - -if TYPE_CHECKING: - from types import TracebackType - - from archivefile._enums import CompressionType - from archivefile._types import ( - CollectionOf, - CompressionLevel, - ErrorHandler, - OpenArchiveMode, - SortBy, - StrPath, - TableStyle, - TreeStyle, - ) - from typing_extensions import Generator, Self - - -class TarFileAdapter(BaseArchiveAdapter): - # fmt: off - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - # fmt: on - - def __init__( - self, - file: StrPath, - mode: OpenArchiveMode | str = "r", - *, - password: str | None = None, - compression_type: CompressionType | None = None, - compression_level: CompressionLevel | int | None = None, - **kwargs: Any, - ) -> None: - self._file = realpath(file) - self._mode = mode - self._password = password - self._tarfile = tarfile.open(self._file, mode=self._mode, **kwargs) - # https://docs.python.org/3/library/tarfile.html#supporting-older-python-versions - self._tarfile.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member)) - - def __enter__(self) -> Self: - return self - - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None - ) -> None: - self._tarfile.close() - - @property - def file(self) -> Path: - return self._file - - @property - def mode(self) -> OpenArchiveMode: - return self._mode # type: ignore - - @property - def password(self) -> str | None: - return self._password - - @property - def compression_type(self) -> CompressionType | None: - # TarFile doesn't support this, so this will always be None. - # Only ZipFile supports this - return None - - @property - def compression_level(self) -> CompressionLevel | None: - # TarFile doesn't support this, so this will always be None. - # Only ZipFile supports this - return None - - @property - def adapter(self) -> str: - return self.__class__.__name__ - - def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: - name = get_member_name(member) - - tarinfo = self._tarfile.getmember(name) - - return ArchiveMember( - name=tarinfo.name, - size=tarinfo.size, # type: ignore - compressed_size=tarinfo.size, # type: ignore - datetime=tarinfo.mtime, # type: ignore - checksum=tarinfo.chksum, - is_dir=tarinfo.isdir(), - is_file=tarinfo.isfile(), - ) - - def get_members(self) -> Generator[ArchiveMember]: - for tarinfo in self._tarfile.getmembers(): - yield ArchiveMember( - name=tarinfo.name, - size=tarinfo.size, # type: ignore - compressed_size=tarinfo.size, # type: ignore - datetime=tarinfo.mtime, # type: ignore - checksum=tarinfo.chksum, - is_dir=tarinfo.isdir(), - is_file=tarinfo.isfile(), - ) - - def get_names(self) -> tuple[str, ...]: - return tuple(self._tarfile.getnames()) - - def print_tree( - self, - *, - max_depth: int = 0, - style: TreeStyle = "const", - ) -> None: - try: - from bigtree.tree.construct import list_to_tree - except ModuleNotFoundError: # pragma: no cover - raise ModuleNotFoundError("The 'print_tree()' method requires the 'bigtree' dependency.") - - paths = [f"{self.file.name}/{member}" for member in self.get_names()] - tree = list_to_tree(paths) # type: ignore - tree.show(max_depth=max_depth, style=style) - - def print_table( - self, - *, - title: str | None = None, - style: TableStyle = "markdown", - sort_by: SortBy = "name", - descending: bool = False, - **kwargs: Any, - ) -> None: - try: - from rich import box as RichBox - from rich import print as richprint - from rich.table import Table as RichTable - except ModuleNotFoundError: # pragma: no cover - raise ModuleNotFoundError("The 'print_table()' method requires the 'rich' dependency.") - - if title is None: - title = self.file.name - - members = self.get_members() - table = RichTable(title=title, box=getattr(RichBox, style.upper()), **kwargs) - table.add_column("Name", no_wrap=True) - table.add_column("Date modified", no_wrap=True) - table.add_column("Type", no_wrap=True) - table.add_column("Size", no_wrap=True) - table.add_column("Compressed Size", no_wrap=True) - for member in sorted(members, key=lambda member: getattr(member, sort_by), reverse=descending): - table.add_row( - member.name, - member.datetime.isoformat(), - "File" if member.is_file else "Folder", - member.size.human_readable(), - member.compressed_size.human_readable(), - ) - richprint(table) - - def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Path.cwd()) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - name = get_member_name(member) - self._tarfile.extract(member=name, path=destination) - return destination / name - - def extractall( - self, *, destination: StrPath = Path.cwd(), members: CollectionOf[StrPath | ArchiveMember] | None = None - ) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - names: list[tarfile.TarInfo] = [] - if members: - for member in members: - names.append(self._tarfile.getmember(get_member_name(member))) - - self._tarfile.extractall(path=destination, members=names) - - else: - self._tarfile.extractall(path=destination) - - return destination - - def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: - name = get_member_name(member) - fileobj = self._tarfile.extractfile(name) - if fileobj is None: # pragma: no cover - return b"" - return fileobj.read() - - def read_text( - self, - member: StrPath | ArchiveMember, - *, - encoding: str = "utf-8", - errors: ErrorHandler = "strict", - ) -> str: - return self.read_bytes(member).decode(encoding, errors) - - def write( - self, - file: StrPath, - *, - arcname: StrPath | None = None, - ) -> None: - file = realpath(file) - - if arcname is None: - arcname = file.name - - if not file.is_file(): - raise ValueError(f"The specified file '{file}' either does not exist or is not a regular file!") - - self._tarfile.add(file, arcname=arcname) - - def write_text( - self, - data: str, - *, - arcname: StrPath, - ) -> None: - self.write_bytes(data=data.encode(), arcname=arcname) - - def write_bytes( - self, - data: bytes, - *, - arcname: StrPath, - ) -> None: - tarinfo = tarfile.TarInfo(get_member_name(arcname)) - tarinfo.size = len(data) - self._tarfile.addfile(tarinfo, BytesIO(data)) - - def writeall( - self, - dir: StrPath, - *, - root: StrPath | None = None, - glob: str = "*", - recursive: bool = True, - ) -> None: - dir = realpath(dir) - - if not dir.is_dir(): - raise ValueError(f"The specified file '{dir}' either does not exist or is not a regular directory!") - - if root is None: - root = dir.parent - else: - root = realpath(root) - - if not dir.is_relative_to(root): - raise ValueError(f"{dir} must be relative to {root}") - - files = dir.rglob(glob) if recursive else dir.glob(glob) - - for file in files: - if file.is_file(): - arcname = file.relative_to(root) - self.write(file, arcname=arcname) - - def close(self) -> None: - self._tarfile.close() - - def __repr__(self) -> str: - password = '"********"' if self.password else None - return f'{self.__class__.__name__}("{self.file}", "{self.mode}", password={password})' diff --git a/src/archivefile/_adapters/_zip.py b/src/archivefile/_adapters/_zip.py deleted file mode 100644 index 77881c4..0000000 --- a/src/archivefile/_adapters/_zip.py +++ /dev/null @@ -1,290 +0,0 @@ -from __future__ import annotations - -from datetime import datetime -from pathlib import Path -from typing import TYPE_CHECKING, Any, overload -from zipfile import ZipFile - -from archivefile._adapters._base import BaseArchiveAdapter -from archivefile._enums import CompressionType -from archivefile._models import ArchiveMember -from archivefile._utils import clamp_compression_level, get_member_name, realpath - -if TYPE_CHECKING: - from types import TracebackType - - from archivefile._types import ( - CollectionOf, - CompressionLevel, - ErrorHandler, - OpenArchiveMode, - SortBy, - StrPath, - TableStyle, - TreeStyle, - ) - from typing_extensions import Generator, Self - - -class ZipFileAdapter(BaseArchiveAdapter): - # fmt: off - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... - - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - # fmt: on - - def __init__( - self, - file: StrPath, - mode: OpenArchiveMode | str = "r", - *, - password: str | None = None, - compression_type: CompressionType | None = None, - compression_level: CompressionLevel | int | None = None, - **kwargs: Any, - ) -> None: - self._file = realpath(file) - self._mode = mode[0] - self._password = password - self._pwd = password.encode() if password else None - - self._compression_type = CompressionType.get(compression_type) - self._compression_level = clamp_compression_level(compression_level) if compression_level is not None else None - - if self._compression_type is CompressionType.BZIP2: - # BZIP2 only supports 1-9 - if self._compression_level == 0: - self._compression_level = 1 - - self._zipfile = ZipFile( - self._file, - mode=self._mode, - compression=self._compression_type, - compresslevel=self._compression_level, - **kwargs, - ) # type: ignore - - def __enter__(self) -> Self: - return self - - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None - ) -> None: - self._zipfile.close() - - @property - def file(self) -> Path: - return self._file - - @property - def mode(self) -> OpenArchiveMode: - return self._mode # type: ignore - - @property - def password(self) -> str | None: - return self._password - - @property - def compression_type(self) -> CompressionType | None: - return self._compression_type - - @property - def compression_level(self) -> CompressionLevel | None: - return self._compression_level # type: ignore - - @property - def adapter(self) -> str: - return self.__class__.__name__ - - def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: - name = get_member_name(member) - zipinfo = self._zipfile.getinfo(name) - - return ArchiveMember( - name=zipinfo.filename, - size=zipinfo.file_size, - compressed_size=zipinfo.compress_size, - datetime=datetime(*zipinfo.date_time), - checksum=zipinfo.CRC, - is_dir=zipinfo.is_dir(), - is_file=not zipinfo.is_dir(), - ) - - def get_members(self) -> Generator[ArchiveMember]: - for zipinfo in self._zipfile.filelist: - yield ArchiveMember( - name=zipinfo.filename, - size=zipinfo.file_size, - compressed_size=zipinfo.compress_size, - datetime=datetime(*zipinfo.date_time), - checksum=zipinfo.CRC, - is_dir=zipinfo.is_dir(), - is_file=not zipinfo.is_dir(), - ) - - def get_names(self) -> tuple[str, ...]: - return tuple(self._zipfile.namelist()) - - def print_tree( - self, - *, - max_depth: int = 0, - style: TreeStyle = "const", - ) -> None: - try: - from bigtree.tree.construct import list_to_tree - except ModuleNotFoundError: # pragma: no cover - raise ModuleNotFoundError("The 'print_tree()' method requires the 'bigtree' dependency.") - - paths = [f"{self.file.name}/{member}" for member in self.get_names()] - tree = list_to_tree(paths) # type: ignore - tree.show(max_depth=max_depth, style=style) - - def print_table( - self, - *, - title: str | None = None, - style: TableStyle = "markdown", - sort_by: SortBy = "name", - descending: bool = False, - **kwargs: Any, - ) -> None: - try: - from rich import box as RichBox - from rich import print as richprint - from rich.table import Table as RichTable - except ModuleNotFoundError: # pragma: no cover - raise ModuleNotFoundError("The 'print_table()' method requires the 'rich' dependency.") - - if title is None: - title = self.file.name - - members = self.get_members() - table = RichTable(title=title, box=getattr(RichBox, style.upper()), **kwargs) - table.add_column("Name", no_wrap=True) - table.add_column("Date modified", no_wrap=True) - table.add_column("Type", no_wrap=True) - table.add_column("Size", no_wrap=True) - table.add_column("Compressed Size", no_wrap=True) - for member in sorted(members, key=lambda member: getattr(member, sort_by), reverse=descending): - table.add_row( - member.name, - member.datetime.isoformat(), - "File" if member.is_file else "Folder", - member.size.human_readable(), - member.compressed_size.human_readable(), - ) - richprint(table) - - def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Path.cwd()) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - name = get_member_name(member) - self._zipfile.extract(member=name, path=destination, pwd=self._pwd) - return destination / name - - def extractall( - self, *, destination: StrPath = Path.cwd(), members: CollectionOf[StrPath | ArchiveMember] | None = None - ) -> Path: - destination = realpath(destination) - destination.mkdir(parents=True, exist_ok=True) - - names: list[str] = [] - if members: - for member in members: - names.append(get_member_name(member)) - - if names: - self._zipfile.extractall(path=destination, members=names, pwd=self._pwd) - else: - self._zipfile.extractall(path=destination, pwd=self._pwd) - - return destination - - def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: - name = get_member_name(member) - return self._zipfile.read(name, pwd=self._pwd) # type: ignore - - def read_text( - self, - member: StrPath | ArchiveMember, - *, - encoding: str = "utf-8", - errors: ErrorHandler = "strict", - ) -> str: - return self.read_bytes(member).decode(encoding, errors) - - def write( - self, - file: StrPath, - *, - arcname: StrPath | None = None, - ) -> None: - file = realpath(file) - - if arcname is None: - arcname = file.name - - if not file.is_file(): - raise ValueError(f"The specified file '{file}' either does not exist or is not a regular file!") - - self._zipfile.write(file, arcname=arcname) - - def write_text( - self, - data: str, - *, - arcname: StrPath, - ) -> None: - self._zipfile.writestr(get_member_name(arcname), data) - - def write_bytes( - self, - data: bytes, - *, - arcname: StrPath, - ) -> None: - self._zipfile.writestr(get_member_name(arcname), data) - - def writeall( - self, - dir: StrPath, - *, - root: StrPath | None = None, - glob: str = "*", - recursive: bool = True, - ) -> None: - dir = realpath(dir) - - if not dir.is_dir(): - raise ValueError(f"The specified file '{dir}' either does not exist or is not a regular directory!") - - if root is None: - root = dir.parent - else: - root = realpath(root) - - if not dir.is_relative_to(root): - raise ValueError(f"{dir} must be relative to {root}") - - files = dir.rglob(glob) if recursive else dir.glob(glob) - - for file in files: - arcname = file.relative_to(root) - self.write(file, arcname=arcname) - - def close(self) -> None: - self._zipfile.close() - - def __repr__(self) -> str: - password = '"********"' if self.password else None - return f'{self.__class__.__name__}("{self.file}", "{self.mode}", password={password})' diff --git a/src/archivefile/_core.py b/src/archivefile/_core.py index 950f5d0..8a7215c 100644 --- a/src/archivefile/_core.py +++ b/src/archivefile/_core.py @@ -1,63 +1,55 @@ from __future__ import annotations -import re -from pathlib import Path from tarfile import is_tarfile -from types import TracebackType -from typing import Any, overload +from typing import TYPE_CHECKING from zipfile import is_zipfile -from py7zr import is_7zfile -from pydantic import validate_call -from rarfile import is_rarfile, is_rarfile_sfx -from typing_extensions import Generator, Self - -from archivefile._adapters._base import BaseArchiveAdapter -from archivefile._adapters._rar import RarFileAdapter -from archivefile._adapters._sevenzip import SevenZipFileAdapter -from archivefile._adapters._tar import TarFileAdapter -from archivefile._adapters._zip import ZipFileAdapter -from archivefile._enums import CompressionType -from archivefile._models import ArchiveMember -from archivefile._types import ( - CollectionOf, - CompressionLevel, - ErrorHandler, - OpenArchiveMode, - SortBy, - StrPath, - TableStyle, - TreeStyle, -) from archivefile._utils import realpath +from ._errors import UnsupportedArchiveFormatError +from ._impl._rar import RarArchiveFile, is_rarfile +from ._impl._sevenzip import SevenZipArchiveFile, is_7zfile +from ._impl._tar import TarArchiveFile +from ._impl._zip import ZipArchiveFile -class ArchiveFile(BaseArchiveAdapter): - # fmt: off - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + from pathlib import Path - @overload - def __init__(self, file: StrPath, mode: OpenArchiveMode = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... + from typing_extensions import Self - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: CompressionLevel | None = None, **kwargs: Any) -> None: ... + from ._impl._abc import AbstractArchiveFile + from ._models import ArchiveMember + from ._types import ErrorHandler, MemberLike, StrPath - @overload - def __init__(self, file: StrPath, mode: str = "r", *, password: str | None = None, compression_type: CompressionType | None = None, compression_level: int | None = None, **kwargs: Any) -> None: ... - # fmt: on - @validate_call - def __init__( - self, - file: StrPath, - mode: OpenArchiveMode | str = "r", - *, - password: str | None = None, - compression_type: CompressionType | None = None, - compression_level: CompressionLevel | int | None = None, - **kwargs: Any, - ) -> None: +def is_archive(file: StrPath) -> bool: + """ + Check whether the given archive file is a supported archive or not. + + Parameters + ---------- + file : StrPath + Path to the archive file. + + Returns + ------- + bool + True if the archive is supported, False otherwise. + + """ + file = realpath(file) + + if not file.is_file(): + return False + + return is_tarfile(file) or is_zipfile(file) or is_7zfile(file) or is_rarfile(file) + + +class ArchiveFile: + __slots__ = ("_impl",) + + def __init__(self, file: StrPath, /, *, password: str | None = None) -> None: """ Open an archive file. @@ -65,136 +57,66 @@ def __init__( ---------- file : StrPath Path to the archive file. - mode : OpenArchiveMode, optional - Mode for opening the archive file. password : str, optional Password for encrypted archive files. - compression_type : CompressionType, optional - The compression method for writing zip files. - compression_level : CompressionLevel, optional - The compression level for writing zip files. - kwargs : Any - Keyword arugments to pass to the underlying library. - - Returns - ------- - None Raises ------ - NotImplementedError + UnsupportedArchiveFormatError Raised if the archive format is unsupported Notes ----- - The `compression_type` and `compression_level` parameters are only applicable when creating - zip files and do not affect reading zip files or other archive formats. - - References - ---------- ArchiveFile currently supports the following: - [`ZipFile`][zipfile.ZipFile] - [`TarFile`][tarfile.TarFile.open] - - [`RarFile`][rarfile.RarFile] - - [`SevenZipFile`][py7zr.SevenZipFile] - """ - self._file = realpath(file) - self._mode = mode - self._password = password - self._kwargs = kwargs - self._compression_type = compression_type - self._compression_level = compression_level - self._initialize_adapter() - - def _initialize_adapter(self) -> None: - if not self._file.exists(): - if not self._mode.startswith("r"): - filename = self._file.name.lower() - - if re.search(r"\.(zip|cbz)$", filename): - adapter = ZipFileAdapter - elif re.search(r"\.((tar(\.(bz2|gz|xz))?)|(cbt))$", filename): - adapter = TarFileAdapter # type: ignore - elif re.search(r"\.(7z|cb7)$", filename): - adapter = SevenZipFileAdapter # type: ignore - elif re.search(r"\.(rar|cbr)$", filename): - adapter = RarFileAdapter # type: ignore - else: - raise NotImplementedError(f"Unsupported archive format: {self._file}") - else: - raise FileNotFoundError(self._file) - - elif is_zipfile(self._file): - adapter = ZipFileAdapter - - elif is_tarfile(self._file): - adapter = TarFileAdapter # type: ignore - - elif is_7zfile(self._file): - adapter = SevenZipFileAdapter # type: ignore - - elif is_rarfile(self._file) or is_rarfile_sfx(self._file): - adapter = RarFileAdapter # type: ignore + - [`RarFile`][rarfile.RarFile] - requires `archivefile[rar]` + - [`SevenZipFile`][py7zr.SevenZipFile] - requires `archivefile[7z]` + """ + file = realpath(file) + if not file.is_file(): + raise FileNotFoundError(file) + + implmentation: type[AbstractArchiveFile] + + if is_zipfile(file): + implmentation = ZipArchiveFile + elif is_tarfile(file): + implmentation = TarArchiveFile + elif is_7zfile(file): + implmentation = SevenZipArchiveFile + elif is_rarfile(file): + implmentation = RarArchiveFile else: - raise NotImplementedError(f"Unsupported archive format: {self._file}") + raise UnsupportedArchiveFormatError(file=file) - self._adapter = adapter( - self._file, - self._mode, - password=self._password, - compression_type=self._compression_type, - compression_level=self._compression_level, - **self._kwargs, - ) + self._impl = implmentation(file, password=password) def __enter__(self) -> Self: return self - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None - ) -> None: - self._adapter.close() + def __exit__(self, *args: object) -> None: + self.close() @property def file(self) -> Path: """Path to the archive file.""" - return self._adapter.file - - @property - def mode(self) -> OpenArchiveMode: - """Mode in which the archive file was opened.""" - return self._adapter.mode + return self._impl.file @property def password(self) -> str | None: """Archive password.""" - return self._adapter.password + return self._impl.password - @property - def compression_type(self) -> CompressionType | None: - """Compression type used for writing.""" - return self._adapter.compression_type - - @property - def compression_level(self) -> CompressionLevel | None: - """Compression level used for writing.""" - return self._adapter.compression_level - - @property - def adapter(self) -> str: - """Name of the underlying adapter class, useful for debugging.""" - return self._adapter.adapter - - @validate_call - def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: + def get_member(self, member: MemberLike, /) -> ArchiveMember: """ Retrieve an ArchiveMember object by it's name. Parameters ---------- - member : StrPath | ArchiveMember + member : MemberLike Name of the member. Returns @@ -214,18 +136,25 @@ def get_member(self, member: StrPath | ArchiveMember) -> ArchiveMember: with ArchiveFile("source.tar") as archive: archive.get_member("README.md") - # ArchiveMember(name='README.md', size=3799, compressed_size=3799, datetime=datetime.datetime(2024, 4, 10, 20, 10, 57, tzinfo=datetime.timezone.utc), checksum=5251, is_dir=False, is_file=True) + # ArchiveMember( + # name="README.md", + # size=3799, + # compressed_size=3799, + # datetime=datetime.datetime(2024, 4, 10, 20, 10, 57), + # is_dir=False, + # is_file=True, + # ) ``` + """ - return self._adapter.get_member(member) + return self._impl.get_member(member) - @validate_call - def get_members(self) -> Generator[ArchiveMember]: + def get_members(self) -> Iterator[ArchiveMember]: """ Retrieve all members of the archive as a generator of `ArchiveMember` objects. Yields - ------- + ------ ArchiveMember Each member of the archive as an `ArchiveMember` object. @@ -240,10 +169,10 @@ def get_members(self) -> Generator[ArchiveMember]: # project/pyproject.toml # project/src ``` + """ - yield from self._adapter.get_members() + yield from self._impl.get_members() - @validate_call def get_names(self) -> tuple[str, ...]: """ Retrieve all members of the archive as a tuple of strings. @@ -265,128 +194,17 @@ def get_names(self) -> tuple[str, ...]: # "project/src", # ) ``` - """ - return self._adapter.get_names() - def print_tree( - self, - *, - max_depth: int = 0, - style: TreeStyle = "const", - ) -> None: """ - Print the contents of the archive as a tree. - - Parameters - ---------- - max_depth : int, optional - Maximum depth to print. - style : TreeStyle, optional - The style of the tree. - - Returns - ------- - None + return self._impl.get_names() - Notes - ----- - The [`bigtree`](https://pypi.org/p/bigtree/) dependency is required to use this method. - - You can install it via either of these commands: - - - `pip install archivefile[bigtree]` - - `pip install archivefile[all]` - - Examples - -------- - ```py - from archivefile import ArchiveFile - - with ArchiveFile("source.tar.gz") as archive: - archive.print_tree() - # source.tar.gz - # └── hello-world - # ├── pyproject.toml - # ├── README.md - # ├── src - # │ └── hello_world - # │ └── __init__.py - # └── tests - # └── __init__.py - ``` - """ - self._adapter.print_tree(max_depth=max_depth, style=style) - - @validate_call - def print_table( - self, - *, - title: str | None = None, - style: TableStyle = "markdown", - sort_by: SortBy = "name", - descending: bool = False, - **kwargs: Any, - ) -> None: - """ - Print the contents of the archive as a table. - - Parameters - ---------- - title : str, optional - Title of the table. Defaults to archive file name. - style : TableStyle, optional - The style of the table. - sort_by : SortBy, optional - Key used to sort the table. - descending : bool, optional - If True, sorting will be in descending order. - kwargs : Any - Additional keyword arguments to be passed to the [`Table`][rich.table.Table] constructor. - - Returns - ------- - None - - Notes - ----- - The [`rich`](https://pypi.org/p/rich/) dependency is required to use this method. - - You can install it via either of these commands: - - - `pip install archivefile[rich]` - - `pip install archivefile[all]` - - Examples - -------- - ```py - from archivefile import ArchiveFile - - with ArchiveFile("source.zip") as archive: - archive.print_table() - # source.zip - # - # | Name | Date modified | Type | Size | Compressed Size | - # |-----------------------------------------|---------------------------|--------|------|-----------------| - # | hello-world/ | 2024-05-02T09:41:24+00:00 | Folder | 0B | 0B | - # | hello-world/README.md | 2024-05-02T09:41:24+00:00 | File | 0B | 0B | - # | hello-world/pyproject.toml | 2024-05-02T09:41:24+00:00 | File | 363B | 241B | - # | hello-world/src/ | 2024-05-02T09:41:24+00:00 | Folder | 0B | 0B | - # | hello-world/src/hello_world/ | 2024-05-02T09:41:24+00:00 | Folder | 0B | 0B | - # | hello-world/src/hello_world/__init__.py | 2024-05-02T09:41:24+00:00 | File | 0B | 0B | - # | hello-world/tests/ | 2024-05-02T09:41:24+00:00 | Folder | 0B | 0B | - # | hello-world/tests/__init__.py | 2024-05-02T09:41:24+00:00 | File | 0B | 0B | - ``` - """ - self._adapter.print_table(title=title, style=style, sort_by=sort_by, descending=descending, **kwargs) - - @validate_call - def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Path.cwd()) -> Path: + def extract(self, member: MemberLike, /, *, destination: StrPath | None = None) -> Path: """ Extract a member of the archive. Parameters ---------- - member : StrPath | ArchiveMember + member : MemberLike Name of the member or an ArchiveMember object. destination : StrPath The path to the directory where the member will be extracted. @@ -417,12 +235,15 @@ def extract(self, member: StrPath | ArchiveMember, *, destination: StrPath = Pat # readme = "README.md" # packages = [{include = "hello_world", from = "src"}] ``` + """ - return self._adapter.extract(member, destination=destination) + return self._impl.extract(member, destination=destination) - @validate_call def extractall( - self, *, destination: StrPath = Path.cwd(), members: CollectionOf[StrPath | ArchiveMember] | None = None + self, + *, + destination: StrPath | None = None, + members: Iterable[MemberLike] | None = None, ) -> Path: """ Extract all the members of the archive to the destination directory. @@ -432,7 +253,7 @@ def extractall( destination : StrPath The path to the directory where the members will be extracted. If not specified, the current working directory is used as the default destination. - members : CollectionOf[StrPath | ArchiveMember], optional + members : CollectionOf[MemberLike], optional Collection of member names or ArchiveMember objects to extract. Default is `None` which will extract all members. @@ -465,17 +286,17 @@ def extractall( # /source/hello-world/src/hello_world/__init__.py # /source/hello-world/tests/__init__.py ``` + """ - return self._adapter.extractall(destination=destination, members=members) + return self._impl.extractall(destination=destination, members=members) - @validate_call - def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: + def read_bytes(self, member: MemberLike, /) -> bytes: """ Read the member in bytes mode. Parameters ---------- - member : StrPath | ArchiveMember + member : MemberLike Name of the member or an ArchiveMember object. Returns @@ -496,15 +317,16 @@ def read_bytes(self, member: StrPath | ArchiveMember) -> bytes: with ArchiveFile("source.zip") as archive: data = archive.read_bytes("hello-world/pyproject.toml") print(data) - # b'[tool.poetry]\\r\\nname = "hello-world"\\r\\nversion = "0.1.0"\\r\\ndescription = ""\\r\\nreadme = "README.md"\\r\\npackages = [{include = "hello_world", from = "src"}]\\r\\n' + # b'[tool.poetry]\\r\\nname = "hello-world"\\r\\nversion = "0.1.0" [...]' ``` + """ - return self._adapter.read_bytes(member) + return self._impl.read_bytes(member) - @validate_call def read_text( self, - member: StrPath | ArchiveMember, + member: MemberLike, + /, *, encoding: str = "utf-8", errors: ErrorHandler = "strict", @@ -514,7 +336,7 @@ def read_text( Parameters ---------- - member : StrPath | ArchiveMember + member : MemberLike Name of the member or an ArchiveMember object. encoding : str, optional Encoding used to read the file. Default is `utf-8`. @@ -551,182 +373,9 @@ def read_text( # readme = "README.md" # packages = [{include = "hello_world", from = "src"}] ``` - """ - return self._adapter.read_text(member, encoding=encoding, errors=errors) - - @validate_call - def write( - self, - file: StrPath, - *, - arcname: StrPath | None = None, - ) -> None: - """ - Write a single file to the archive. - - Parameters - ---------- - file : StrPath - Path of the file. - arcname : StrPath, optional - Name which the file will have in the archive. - Default is the basename of the file. - - Returns - ------- - None - - Examples - -------- - ```py - from archivefile import ArchiveFile - - with ArchiveFile("example.zip", "w") as archive: - archive.write("/root/some/path/to/foo.txt") - archive.write("bar.txt", arcname="baz.txt") - archive.write("recipe/spam.txt", arcname="ingredients/spam.txt") - archive.write("recipe/eggs.txt", arcname="ingredients/eggs.txt") - archive.print_tree() - # example.zip - # ├── foo.txt - # ├── baz.txt - # └── ingredients - # ├── spam.txt - # └── eggs.txt - ``` - """ - self._adapter.write(file, arcname=arcname) - @validate_call - def write_text( - self, - data: str, - *, - arcname: StrPath, - ) -> None: """ - Write the string `data` to a file within the archive named `arcname`. - - Parameters - ---------- - data : str - The text data to write to the archive. - arcname : StrPath, optional - The name which the file will have in the archive. - - Returns - ------- - None - - Examples - -------- - ```py - from archivefile import ArchiveFile - - with ArchiveFile("newarchive.zip", "w") as archive: - archive.write_text("spam and eggs", arcname="recipe.txt") - members = archive.get_names() - print(members) - # ('recipe.txt',) - text = archive.read_text("recipe.txt") - print(text) - # 'spam and eggs' - ``` - """ - self._adapter.write_text(data, arcname=arcname) - - @validate_call - def write_bytes( - self, - data: bytes, - *, - arcname: StrPath, - ) -> None: - """ - Write the bytes `data` to a file within the archive named `arcname`. - - Parameters - ---------- - data: str - The bytes data to write to the archive. - arcname : StrPath, optional - The name which the file will have in the archive. - - Returns - ------- - None - - Examples - -------- - ```py - from archivefile import ArchiveFile - - with ArchiveFile("skynet.7z", "w") as archive: - archive.write_bytes(b"010010100101", arcname="terminator.py") - members = archive.get_names() - print(members) - # ('terminator.py',) - data = archive.read_bytes("terminator.py") - print(data) - # b"010010100101" - ``` - """ - self._adapter.write_bytes(data, arcname=arcname) - - @validate_call - def writeall( - self, - dir: StrPath, - *, - root: StrPath | None = None, - glob: str = "*", - recursive: bool = True, - ) -> None: - """ - Write a directory to the archive. - - Parameters - ---------- - dir : StrPath - Path of the directory. - root : StrPath - Directory that will be the root directory of the archive, all paths in the archive will be relative to it. - This must be relative to given directory path. Default is the parent of the given directory. - glob : str, optional - Only write files that match this glob pattern to the archive. - recursive : bool, optional - Recursively write all the files in the given directory. Default is True. - - Returns - ------- - None - - Examples - -------- - ```py - from archivefile import ArchiveFile - - with ArchiveFile("source.tar.gz", "w:gz") as archive: - archive.writeall(dir="hello-world/") - archive.print_tree() - # source.tar.gz - # └── hello-world - # ├── pyproject.toml - # ├── README.md - # ├── src - # │ └── hello_world - # │ └── __init__.py - # └── tests - # └── __init__.py - ``` - """ - - self._adapter.writeall( - dir, - root=root, - glob=glob, - recursive=recursive, - ) + return self._impl.read_text(member, encoding=encoding, errors=errors) def close(self) -> None: """ @@ -745,9 +394,13 @@ def close(self) -> None: archive.write_bytes(b"01010101001", arcname="terminator.py") archive.close() ``` - """ - self._adapter.close() - def __repr__(self) -> str: - password = '"********"' if self.password else None - return f'{self.__class__.__name__}("{self.file}", "{self.mode}", password={password})' + """ + self._impl.close() + + def __repr__(self) -> str: # pragma: no cover + file = self.file.as_posix() + cls = self.__class__.__name__ + if self.password: + return f"{cls}({file!r}, password='********')" + return f"{cls}({file!r})" diff --git a/src/archivefile/_enums.py b/src/archivefile/_enums.py deleted file mode 100644 index 59b5776..0000000 --- a/src/archivefile/_enums.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from enum import IntEnum -from typing import Literal, overload - - -class CompressionType(IntEnum): - """Compression algorithms for ZipFile""" - - STORED = 0 - """The numeric constant for an uncompressed archive member.""" - DEFLATED = 8 - """ - The numeric constant for the usual ZIP compression method. - This requires the [zlib](https://docs.python.org/3/library/zlib.html#module-zlib) module. - """ - BZIP2 = 12 - """ - The numeric constant for the BZIP2 compression method. - This requires the [bz2](https://docs.python.org/3/library/bz2.html#module-bz2) module. - """ - LZMA = 14 - """ - The numeric constant for the LZMA compression method. - This requires the [lzma](https://docs.python.org/3/library/lzma.html#module-lzma) module. - """ - - @overload - @classmethod - def get( - cls, - key: str | int | None = None, - default: Literal["stored", "deflated", "bzip2", "lzma"] = "stored", - ) -> CompressionType: ... - - @overload - @classmethod - def get(cls, key: str | int | None = None, default: str | int = "stored") -> CompressionType: ... - - @classmethod - def get( - cls, - key: str | int | None = None, - default: Literal["stored", "deflated", "bzip2", "lzma"] | str | int = "stored", - ) -> CompressionType: - """ - Get the `CompressionType` by its name or number. - Return the default if the key is missing or invalid. - - Parameters - ---------- - key : str | int, optional - The key to retrieve. - default : Literal["stored", "deflated", "bzip2", "lzma"] | str | int, optional - The default value to return if the key is missing or invalid. - - Returns - ------- - CompressionType - The `CompressionType` corresponding to the key. - """ - try: - match key: - case str(): - return cls[key.upper()] - - case int(): - return cls(key) - - case _: - return cls[default.upper()] if isinstance(default, str) else cls(default) - except (KeyError, ValueError): - return cls[default.upper()] if isinstance(default, str) else cls(default) diff --git a/src/archivefile/_errors.py b/src/archivefile/_errors.py new file mode 100644 index 0000000..6d28cc4 --- /dev/null +++ b/src/archivefile/_errors.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._types import StrPath + + +class ArchiveFileError(Exception): + """ + Base exception for all ArchiveFile errors. + """ + + __module__ = "archivefile" + + def __init_subclass__(cls) -> None: + # Ensure subclasses also appear as part of the public 'archivefile' module + # in tracebacks, instead of the internal implementation module. + cls.__module__ = "archivefile" + + def __init__(self, message: str, /, *, file: StrPath) -> None: + self._file = Path(file) + super().__init__(message) + + @property + def file(self) -> Path: + """The archive file related to the error.""" + return self._file + + +class UnsupportedArchiveFormatError(ArchiveFileError): + """ + Raised when the archive file format is unsupported or unrecognized. + """ + + def __init__(self, *, file: StrPath) -> None: + filename = Path(file).as_posix() + message = ( + f"Unsupported or unrecognized archive format for file: {filename!r}.\n" + "If this is a 7z or rar archive, support is available via the optional " + "extras 'archivefile[7z]' and 'archivefile[rar]'." + ) + super().__init__(message, file=file) + + +class ArchiveMemberNotFoundError(ArchiveFileError): + """ + Raised when a specified member (file or directory) is not found inside the archive file. + """ + + def __init__(self, *, member: str, file: StrPath) -> None: + self._member = member + filename = Path(file).as_posix() + message = f"Archive member {member!r} not found in file: {filename!r}" + super().__init__(message, file=file) + + @property + def member(self) -> str: + """The member that was not found.""" + return self._member + + +class ArchiveMemberNotAFileError(ArchiveFileError): + """ + Raised when a specified member is not a file (e.g., it's a directory). + """ + + def __init__(self, *, member: str, file: StrPath) -> None: + self._member = member + filename = Path(file).as_posix() + message = f"Archive member {member!r} in file {filename!r} exists but is not a file." + super().__init__(message, file=file) + + @property + def member(self) -> str: + """The member that is not a file.""" + return self._member diff --git a/tests/__init__.py b/src/archivefile/_impl/__init__.py similarity index 100% rename from tests/__init__.py rename to src/archivefile/_impl/__init__.py diff --git a/src/archivefile/_impl/_abc.py b/src/archivefile/_impl/_abc.py new file mode 100644 index 0000000..1b55ce7 --- /dev/null +++ b/src/archivefile/_impl/_abc.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +import abc +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + + from .._models import ArchiveMember + from .._types import ErrorHandler, MemberLike, StrPath + + +class AbstractArchiveFile(abc.ABC): + def __init__(self, file: StrPath, /, *, password: str | None = None) -> None: + self._file = Path(file) + self._password = password + super().__init__() + + @property + def file(self) -> Path: + return self._file + + @property + def password(self) -> str | None: + return self._password + + @abc.abstractmethod + def get_member(self, member: MemberLike, /) -> ArchiveMember: ... + + @abc.abstractmethod + def get_members(self) -> Iterator[ArchiveMember]: ... + + @abc.abstractmethod + def get_names(self) -> tuple[str, ...]: ... + + @abc.abstractmethod + def extract(self, member: MemberLike, /, *, destination: StrPath | None = None) -> Path: ... + + @abc.abstractmethod + def extractall( + self, + *, + destination: StrPath | None = None, + members: Iterable[MemberLike] | None = None, + ) -> Path: ... + + @abc.abstractmethod + def read_bytes(self, member: MemberLike, /) -> bytes: ... + + def read_text( + self, + member: MemberLike, + /, + *, + encoding: str = "utf-8", + errors: ErrorHandler = "strict", + ) -> str: + return self.read_bytes(member).decode(encoding=encoding, errors=errors) + + @abc.abstractmethod + def close(self) -> None: ... + + def __repr__(self) -> str: # pragma: no cover + file = self.file.as_posix() + cls = self.__class__.__name__ + if self.password: + return f"{cls}({file!r}, password='********')" + return f"{cls}({file!r})" diff --git a/src/archivefile/_impl/_rar.py b/src/archivefile/_impl/_rar.py new file mode 100644 index 0000000..ffa31c0 --- /dev/null +++ b/src/archivefile/_impl/_rar.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import io +from pathlib import Path +from typing import TYPE_CHECKING + +from .._errors import ArchiveMemberNotAFileError, ArchiveMemberNotFoundError +from .._models import ArchiveMember +from .._utils import get_member_name, realpath, validate_members +from ._abc import AbstractArchiveFile + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + + from rarfile import RarInfo + + from .._types import MemberLike, StrPath + + +def is_rarfile(file: StrPath, /) -> bool: + try: + import rarfile + + return rarfile.is_rarfile(file) or rarfile.is_rarfile_sfx(file) # type: ignore[no-any-return] + except ModuleNotFoundError: + return False + + +def _rarinfo_to_member(rarinfo: RarInfo, /) -> ArchiveMember: + return ArchiveMember( + name=rarinfo.filename, + size=rarinfo.file_size, + compressed_size=rarinfo.compress_size, + is_dir=rarinfo.filename.endswith("/"), + is_file=not rarinfo.filename.endswith("/"), + ) + + +class RarArchiveFile(AbstractArchiveFile): + def __init__(self, file: StrPath, /, *, password: str | None = None) -> None: + try: + import rarfile + except ModuleNotFoundError: # pragma: no cover + filename = Path(file).as_posix() + msg = ( + f"Cannot open archive: {filename!r}\n" + "RAR support requires the 'rarfile' package, which is not installed.\n" + "To enable RAR support, install archivefile with the optional RAR dependencies: 'archivefile[rar]'" + ) + raise ModuleNotFoundError(msg) from None + + super().__init__(file, password=password) + self._RarFile = rarfile.RarFile + self._NoRarEntry = rarfile.NoRarEntry + self._rarfile = self._RarFile(self._file) + + def get_member(self, member: MemberLike, /) -> ArchiveMember: + name = get_member_name(member) + + try: + # ZipFile and TarFile raise KeyError but RarFile raises it's own NoRarEntry + # So for consistency's sake, we'll also raise KeyError here + rarinfo: RarInfo = self._rarfile.getinfo(name) + except self._NoRarEntry: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return _rarinfo_to_member(rarinfo) + + def get_members(self) -> Iterator[ArchiveMember]: + for rarinfo in self._rarfile.infolist(): + yield _rarinfo_to_member(rarinfo) + + def get_names(self) -> tuple[str, ...]: + return tuple(self._rarfile.namelist()) + + def extract(self, member: MemberLike, /, *, destination: StrPath | None = None) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + name = get_member_name(member) + + try: + # ZipFile and TarFile raise KeyError but RarFile raises it's own NoRarEntry + # So for consistency's sake, we'll also raise KeyError here + self._rarfile.extract(member=name, path=destination, pwd=self._password) + except self._NoRarEntry: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return destination / name + + def extractall( + self, + *, + destination: StrPath | None = None, + members: Iterable[MemberLike] | None = None, + ) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + if members: + names = validate_members(members, available=self._rarfile.namelist(), archive=self.file) + self._rarfile.extractall(path=destination, members=names, pwd=self._password) + else: + self._rarfile.extractall(path=destination, pwd=self._password) + + return destination + + def read_bytes(self, member: MemberLike, /) -> bytes: + name = get_member_name(member) + + try: + data: bytes = self._rarfile.read(name, pwd=self._password) + except self._NoRarEntry: + # `name` simply does not exist in the archive. + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + except io.UnsupportedOperation: + # `name` is NOT a file. So we cannot read it. + raise ArchiveMemberNotAFileError(member=name, file=self.file) from None + else: + return data + + def close(self) -> None: + self._rarfile.close() diff --git a/src/archivefile/_impl/_sevenzip.py b/src/archivefile/_impl/_sevenzip.py new file mode 100644 index 0000000..8f7a36a --- /dev/null +++ b/src/archivefile/_impl/_sevenzip.py @@ -0,0 +1,178 @@ +from __future__ import annotations + +import io +from pathlib import Path +from typing import TYPE_CHECKING + +from .._errors import ArchiveMemberNotAFileError, ArchiveMemberNotFoundError +from .._models import ArchiveMember +from .._utils import get_member_name, realpath, validate_members +from ._abc import AbstractArchiveFile + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + + from py7zr import FileInfo + from py7zr.io import Py7zIO, WriterFactory + + from .._types import MemberLike, StrPath +else: + Py7zIO = object + WriterFactory = object + + +def is_7zfile(file: StrPath, /) -> bool: + try: + import py7zr + + return py7zr.is_7zfile(file) # type: ignore[arg-type] + except ModuleNotFoundError: + return False + + +class Py7zBytesIO(Py7zIO): + def __init__(self, filename: str): + self.filename = filename + self._buffer = io.BytesIO() + + def write(self, s: bytes | bytearray) -> int: + return self._buffer.write(s) + + def read(self, size: int | None = None) -> bytes: + return self._buffer.read() + + def seek(self, offset: int, whence: int = 0) -> int: + return self._buffer.seek(offset, whence) + + def flush(self) -> None: # pragma: no cover + # Required by the abstract interface. Not used in this implementation. + return self._buffer.flush() + + def size(self) -> int: # pragma: no cover + # Required by the abstract interface. Not used in this implementation. + return self._buffer.getbuffer().nbytes + + +class BytesIOFactory(WriterFactory): + def __init__(self) -> None: + self.products: dict[str, Py7zBytesIO] = {} + + def create(self, filename: str) -> Py7zIO: + product = Py7zBytesIO(filename) + self.products[filename] = product + return product + + def read(self, filename: str) -> bytes: + return self.products[filename].read() + + +def _sevenzipinfo_to_member(sevenzipinfo: FileInfo, /) -> ArchiveMember: + is_dir = sevenzipinfo.is_directory + name = sevenzipinfo.filename + + if is_dir and not name.endswith("/"): + name += "/" + + return ArchiveMember( + name=name, + size=sevenzipinfo.uncompressed, + # Sometimes sevenzip can return 0 for compressed size when there's no compression. + # In that case we simply return the uncompressed size instead. + compressed_size=sevenzipinfo.compressed or sevenzipinfo.uncompressed, + is_dir=is_dir, + is_file=not is_dir, + ) + + +class SevenZipArchiveFile(AbstractArchiveFile): + def __init__(self, file: StrPath, /, *, password: str | None = None) -> None: + try: + import py7zr + except ModuleNotFoundError: # pragma: no cover + filename = Path(file).as_posix() + msg = ( + f"Cannot open archive: {filename!r}\n" + "7z support requires the 'py7zr' package, which is not installed.\n" + "To enable 7z support, install archivefile with the optional 7z dependencies: 'archivefile[7z]'" + ) + raise ModuleNotFoundError(msg) from None + + super().__init__(file, password=password) + self._sevenzipfile = py7zr.SevenZipFile(self.file, password=self.password) + + def get_member(self, member: MemberLike, /) -> ArchiveMember: + # TODO: Replace this implementation with SevenZipFile.getinfo + # once py7zr releases a version that fixes this bug: + # https://github.com/miurahr/py7zr/issues/675 + name = get_member_name(member).removesuffix("/") + try: + sevenzipinfo: FileInfo = next(member for member in self._sevenzipfile.list() if member.filename == name) + except StopIteration: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return _sevenzipinfo_to_member(sevenzipinfo) + + def get_members(self) -> Iterator[ArchiveMember]: + for sevenzipinfo in self._sevenzipfile.list(): + yield _sevenzipinfo_to_member(sevenzipinfo) + + def get_names(self) -> tuple[str, ...]: + return tuple(member.name for member in self.get_members()) + + def extract(self, member: MemberLike, /, *, destination: StrPath | None = None) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + name = get_member_name(member) + + if name in self._sevenzipfile.getnames(): + self._sevenzipfile.extract(path=destination, targets=[name], recursive=True) + else: + raise ArchiveMemberNotFoundError(member=name, file=self.file) + + self._sevenzipfile.reset() + return destination / name + + def extractall( + self, + *, + destination: StrPath | None = None, + members: Iterable[MemberLike] | None = None, + ) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + if members: + names = validate_members(members, available=self._sevenzipfile.getnames(), archive=self.file) + self._sevenzipfile.extract(path=destination, targets=names, recursive=True) + else: + self._sevenzipfile.extractall(path=destination) + + self._sevenzipfile.reset() + return destination + + def read_bytes(self, member: MemberLike, /) -> bytes: + name = get_member_name(member) + + # SevenZipFile listings do not preserve trailing `/`, + # so we normalize the name for lookup while keeping + # the original for clearer error messages. + normname = name.removesuffix("/") + + if normname not in self._sevenzipfile.getnames(): + # `name` simply does not exist in the archive. + raise ArchiveMemberNotFoundError(member=normname, file=self.file) + + factory = BytesIOFactory() + self._sevenzipfile.extract(targets=[normname], factory=factory) + self._sevenzipfile.reset() + + try: + data = factory.read(normname) + except KeyError: + # `name` is NOT a file. So we cannot read it. + raise ArchiveMemberNotAFileError(member=name, file=self.file) from None + else: + return data + + def close(self) -> None: + self._sevenzipfile.close() # type: ignore[no-untyped-call] diff --git a/src/archivefile/_impl/_tar.py b/src/archivefile/_impl/_tar.py new file mode 100644 index 0000000..e236517 --- /dev/null +++ b/src/archivefile/_impl/_tar.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +import tarfile +from pathlib import Path +from typing import TYPE_CHECKING + +from .._errors import ArchiveMemberNotAFileError, ArchiveMemberNotFoundError +from .._models import ArchiveMember +from .._utils import get_member_name, realpath, validate_members +from ._abc import AbstractArchiveFile + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + + from .._types import MemberLike, StrPath + + +def _tarinfo_to_member(tarinfo: tarfile.TarInfo, /) -> ArchiveMember: + is_dir = tarinfo.isdir() + name = tarinfo.name + if is_dir and not name.endswith("/"): + name += "/" + + return ArchiveMember( + name=name, + size=tarinfo.size, + compressed_size=tarinfo.size, + is_dir=is_dir, + is_file=tarinfo.isfile(), + ) + + +class TarArchiveFile(AbstractArchiveFile): + def __init__(self, file: StrPath, /, *, password: str | None = None) -> None: + super().__init__(file, password=password) + self._tarfile = tarfile.TarFile.open(self.file) + # https://docs.python.org/3/library/tarfile.html#supporting-older-python-versions + self._tarfile.extraction_filter = getattr(tarfile, "data_filter", (lambda member, path: member)) + + def get_member(self, member: MemberLike, /) -> ArchiveMember: + name = get_member_name(member) + try: + tarinfo = self._tarfile.getmember(name) + except KeyError: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return _tarinfo_to_member(tarinfo) + + def get_members(self) -> Iterator[ArchiveMember]: + for tarinfo in self._tarfile.getmembers(): + yield _tarinfo_to_member(tarinfo) + + def get_names(self) -> tuple[str, ...]: + return tuple(member.name for member in self.get_members()) + + def extract(self, member: MemberLike, /, *, destination: StrPath | None = None) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + name = get_member_name(member) + try: + self._tarfile.extract(member=name, path=destination) + except KeyError: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return destination / name + + def extractall( + self, + *, + destination: StrPath | None = None, + members: Iterable[MemberLike] | None = None, + ) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + if members: + members = validate_members(members, available=self._tarfile.getnames(), archive=self.file) + self._tarfile.extractall(path=destination, members=members) # type: ignore[arg-type] + else: + self._tarfile.extractall(path=destination) + + return destination + + def read_bytes(self, member: MemberLike, /) -> bytes: + name = get_member_name(member) + + try: + fileobj = self._tarfile.extractfile(name) + except KeyError: + # `name` simply does not exist in the archive. + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + if fileobj is None: + # `name` is NOT a file. So we cannot read it. + raise ArchiveMemberNotAFileError(member=name, file=self.file) from None + + return fileobj.read() + + def close(self) -> None: + self._tarfile.close() diff --git a/src/archivefile/_impl/_zip.py b/src/archivefile/_impl/_zip.py new file mode 100644 index 0000000..3a4f840 --- /dev/null +++ b/src/archivefile/_impl/_zip.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING +from zipfile import ZipFile, ZipInfo + +from .._errors import ArchiveMemberNotAFileError, ArchiveMemberNotFoundError +from .._models import ArchiveMember +from .._utils import get_member_name, realpath, validate_members +from ._abc import AbstractArchiveFile + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + + from .._types import MemberLike, StrPath + + +def _zipinfo_to_member(zipinfo: ZipInfo, /) -> ArchiveMember: + return ArchiveMember( + name=zipinfo.filename, + size=zipinfo.file_size, + compressed_size=zipinfo.compress_size, + is_dir=zipinfo.is_dir(), + is_file=not zipinfo.is_dir(), + ) + + +class ZipArchiveFile(AbstractArchiveFile): + def __init__(self, file: StrPath, /, *, password: str | None = None) -> None: + super().__init__(file, password=password) + self._encoded_password = password.encode() if password else None + self._zipfile = ZipFile(self.file) + + def get_member(self, member: MemberLike, /) -> ArchiveMember: + name = get_member_name(member) + try: + zipinfo = self._zipfile.getinfo(name) + except KeyError: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return _zipinfo_to_member(zipinfo) + + def get_members(self) -> Iterator[ArchiveMember]: + for zipinfo in self._zipfile.filelist: + yield _zipinfo_to_member(zipinfo) + + def get_names(self) -> tuple[str, ...]: + return tuple(self._zipfile.namelist()) + + def extract(self, member: MemberLike, /, *, destination: StrPath | None = None) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + name = get_member_name(member) + try: + self._zipfile.extract(member=name, path=destination, pwd=self._encoded_password) + except KeyError: + raise ArchiveMemberNotFoundError(member=name, file=self.file) from None + + return destination / name + + def extractall( + self, + *, + destination: StrPath | None = None, + members: Iterable[MemberLike] | None = None, + ) -> Path: + destination = realpath(destination) if destination else Path.cwd() + destination.mkdir(parents=True, exist_ok=True) + + if members: + members = validate_members(members, available=self._zipfile.namelist(), archive=self.file) + self._zipfile.extractall(path=destination, members=members) + else: + self._zipfile.extractall(path=destination) + + return destination + + def read_bytes(self, member: MemberLike, /) -> bytes: + member = self.get_member(member) + + if member.is_dir: + # `name` is NOT a file. So we cannot read it. + raise ArchiveMemberNotAFileError(member=member.name, file=self.file) from None + + # At this point, `self.get_member(member)` ensures the member exists, + # and the `if member.is_dir` check ensures it is a regular file. + # Therefore, reading its contents here is safe. + return self._zipfile.read(member.name, pwd=self._encoded_password) + + def close(self) -> None: + self._zipfile.close() diff --git a/src/archivefile/_models.py b/src/archivefile/_models.py index 43df9e2..9c68946 100644 --- a/src/archivefile/_models.py +++ b/src/archivefile/_models.py @@ -1,52 +1,28 @@ from __future__ import annotations -from datetime import datetime -from typing import Any +from dataclasses import dataclass -from pydantic import BaseModel, ByteSize, ConfigDict, ValidationInfo, field_validator -from archivefile._types import UTCDateTime - - -class ArchiveMember(BaseModel): +@dataclass(frozen=True, kw_only=True, slots=True) +class ArchiveMember: """ Represents a member of an archive file. - This is immutable, hashable, and supports equality checking. """ - model_config = ConfigDict(frozen=True) - name: str """Name of the archive member.""" - size: ByteSize = ByteSize(0) + size: int """Uncompressed size of the archive member.""" - compressed_size: ByteSize = ByteSize(0) + compressed_size: int """Compressed size of the archive member.""" - datetime: UTCDateTime = datetime.min - """The time and date of the last modification to the archive member.""" - - checksum: int = 0 - """CRC32 checksum if the archive is a ZipFile, RarFile, or SevenZipFile. Header checksum if archive is a TarFile.""" - - is_dir: bool = False + is_dir: bool """True if the archive member is a directory, False otherwise.""" - is_file: bool = False + is_file: bool """True if the archive member is a file, False otherwise.""" - @field_validator("*", mode="before") - @classmethod - def _use_default_value(cls, v: Any, info: ValidationInfo) -> Any: - if v is None: - return cls.model_fields[info.field_name].default # type: ignore - return v - def __str__(self) -> str: - """ - Simple string representation. - This is equivalent to `ArchiveMember.name` - """ return self.name diff --git a/src/archivefile/_types.py b/src/archivefile/_types.py index fdb9978..9b6b415 100644 --- a/src/archivefile/_types.py +++ b/src/archivefile/_types.py @@ -1,71 +1,13 @@ from __future__ import annotations -from datetime import datetime, timezone -from pathlib import Path -from typing import Annotated, Literal, TypeAlias, Union +import os +from typing import TYPE_CHECKING, Literal, TypeAlias -from pydantic import AfterValidator -from typing_extensions import TypeVar - -UTCDateTime = Annotated[datetime, AfterValidator(lambda dt: dt.astimezone(timezone.utc))] -"""Datetime that's always in UTC.""" - -StrPath: TypeAlias = Union[str, Path] - -T = TypeVar("T") -CollectionOf: TypeAlias = Union[list[T], tuple[T, ...], set[T]] -"""Type alias representing a union of list, tuple, and set.""" - -OpenArchiveMode: TypeAlias = Literal[ - "r", - "r:*", - "r:", - "r:gz", - "r:bz2", - "r:xz", - "w", - "w:", - "w:gz", - "w:bz2", - "w:xz", - "x", - "x:", - "x:", - "x:gz", - "x:bz2", - "x:xz", - "a", - "a:", -] - -TreeStyle: TypeAlias = Literal["ansi", "ascii", "const", "const_bold", "rounded", "double"] - -TableStyle: TypeAlias = Literal[ - "ascii", - "ascii2", - "ascii_double_head", - "square", - "square_double_head", - "minimal", - "minimal_heavy_head", - "minimal_double_head", - "simple", - "simple_head", - "simple_heavy", - "horizontals", - "rounded", - "heavy", - "heavy_edge", - "heavy_head", - "double", - "double_edge", - "markdown", -] - -SortBy: TypeAlias = Literal["name", "datetime", "size", "compressed_size", "checksum"] +if TYPE_CHECKING: + from ._models import ArchiveMember +StrPath: TypeAlias = str | os.PathLike[str] +MemberLike: TypeAlias = "StrPath | ArchiveMember" ErrorHandler: TypeAlias = Literal[ "strict", "ignore", "replace", "backslashreplace", "surrogateescape", "xmlcharrefreplace", "namereplace" ] - -CompressionLevel: TypeAlias = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] diff --git a/src/archivefile/_utils.py b/src/archivefile/_utils.py index 9556372..22cce39 100644 --- a/src/archivefile/_utils.py +++ b/src/archivefile/_utils.py @@ -1,14 +1,16 @@ from __future__ import annotations +import os from pathlib import Path -from tarfile import is_tarfile -from zipfile import is_zipfile +from typing import TYPE_CHECKING -from py7zr import is_7zfile -from rarfile import is_rarfile, is_rarfile_sfx +from ._errors import ArchiveMemberNotFoundError +from ._models import ArchiveMember -from archivefile._models import ArchiveMember -from archivefile._types import StrPath +if TYPE_CHECKING: + from collections.abc import Iterable, Sequence + + from ._types import MemberLike, StrPath def realpath(path: StrPath) -> Path: @@ -24,48 +26,68 @@ def realpath(path: StrPath) -> Path: ------- Path The path after expanding the user's home directory and resolving any symbolic links. - """ - return path.expanduser().resolve() if isinstance(path, Path) else Path(path).expanduser().resolve() - -def is_archive(file: StrPath) -> bool: """ - Check whether the given archive file is a supported archive or not. + return Path(path).expanduser().resolve() - Parameters - --------- - file : StrPath - Path to the archive file. - - Returns - ------- - bool - True if the archive is supported, False otherwise. - """ - file = realpath(file) - - if file.exists(): - return is_tarfile(file) or is_zipfile(file) or is_rarfile(file) or is_rarfile_sfx(file) or is_7zfile(file) - else: - return False - -def get_member_name(member: StrPath | ArchiveMember) -> str: - """Get the member name from a string, path, or ArchiveMember""" +def get_member_name(member: MemberLike, /) -> str: + """Get the member name from a string, path, or ArchiveMember.""" match member: + case str(): + return member + case ArchiveMember(): return member.name - case Path(): - return member.relative_to(member.anchor).as_posix() + case os.PathLike(): + return Path(member).as_posix() case _: - return member + msg = ( + f"Unsupported type for 'member'. Expected 'str', 'PathLike', or 'ArchiveMember', " + f"but got {type(member).__name__!r}." + ) + raise TypeError(msg) -def clamp_compression_level(level: int) -> int: +def validate_members(requested: Iterable[MemberLike], /, *, available: Iterable[str], archive: Path) -> Sequence[str]: """ - Pretty simple method to clamp compression level to a valid range + Validate and normalize requested archive members. + + Parameters + ---------- + requested : Iterable[str] + File names requested by the user. May contain duplicates. + Order will be preserved. + available : Iterable[str] + All available member names in the archive. + archive : str + Path to the archive file, used in error reporting. + + Returns + ------- + Sequence[str] + Normalized, validated file names. Preserves the input order and + removes duplicates. + + Raises + ------ + ArchiveMemberNotFoundError + If a requested file is not present in the archive. + """ - return max(0, min(level, 9)) + available = set(available) + seen: set[str] = set() + out: list[str] = [] + + for req in requested: + name = get_member_name(req) + if name not in available: + raise ArchiveMemberNotFoundError(member=name, file=archive) from None + if name not in seen: + seen.add(name) + out.append(name) + + return out diff --git a/src/archivefile/_version.py b/src/archivefile/_version.py deleted file mode 100644 index 040f997..0000000 --- a/src/archivefile/_version.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import annotations - -from importlib import metadata - -from typing_extensions import NamedTuple - - -class Version(NamedTuple): - """Version tuple based on SemVer""" - - major: int - """Major version number""" - minor: int - """Minor version number""" - patch: int - """Patch version number""" - - -def _get_version() -> str: - """ - Get the version of archivefile - """ - try: - return metadata.version("archivefile") - - except metadata.PackageNotFoundError: - return "0.0.0" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..f595dae --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from importlib.util import find_spec +from pathlib import Path +from typing import TYPE_CHECKING + +import pytest + +from archivefile import ArchiveFile + +if TYPE_CHECKING: + from collections.abc import Iterator + +NO_PY7ZR = find_spec("py7zr") is None +NO_RARFILE = find_spec("rarfile") is None + + +@pytest.fixture( + params=[ + pytest.param(Path("tests/test_data/source_GNU.tar"), id="GNU.tar"), + pytest.param(Path("tests/test_data/source_LZMA.zip"), id="LZMA.zip"), + pytest.param(Path("tests/test_data/source_POSIX.tar.gz"), id="POSIX.tar.gz"), + pytest.param( + Path("tests/test_data/source_LZMA.7z"), + marks=pytest.mark.skipif(NO_PY7ZR, reason="py7zr is not installed."), + id="LZMA.7z", + ), + pytest.param( + Path("tests/test_data/source_BEST.rar"), + marks=pytest.mark.skipif(NO_RARFILE, reason="rarfile is not installed."), + id="BEST.rar", + ), + ] +) +def archive_file(request: pytest.FixtureRequest) -> Iterator[ArchiveFile]: + with ArchiveFile(request.param) as f: + assert str(f) == repr(f) == f"ArchiveFile('{request.param.resolve().as_posix()}')" + yield f diff --git a/tests/test_data/source_BZIP2.7z b/tests/test_data/source_BZIP2.7z deleted file mode 100644 index 2cafa38..0000000 Binary files a/tests/test_data/source_BZIP2.7z and /dev/null differ diff --git a/tests/test_data/source_BZIP2.zip b/tests/test_data/source_BZIP2.zip deleted file mode 100644 index 61ea2d7..0000000 Binary files a/tests/test_data/source_BZIP2.zip and /dev/null differ diff --git a/tests/test_data/source_BZIP2_SOLID.7z b/tests/test_data/source_BZIP2_SOLID.7z deleted file mode 100644 index 2cafa38..0000000 Binary files a/tests/test_data/source_BZIP2_SOLID.7z and /dev/null differ diff --git a/tests/test_data/source_DEFLATE.zip b/tests/test_data/source_DEFLATE.zip deleted file mode 100644 index 4c09604..0000000 Binary files a/tests/test_data/source_DEFLATE.zip and /dev/null differ diff --git a/tests/test_data/source_DEFLATE64.zip b/tests/test_data/source_DEFLATE64.zip deleted file mode 100644 index 3940613..0000000 Binary files a/tests/test_data/source_DEFLATE64.zip and /dev/null differ diff --git a/tests/test_data/source_GNU.tar.bz2 b/tests/test_data/source_GNU.tar.bz2 deleted file mode 100644 index 55dab3a..0000000 Binary files a/tests/test_data/source_GNU.tar.bz2 and /dev/null differ diff --git a/tests/test_data/source_GNU.tar.gz b/tests/test_data/source_GNU.tar.gz deleted file mode 100644 index 0c36876..0000000 Binary files a/tests/test_data/source_GNU.tar.gz and /dev/null differ diff --git a/tests/test_data/source_GNU.tar.xz b/tests/test_data/source_GNU.tar.xz deleted file mode 100644 index 5bf6719..0000000 Binary files a/tests/test_data/source_GNU.tar.xz and /dev/null differ diff --git a/tests/test_data/source_LZMA2.7z b/tests/test_data/source_LZMA2.7z deleted file mode 100644 index a2a1172..0000000 Binary files a/tests/test_data/source_LZMA2.7z and /dev/null differ diff --git a/tests/test_data/source_LZMA2_SOLID.7z b/tests/test_data/source_LZMA2_SOLID.7z deleted file mode 100644 index a2a1172..0000000 Binary files a/tests/test_data/source_LZMA2_SOLID.7z and /dev/null differ diff --git a/tests/test_data/source_LZMA_SOLID.7z b/tests/test_data/source_LZMA_SOLID.7z deleted file mode 100644 index 8975b2a..0000000 Binary files a/tests/test_data/source_LZMA_SOLID.7z and /dev/null differ diff --git a/tests/test_data/source_POSIX.tar b/tests/test_data/source_POSIX.tar deleted file mode 100644 index 635e6f6..0000000 Binary files a/tests/test_data/source_POSIX.tar and /dev/null differ diff --git a/tests/test_data/source_POSIX.tar.bz2 b/tests/test_data/source_POSIX.tar.bz2 deleted file mode 100644 index 55dab3a..0000000 Binary files a/tests/test_data/source_POSIX.tar.bz2 and /dev/null differ diff --git a/tests/test_data/source_POSIX.tar.xz b/tests/test_data/source_POSIX.tar.xz deleted file mode 100644 index efb7da9..0000000 Binary files a/tests/test_data/source_POSIX.tar.xz and /dev/null differ diff --git a/tests/test_data/source_PPMD.7z b/tests/test_data/source_PPMD.7z deleted file mode 100644 index 6952db8..0000000 Binary files a/tests/test_data/source_PPMD.7z and /dev/null differ diff --git a/tests/test_data/source_PPMD.zip b/tests/test_data/source_PPMD.zip deleted file mode 100644 index b671f81..0000000 Binary files a/tests/test_data/source_PPMD.zip and /dev/null differ diff --git a/tests/test_data/source_PPMD_SOLID.7z b/tests/test_data/source_PPMD_SOLID.7z deleted file mode 100644 index 6952db8..0000000 Binary files a/tests/test_data/source_PPMD_SOLID.7z and /dev/null differ diff --git a/tests/test_data/source_STORE.7z b/tests/test_data/source_STORE.7z deleted file mode 100644 index 970e1dd..0000000 Binary files a/tests/test_data/source_STORE.7z and /dev/null differ diff --git a/tests/test_data/source_STORE.rar b/tests/test_data/source_STORE.rar deleted file mode 100644 index 0540e55..0000000 Binary files a/tests/test_data/source_STORE.rar and /dev/null differ diff --git a/tests/test_data/source_STORE.zip b/tests/test_data/source_STORE.zip deleted file mode 100644 index e7c120b..0000000 Binary files a/tests/test_data/source_STORE.zip and /dev/null differ diff --git a/tests/test_enums.py b/tests/test_enums.py deleted file mode 100644 index 4717957..0000000 --- a/tests/test_enums.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import annotations - -from archivefile import CompressionType - - -def test_compression_type_enum() -> None: - assert CompressionType.get("stored") is CompressionType.STORED - assert CompressionType.get("DEFLATED") is CompressionType.DEFLATED - assert CompressionType.get("bziP2") is CompressionType.BZIP2 - assert CompressionType.get("lzMa") is CompressionType.LZMA - - assert CompressionType.get(0) is CompressionType.STORED - assert CompressionType.get(8) is CompressionType.DEFLATED - assert CompressionType.get(12) is CompressionType.BZIP2 - assert CompressionType.get(14) is CompressionType.LZMA - - assert CompressionType.get(CompressionType.STORED) is CompressionType.STORED - assert CompressionType.get(CompressionType.DEFLATED) is CompressionType.DEFLATED - assert CompressionType.get(CompressionType.BZIP2) is CompressionType.BZIP2 - assert CompressionType.get(CompressionType.LZMA) is CompressionType.LZMA - - assert CompressionType.get(999999999999) is CompressionType.STORED - assert CompressionType.get("non-existent-key") is CompressionType.STORED - assert CompressionType.get(999999999999, "bzip2") is CompressionType.BZIP2 - assert CompressionType.get("non-existent-key", "lzma") is CompressionType.LZMA - - assert CompressionType.get(999999999999) is CompressionType.STORED - assert CompressionType.get("non-existent-key") is CompressionType.STORED - assert CompressionType.get(999999999999, CompressionType.BZIP2) is CompressionType.BZIP2 - assert CompressionType.get("non-existent-key", CompressionType.LZMA) is CompressionType.LZMA diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index b81eb1e..a10daa8 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,159 +1,87 @@ from __future__ import annotations -from pathlib import Path +import re +from typing import TYPE_CHECKING import pytest -from archivefile import ArchiveFile - -modes = ( - "w", - "w:", - "w:gz", - "w:bz2", - "w:xz", - "x:", - "x:", - "x:gz", - "x:bz2", - "x:xz", - "a", - "a:", -) - -extensions = ("zip", "cbz") + ("tar", "tar.bz2", "tar.gz", "tar.xz", "cbt") + ("7z", "cb7") - -files = ( - Path("tests/test_data/source_BEST.rar"), - Path("tests/test_data/source_BZIP2.7z"), - Path("tests/test_data/source_BZIP2.zip"), - Path("tests/test_data/source_DEFLATE.zip"), - Path("tests/test_data/source_DEFLATE64.zip"), # Deflate64 is not supported by ZipFile - Path("tests/test_data/source_GNU.tar"), - Path("tests/test_data/source_GNU.tar.bz2"), - Path("tests/test_data/source_GNU.tar.gz"), - Path("tests/test_data/source_GNU.tar.xz"), - Path("tests/test_data/source_LZMA.7z"), - Path("tests/test_data/source_LZMA.zip"), - Path("tests/test_data/source_LZMA2.7z"), - Path("tests/test_data/source_POSIX.tar"), - Path("tests/test_data/source_POSIX.tar.bz2"), - Path("tests/test_data/source_POSIX.tar.gz"), - Path("tests/test_data/source_POSIX.tar.xz"), - Path("tests/test_data/source_PPMD.7z"), - Path("tests/test_data/source_PPMD.zip"), # PPMd is not supported by ZipFile - Path("tests/test_data/source_STORE.7z"), - Path("tests/test_data/source_LZMA_SOLID.7z"), - Path("tests/test_data/source_LZMA2_SOLID.7z"), - Path("tests/test_data/source_PPMD_SOLID.7z"), - Path("tests/test_data/source_BZIP2_SOLID.7z"), - Path("tests/test_data/source_STORE.rar"), - Path("tests/test_data/source_STORE.zip"), -) - -# Alias the pre-configured parametrize function for reusability -parametrize_files = pytest.mark.parametrize("file", files, ids=lambda x: x.name) - - -def test_write_rar() -> None: - with pytest.raises(NotImplementedError): - with ArchiveFile("somerar.rar", "w") as archive: - archive.read_text("somefile.txt") - - with pytest.raises(NotImplementedError): - with ArchiveFile("tests/test_data/source_BEST.rar", "w") as archive: - archive.print_tree() - - -def test_write_not_archive() -> None: - with pytest.raises(NotImplementedError): - with ArchiveFile("somefile.hello", "w") as archive: - archive.read_text("somefile.txt") - - -def test_write_without_write_mode() -> None: - with pytest.raises(FileNotFoundError): - with ArchiveFile("somefile.zip", "r") as archive: - archive.read_text("somefile.txt") - - -def test_write_mode_x_sevenzip(tmp_path: Path) -> None: - file = tmp_path / "archive.7z" - with ArchiveFile(file, "x") as archive: - archive.write_text("abc1234", arcname="a.txt") - - with pytest.raises(FileExistsError): - with ArchiveFile(file, "x") as archive: - archive.write_text("abc1234", arcname="a.txt") - - -def test_existing_unsupported_archive(tmp_path: Path) -> None: - file = tmp_path / "archive.yaml" - file.touch() - with pytest.raises(NotImplementedError): - with ArchiveFile(file, "x") as archive: - archive.write_text("abc1234", arcname="a.txt") - - -@parametrize_files -def test_missing_member(file: Path) -> None: - with pytest.raises(KeyError): - with ArchiveFile(file) as archive: - archive.get_member("non-existent.member") - - -@parametrize_files -def test_missing_member_in_read_bytes(file: Path) -> None: - with pytest.raises(KeyError): - with ArchiveFile(file) as archive: - archive.read_bytes("non-existent.member") - - -@parametrize_files -def test_missing_member_in_read_text(file: Path) -> None: - with pytest.raises(KeyError): - with ArchiveFile(file) as archive: - archive.read_text("non-existent.member") - - -@parametrize_files -def test_missing_member_in_extract(file: Path) -> None: - with pytest.raises(KeyError): - with ArchiveFile(file) as archive: - archive.extract("non-existent.member") - - -@parametrize_files -def test_missing_member_in_extractall(file: Path, tmp_path: Path) -> None: - with pytest.raises(KeyError): - with ArchiveFile(file) as archive: - archive.extractall(destination=tmp_path, members=["non-existent.member"]) - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_not_a_file(tmp_path: Path, mode: str, extension: str) -> None: - with pytest.raises(ValueError): - archive_file = tmp_path / f"somefile.{extension}" - with ArchiveFile(archive_file, mode) as archive: - archive.write(tmp_path) - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_not_a_dir(tmp_path: Path, mode: str, extension: str) -> None: - with pytest.raises(ValueError): - archive_file = tmp_path / f"somefile.{extension}" - file = tmp_path / "somefile.txt" - file.touch() - with ArchiveFile(archive_file, mode) as archive: - archive.writeall(file) +from archivefile import ArchiveFile, ArchiveMemberNotFoundError, UnsupportedArchiveFormatError -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_writeall_not_dir(tmp_path: Path, mode: str, extension: str) -> None: - archive_dir = Path("src/archivefile").resolve() - with pytest.raises(ValueError): - dir = tmp_path / f"somefile.{extension}" - with ArchiveFile(dir, mode) as archive: - archive.writeall(archive_dir, root=tmp_path) +if TYPE_CHECKING: + from pathlib import Path + + +def test_non_existent_file_error(tmp_path: Path) -> None: + archive_path = tmp_path / "foo.zip" + with pytest.raises(FileNotFoundError, match=re.escape(str(archive_path))): + ArchiveFile(archive_path) + + +def test_unsupported_archive_format_error(tmp_path: Path) -> None: + archive_path = tmp_path / "foo.zip" + archive_path.write_text("This is not a valid archive format.") + filename = archive_path.as_posix() + message = ( + f"Unsupported or unrecognized archive format for file: {filename!r}.\n" + "If this is a 7z or rar archive, support is available via the optional " + "extras 'archivefile[7z]' and 'archivefile[rar]'." + ) + with pytest.raises(UnsupportedArchiveFormatError, match=re.escape(message)) as exc: + ArchiveFile(archive_path) + + assert exc.value.file == archive_path + + +def test_bad_type_member(archive_file: ArchiveFile) -> None: + message = "Unsupported type for 'member'. Expected 'str', 'PathLike', or 'ArchiveMember', but got 'object'." + with pytest.raises(TypeError, match=message): + archive_file.get_member(object()) # type: ignore[arg-type] + + +def test_missing_member(archive_file: ArchiveFile) -> None: + filename = archive_file.file.as_posix() + message = re.escape(f"Archive member 'non-existent.member' not found in file: {filename!r}") + with pytest.raises(ArchiveMemberNotFoundError, match=message) as exc: + archive_file.get_member("non-existent.member") + + assert exc.value.file == archive_file.file + + +def test_missing_member_in_read_bytes(archive_file: ArchiveFile) -> None: + filename = archive_file.file.as_posix() + message = re.escape(f"Archive member 'non-existent.member' not found in file: {filename!r}") + with pytest.raises(ArchiveMemberNotFoundError, match=message) as exc: + archive_file.read_bytes("non-existent.member") + + assert exc.value.member == "non-existent.member" + assert exc.value.file == archive_file.file + + +def test_missing_member_in_read_text(archive_file: ArchiveFile) -> None: + filename = archive_file.file.as_posix() + message = re.escape(f"Archive member 'non-existent.member' not found in file: {filename!r}") + with pytest.raises(ArchiveMemberNotFoundError, match=message) as exc: + archive_file.read_text("non-existent.member") + + assert exc.value.member == "non-existent.member" + assert exc.value.file == archive_file.file + + +def test_missing_member_in_extract(archive_file: ArchiveFile) -> None: + filename = archive_file.file.as_posix() + message = re.escape(f"Archive member 'non-existent.member' not found in file: {filename!r}") + with pytest.raises(ArchiveMemberNotFoundError, match=message) as exc: + archive_file.extract("non-existent.member") + + assert exc.value.member == "non-existent.member" + assert exc.value.file == archive_file.file + + +def test_missing_member_in_extractall(archive_file: ArchiveFile, tmp_path: Path) -> None: + filename = archive_file.file.as_posix() + message = re.escape(f"Archive member 'non-existent.member' not found in file: {filename!r}") + with pytest.raises(ArchiveMemberNotFoundError, match=message) as exc: + archive_file.extractall(destination=tmp_path, members=["non-existent.member"]) + + assert exc.value.member == "non-existent.member" + assert exc.value.file == archive_file.file diff --git a/tests/test_extract.py b/tests/test_extract.py index 97de94b..8f2ecb0 100644 --- a/tests/test_extract.py +++ b/tests/test_extract.py @@ -1,100 +1,57 @@ from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING from uuid import uuid4 from zipfile import ZipFile -import pytest -from archivefile import ArchiveFile, ArchiveMember +if TYPE_CHECKING: + from archivefile import ArchiveFile -files = ( - Path("tests/test_data/source_BEST.rar"), - Path("tests/test_data/source_BZIP2.7z"), - Path("tests/test_data/source_BZIP2.zip"), - Path("tests/test_data/source_DEFLATE.zip"), - # Path("tests/test_data/source_DEFLATE64.zip"), # Deflate64 is not supported by ZipFile - Path("tests/test_data/source_GNU.tar"), - Path("tests/test_data/source_GNU.tar.bz2"), - Path("tests/test_data/source_GNU.tar.gz"), - Path("tests/test_data/source_GNU.tar.xz"), - Path("tests/test_data/source_LZMA.7z"), - Path("tests/test_data/source_LZMA.zip"), - Path("tests/test_data/source_LZMA2.7z"), - Path("tests/test_data/source_POSIX.tar"), - Path("tests/test_data/source_POSIX.tar.bz2"), - Path("tests/test_data/source_POSIX.tar.gz"), - Path("tests/test_data/source_POSIX.tar.xz"), - Path("tests/test_data/source_PPMD.7z"), - # Path("tests/test_data/source_PPMD.zip"), # PPMd is not supported by ZipFile - Path("tests/test_data/source_STORE.7z"), - Path("tests/test_data/source_LZMA_SOLID.7z"), - Path("tests/test_data/source_LZMA2_SOLID.7z"), - Path("tests/test_data/source_PPMD_SOLID.7z"), - Path("tests/test_data/source_BZIP2_SOLID.7z"), - Path("tests/test_data/source_STORE.rar"), - Path("tests/test_data/source_STORE.zip"), -) -# Alias the pre-configured parametrize function for reusability -parametrize_files = pytest.mark.parametrize("file", files, ids=lambda x: x.name) +def test_extract(archive_file: ArchiveFile, tmp_path: Path) -> None: + member = archive_file.extract("pyanilist-main/README.md", destination=tmp_path) + assert member.is_file() -@parametrize_files -def test_extract(file: Path, tmp_path: Path) -> None: - with ArchiveFile(file) as archive: - member = archive.extract("pyanilist-main/README.md", destination=tmp_path) - assert member.is_file() - - -@parametrize_files -def test_extract_without_context_manager(file: Path, tmp_path: Path) -> None: - archive = ArchiveFile(file) - extracted_file = archive.extract("pyanilist-main/README.md", destination=tmp_path) - archive.close() +def test_extract_without_context_manager(archive_file: ArchiveFile, tmp_path: Path) -> None: + extracted_file = archive_file.extract("pyanilist-main/README.md", destination=tmp_path) assert extracted_file.is_file() -@parametrize_files -def test_extract_by_member(file: Path, tmp_path: Path) -> None: - with ArchiveFile(file) as archive: - member = [member for member in archive.get_members() if member.is_file][0] - outfile = archive.extract(member, destination=tmp_path) - assert outfile.is_file() +def test_extract_by_member(archive_file: ArchiveFile, tmp_path: Path) -> None: + member = next(member for member in archive_file.get_members() if member.is_file) + outfile = archive_file.extract(member, destination=tmp_path) + assert outfile.is_file() -@parametrize_files -def test_extractall(file: Path, tmp_path: Path) -> None: - with ZipFile("tests/test_data/source_STORE.zip") as archive: +def test_extractall(archive_file: ArchiveFile, tmp_path: Path) -> None: + with ZipFile("tests/test_data/source_LZMA.zip") as archive: dest = tmp_path / uuid4().hex archive.extractall(path=dest) control = tuple((dest / "pyanilist-main").rglob("*")) - with ArchiveFile(file) as archive: - dest2 = tmp_path / uuid4().hex - archive.extractall(destination=dest2) - members = tuple((dest / "pyanilist-main").rglob("*")) - assert control == members + dest2 = tmp_path / uuid4().hex + archive_file.extractall(destination=dest2) + members = tuple((dest / "pyanilist-main").rglob("*")) + assert control == members -@parametrize_files -def test_extractall_by_members(file: Path, tmp_path: Path) -> None: +def test_extractall_by_members(archive_file: ArchiveFile, tmp_path: Path) -> None: expected = [ "pyanilist-main/.gitignore", "pyanilist-main/.pre-commit-config.yaml", - "pyanilist-main/mkdocs.yml", "pyanilist-main/poetry.lock", "pyanilist-main/pyproject.toml", ] - members = [ + members: list[str | Path] = [ "pyanilist-main/.gitignore", Path("pyanilist-main/.pre-commit-config.yaml"), - ArchiveMember(name="pyanilist-main/mkdocs.yml"), "pyanilist-main/poetry.lock", "pyanilist-main/pyproject.toml", ] - with ArchiveFile(file) as archive: - folder = archive.extractall(destination=tmp_path, members=members) / "pyanilist-main" # type: ignore - assert len(members) == len(tuple(folder.rglob("*"))) == 5 - assert sorted(expected) == sorted([member.relative_to(tmp_path).as_posix() for member in folder.rglob("*")]) + folder = archive_file.extractall(destination=tmp_path, members=members) / "pyanilist-main" + assert len(members) == len(tuple(folder.rglob("*"))) == 4 + assert sorted(expected) == sorted([member.relative_to(tmp_path).as_posix() for member in folder.rglob("*")]) diff --git a/tests/test_member.py b/tests/test_member.py index 077d46c..b61c14c 100644 --- a/tests/test_member.py +++ b/tests/test_member.py @@ -1,534 +1,59 @@ from __future__ import annotations -from pathlib import Path +from typing import TYPE_CHECKING -import pytest -from archivefile import ArchiveFile +if TYPE_CHECKING: + from archivefile import ArchiveFile -files = ( - Path("tests/test_data/source_BEST.rar"), - Path("tests/test_data/source_BZIP2.7z"), - Path("tests/test_data/source_BZIP2.zip"), - Path("tests/test_data/source_DEFLATE.zip"), - Path("tests/test_data/source_DEFLATE64.zip"), - Path("tests/test_data/source_GNU.tar"), - Path("tests/test_data/source_GNU.tar.bz2"), - Path("tests/test_data/source_GNU.tar.gz"), - Path("tests/test_data/source_GNU.tar.xz"), - Path("tests/test_data/source_LZMA.7z"), - Path("tests/test_data/source_LZMA.zip"), - Path("tests/test_data/source_LZMA2.7z"), - Path("tests/test_data/source_POSIX.tar"), - Path("tests/test_data/source_POSIX.tar.bz2"), - Path("tests/test_data/source_POSIX.tar.gz"), - Path("tests/test_data/source_POSIX.tar.xz"), - Path("tests/test_data/source_PPMD.7z"), - Path("tests/test_data/source_PPMD.zip"), - Path("tests/test_data/source_STORE.7z"), - Path("tests/test_data/source_LZMA_SOLID.7z"), - Path("tests/test_data/source_LZMA2_SOLID.7z"), - Path("tests/test_data/source_PPMD_SOLID.7z"), - Path("tests/test_data/source_BZIP2_SOLID.7z"), - Path("tests/test_data/source_STORE.rar"), - Path("tests/test_data/source_STORE.zip"), -) -# Alias the pre-configured parametrize function for reusability -parametrize_files = pytest.mark.parametrize("file", files, ids=lambda x: x.name) +def test_get_members(archive_file: ArchiveFile) -> None: + assert len(tuple(archive_file.get_members())) == 53 -@parametrize_files -def test_get_members(file: Path) -> None: - with ArchiveFile(file) as archive: - assert len(tuple(archive.get_members())) == 53 - - -@parametrize_files -def test_get_members_without_context_manager(file: Path) -> None: - archive = ArchiveFile(file) - total_members = len(tuple(archive.get_members())) - archive.close() +def test_get_members_without_context_manager(archive_file: ArchiveFile) -> None: + total_members = len(tuple(archive_file.get_members())) assert total_members == 53 -@parametrize_files -def test_get_names(file: Path) -> None: - with ArchiveFile(file) as archive: - assert len(archive.get_names()) == 53 +def test_get_names(archive_file: ArchiveFile) -> None: + assert len(archive_file.get_names()) == 53 -@parametrize_files -def test_get_names_without_context_manager(file: Path) -> None: - archive = ArchiveFile(file) - total_members = len(archive.get_names()) - archive.close() +def test_get_names_without_context_manager(archive_file: ArchiveFile) -> None: + total_members = len(archive_file.get_names()) assert total_members == 53 -@parametrize_files -def test_member_and_names(file: Path) -> None: - with ArchiveFile(file) as archive: - names = tuple([member.name for member in archive.get_members()]) - assert archive.get_names() == names - - -@parametrize_files -def test_members_and_names_without_context_manager(file: Path) -> None: - archive = ArchiveFile(file) - names = tuple([member.name for member in archive.get_members()]) - assert archive.get_names() == names - archive.close() - - -def test_get_member_files() -> None: - with ArchiveFile("tests/test_data/source_BEST.rar") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 1224 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_BZIP2.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_BZIP2.zip") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 1336 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_BZIP2_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_DEFLATE.zip") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 1168 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_DEFLATE64.zip") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 1170 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_GNU.tar") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_GNU.tar.bz2") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_GNU.tar.gz") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_GNU.tar.xz") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_LZMA.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_LZMA.zip") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 1230 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_LZMA2.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_LZMA2_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_LZMA_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_POSIX.tar") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_POSIX.tar.bz2") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_POSIX.tar.gz") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_POSIX.tar.xz") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 5251 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_PPMD.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_PPMD.zip") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 1103 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_PPMD_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_STORE.7z") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_STORE.rar") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - with ArchiveFile("tests/test_data/source_STORE.zip") as archive: - member = archive.get_member("pyanilist-main/README.md") - assert member.name == "pyanilist-main/README.md" - assert member.size == 3799 - assert member.compressed_size == 3799 - assert member.checksum == 398102207 - assert member.is_dir is False - assert member.is_file is True - - -def test_get_member_dirs() -> None: - with ArchiveFile("tests/test_data/source_BEST.rar") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_BZIP2.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_BZIP2.zip") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_BZIP2_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_DEFLATE.zip") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_DEFLATE64.zip") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_GNU.tar") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_GNU.tar.bz2") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_GNU.tar.gz") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_GNU.tar.xz") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_LZMA.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_LZMA.zip") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_LZMA2.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_LZMA2_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_LZMA_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_POSIX.tar") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False - - with ArchiveFile("tests/test_data/source_POSIX.tar.bz2") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False +def test_member_and_names(archive_file: ArchiveFile) -> None: + names = tuple([member.name for member in archive_file.get_members()]) + assert archive_file.get_names() == names - with ArchiveFile("tests/test_data/source_POSIX.tar.gz") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False - with ArchiveFile("tests/test_data/source_POSIX.tar.xz") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 5024 - assert member.is_dir is True - assert member.is_file is False +def test_members_and_names_without_context_manager(archive_file: ArchiveFile) -> None: + names = tuple([member.name for member in archive_file.get_members()]) + assert archive_file.get_names() == names - with ArchiveFile("tests/test_data/source_PPMD.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - with ArchiveFile("tests/test_data/source_PPMD.zip") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False +def test_get_member_files(archive_file: ArchiveFile) -> None: + assert archive_file.file == archive_file.file.resolve() + assert archive_file.password is None - with ArchiveFile("tests/test_data/source_PPMD_SOLID.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False + member = archive_file.get_member("pyanilist-main/README.md") + assert "pyanilist-main/README.md" in archive_file.get_names() + assert member.name == "pyanilist-main/README.md" == str(member) + assert member.size == 3799 + assert member.is_dir is False + assert member.is_file is True - with ArchiveFile("tests/test_data/source_STORE.7z") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False - with ArchiveFile("tests/test_data/source_STORE.rar") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False +def test_get_member_dirs(archive_file: ArchiveFile) -> None: + assert archive_file.file == archive_file.file.resolve() + assert archive_file.password is None - with ArchiveFile("tests/test_data/source_STORE.zip") as archive: - member = archive.get_member("pyanilist-main/docs/") - assert member.name == "pyanilist-main/docs/" - assert member.size == 0 - assert member.compressed_size == 0 - assert member.checksum == 0 - assert member.is_dir is True - assert member.is_file is False + member = archive_file.get_member("pyanilist-main/docs/") + assert "pyanilist-main/docs/" in archive_file.get_names() + assert member.name == "pyanilist-main/docs/" == str(member) + assert member.size == 0 + assert member.compressed_size == 0 + assert member.is_dir is True + assert member.is_file is False diff --git a/tests/test_models.py b/tests/test_models.py deleted file mode 100644 index 9552b44..0000000 --- a/tests/test_models.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import annotations - -from archivefile import ArchiveMember - - -def test__str__() -> None: - assert ArchiveMember(name="src/main/").name == str(ArchiveMember(name="src/main/")) - assert ArchiveMember(name="src/main").name == str(ArchiveMember(name="src/main")) - assert ArchiveMember(name="src/main.py").name == str(ArchiveMember(name="src/main.py")) diff --git a/tests/test_print_table.py b/tests/test_print_table.py deleted file mode 100644 index 9c5af83..0000000 --- a/tests/test_print_table.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from archivefile import ArchiveFile -from pytest import CaptureFixture - -table = """ -| Name | Date modified | Type | Size | Compressed Size | -|---------------------------------------------------|---------------------------|--------|----------|-----------------| -| pyanilist-main | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/.github | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/.github/cliff-template.toml | 2024-04-10T20:10:57+00:00 | File | 4.1KiB | 4.1KiB | -| pyanilist-main/.github/workflows | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/.github/workflows/docs.yml | 2024-04-10T20:10:57+00:00 | File | 1.2KiB | 1.2KiB | -| pyanilist-main/.github/workflows/release.yml | 2024-04-10T20:10:57+00:00 | File | 1.2KiB | 1.2KiB | -| pyanilist-main/.github/workflows/test.yml | 2024-04-10T20:10:57+00:00 | File | 1.9KiB | 1.9KiB | -| pyanilist-main/.gitignore | 2024-04-10T20:10:57+00:00 | File | 3.0KiB | 3.0KiB | -| pyanilist-main/.pre-commit-config.yaml | 2024-04-10T20:10:57+00:00 | File | 366B | 366B | -| pyanilist-main/README.md | 2024-04-10T20:10:57+00:00 | File | 3.7KiB | 3.7KiB | -| pyanilist-main/UNLICENSE | 2024-04-10T20:10:57+00:00 | File | 1.2KiB | 1.2KiB | -| pyanilist-main/docs | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/docs/CNAME | 2024-04-10T20:10:57+00:00 | File | 14B | 14B | -| pyanilist-main/docs/api-reference | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/docs/api-reference/clients.md | 2024-04-10T20:10:57+00:00 | File | 236B | 236B | -| pyanilist-main/docs/api-reference/enums.md | 2024-04-10T20:10:57+00:00 | File | 338B | 338B | -| pyanilist-main/docs/api-reference/exceptions.md | 2024-04-10T20:10:57+00:00 | File | 3.0KiB | 3.0KiB | -| pyanilist-main/docs/api-reference/models.md | 2024-04-10T20:10:57+00:00 | File | 646B | 646B | -| pyanilist-main/docs/api-reference/types.md | 2024-04-10T20:10:57+00:00 | File | 711B | 711B | -| pyanilist-main/docs/assets | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/docs/assets/logo.png | 2024-04-10T20:10:57+00:00 | File | 70.2KiB | 70.2KiB | -| pyanilist-main/docs/assets/logo.svg | 2024-04-10T20:10:57+00:00 | File | 1.7KiB | 1.7KiB | -| pyanilist-main/docs/examples.md | 2024-04-10T20:10:57+00:00 | File | 3.2KiB | 3.2KiB | -| pyanilist-main/docs/index.md | 2024-04-10T20:10:57+00:00 | File | 3.5KiB | 3.5KiB | -| pyanilist-main/mkdocs.yml | 2024-04-10T20:10:57+00:00 | File | 2.1KiB | 2.1KiB | -| pyanilist-main/poetry.lock | 2024-04-10T20:10:57+00:00 | File | 115.6KiB | 115.6KiB | -| pyanilist-main/pyproject.toml | 2024-04-10T20:10:57+00:00 | File | 1.9KiB | 1.9KiB | -| pyanilist-main/src | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/src/pyanilist | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/src/pyanilist/__init__.py | 2024-04-10T20:10:57+00:00 | File | 2.7KiB | 2.7KiB | -| pyanilist-main/src/pyanilist/_clients | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/src/pyanilist/_clients/__init__.py | 2024-04-10T20:10:57+00:00 | File | 99B | 99B | -| pyanilist-main/src/pyanilist/_clients/_async.py | 2024-04-10T20:10:57+00:00 | File | 10.2KiB | 10.2KiB | -| pyanilist-main/src/pyanilist/_clients/_sync.py | 2024-04-10T20:10:57+00:00 | File | 10.0KiB | 10.0KiB | -| pyanilist-main/src/pyanilist/_compat.py | 2024-04-10T20:10:57+00:00 | File | 329B | 329B | -| pyanilist-main/src/pyanilist/_enums.py | 2024-04-10T20:10:57+00:00 | File | 5.7KiB | 5.7KiB | -| pyanilist-main/src/pyanilist/_exceptions.py | 2024-04-10T20:10:57+00:00 | File | 1.4KiB | 1.4KiB | -| pyanilist-main/src/pyanilist/_models.py | 2024-04-10T20:10:57+00:00 | File | 20.3KiB | 20.3KiB | -| pyanilist-main/src/pyanilist/_query.py | 2024-04-10T20:10:57+00:00 | File | 4.8KiB | 4.8KiB | -| pyanilist-main/src/pyanilist/_types.py | 2024-04-10T20:10:57+00:00 | File | 1.5KiB | 1.5KiB | -| pyanilist-main/src/pyanilist/_utils.py | 2024-04-10T20:10:57+00:00 | File | 3.2KiB | 3.2KiB | -| pyanilist-main/src/pyanilist/_version.py | 2024-04-10T20:10:57+00:00 | File | 477B | 477B | -| pyanilist-main/src/pyanilist/py.typed | 2024-04-10T20:10:57+00:00 | File | 0B | 0B | -| pyanilist-main/tests | 2024-04-10T20:10:57+00:00 | Folder | 0B | 0B | -| pyanilist-main/tests/__init__.py | 2024-04-10T20:10:57+00:00 | File | 0B | 0B | -| pyanilist-main/tests/mock_descriptions.py | 2024-04-10T20:10:57+00:00 | File | 21.3KiB | 21.3KiB | -| pyanilist-main/tests/test_anilist.py | 2024-04-10T20:10:57+00:00 | File | 9.2KiB | 9.2KiB | -| pyanilist-main/tests/test_async_anilist.py | 2024-04-10T20:10:57+00:00 | File | 9.3KiB | 9.3KiB | -| pyanilist-main/tests/test_async_exceptions.py | 2024-04-10T20:10:57+00:00 | File | 600B | 600B | -| pyanilist-main/tests/test_enums.py | 2024-04-10T20:10:57+00:00 | File | 867B | 867B | -| pyanilist-main/tests/test_exceptions.py | 2024-04-10T20:10:57+00:00 | File | 554B | 554B | -| pyanilist-main/tests/test_models.py | 2024-04-10T20:10:57+00:00 | File | 306B | 306B | -| pyanilist-main/tests/test_utils.py | 2024-04-10T20:10:57+00:00 | File | 4.1KiB | 4.1KiB | -""" - - -def test_print_table(capsys: CaptureFixture[str]) -> None: - with ArchiveFile("tests/test_data/source_GNU.tar") as archive: - archive.print_table() - assert len(capsys.readouterr().out.strip().splitlines()) == len(table.strip().splitlines()) + 2 - - with ArchiveFile("tests/test_data/source_GNU.tar") as archive: - archive.print_table(title="") - assert len(capsys.readouterr().out.strip().splitlines()) == len(table.strip().splitlines()) diff --git a/tests/test_print_tree.py b/tests/test_print_tree.py deleted file mode 100644 index 18520ee..0000000 --- a/tests/test_print_tree.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -from archivefile import ArchiveFile -from pytest import CaptureFixture - -tree = """ -source_GNU.tar -└── pyanilist-main - ├── .github - │ ├── cliff-template.toml - │ └── workflows - │ ├── docs.yml - │ ├── release.yml - │ └── test.yml - ├── .gitignore - ├── .pre-commit-config.yaml - ├── docs - │ ├── api-reference - │ │ ├── clients.md - │ │ ├── enums.md - │ │ ├── exceptions.md - │ │ ├── models.md - │ │ └── types.md - │ ├── assets - │ │ ├── logo.png - │ │ └── logo.svg - │ ├── CNAME - │ ├── examples.md - │ └── index.md - ├── mkdocs.yml - ├── poetry.lock - ├── pyproject.toml - ├── README.md - ├── src - │ └── pyanilist - │ ├── py.typed - │ ├── _clients - │ │ ├── _async.py - │ │ ├── _sync.py - │ │ └── __init__.py - │ ├── _compat.py - │ ├── _enums.py - │ ├── _exceptions.py - │ ├── _models.py - │ ├── _query.py - │ ├── _types.py - │ ├── _utils.py - │ ├── _version.py - │ └── __init__.py - ├── tests - │ ├── mock_descriptions.py - │ ├── test_anilist.py - │ ├── test_async_anilist.py - │ ├── test_async_exceptions.py - │ ├── test_enums.py - │ ├── test_exceptions.py - │ ├── test_models.py - │ ├── test_utils.py - │ └── __init__.py - └── UNLICENSE -""".strip() - - -def test_print_tree(capsys: CaptureFixture[str]) -> None: - with ArchiveFile("tests/test_data/source_GNU.tar") as archive: - archive.print_tree() - assert capsys.readouterr().out.strip() == tree.strip() diff --git a/tests/test_property.py b/tests/test_property.py deleted file mode 100644 index cc9eb18..0000000 --- a/tests/test_property.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import pytest -from archivefile import ArchiveFile, CompressionType -from archivefile._adapters._rar import RarFileAdapter -from archivefile._adapters._sevenzip import SevenZipFileAdapter -from archivefile._adapters._tar import TarFileAdapter -from archivefile._adapters._zip import ZipFileAdapter - - -@pytest.mark.parametrize( - "file,compression_type,compression_level,adapter", - [ - (Path("tests/test_data/source_GNU.tar"), None, None, "TarFileAdapter"), - (Path("tests/test_data/source_STORE.7z"), None, None, "SevenZipFileAdapter"), - (Path("tests/test_data/source_STORE.rar"), None, None, "RarFileAdapter"), - (Path("tests/test_data/source_STORE.zip"), CompressionType.STORED, None, "ZipFileAdapter"), - ], - ids=lambda x: x.name if isinstance(x, Path) else x, # https://github.com/pytest-dev/pytest/issues/8283 -) -def test_core_properties( - file: Path, compression_type: CompressionType | None, compression_level: int | None, adapter: str -) -> None: - with ArchiveFile(file) as archive: - assert archive.file == file.resolve() - assert archive.mode == "r" - assert archive.password is None - assert archive.compression_type == compression_type - assert archive.compression_level == compression_level - assert archive.adapter == adapter - - -def test_rar_handler_properties() -> None: - file = "tests/test_data/source_STORE.rar" - with RarFileAdapter(file) as archive: - assert archive.file == Path(file).resolve() - assert archive.mode == "r" - assert archive.password is None - assert archive.compression_type is None - assert archive.compression_level is None - assert archive.adapter == "RarFileAdapter" - - -def test_zip_handler_properties() -> None: - file = "tests/test_data/source_STORE.zip" - with ZipFileAdapter(file) as archive: - assert archive.file == Path(file).resolve() - assert archive.mode == "r" - assert archive.password is None - assert archive.compression_type is CompressionType.STORED - assert archive.compression_level is None - assert archive.adapter == "ZipFileAdapter" - - -def test_tar_handler_properties() -> None: - file = "tests/test_data/source_GNU.tar" - with TarFileAdapter(file) as archive: - assert archive.file == Path(file).resolve() - assert archive.mode == "r" - assert archive.password is None - assert archive.compression_type is None - assert archive.compression_level is None - assert archive.adapter == "TarFileAdapter" - - -def test_sevenzip_handler_properties() -> None: - file = "tests/test_data/source_LZMA.7z" - with SevenZipFileAdapter(file) as archive: - assert archive.file == Path(file).resolve() - assert archive.mode == "r" - assert archive.password is None - assert archive.compression_type is None - assert archive.compression_level is None - assert archive.adapter == "SevenZipFileAdapter" diff --git a/tests/test_read.py b/tests/test_read.py index 6982b86..2bf5f01 100644 --- a/tests/test_read.py +++ b/tests/test_read.py @@ -1,37 +1,13 @@ from __future__ import annotations -from pathlib import Path +from typing import TYPE_CHECKING import pytest -from archivefile import ArchiveFile - -files = ( - Path("tests/test_data/source_BEST.rar"), - Path("tests/test_data/source_BZIP2.7z"), - Path("tests/test_data/source_BZIP2.zip"), - Path("tests/test_data/source_DEFLATE.zip"), - # Path("tests/test_data/source_DEFLATE64.zip"), # Deflate64 is not supported by ZipFile - Path("tests/test_data/source_GNU.tar"), - Path("tests/test_data/source_GNU.tar.bz2"), - Path("tests/test_data/source_GNU.tar.gz"), - Path("tests/test_data/source_GNU.tar.xz"), - Path("tests/test_data/source_LZMA.7z"), - Path("tests/test_data/source_LZMA.zip"), - Path("tests/test_data/source_LZMA2.7z"), - Path("tests/test_data/source_POSIX.tar"), - Path("tests/test_data/source_POSIX.tar.bz2"), - Path("tests/test_data/source_POSIX.tar.gz"), - Path("tests/test_data/source_POSIX.tar.xz"), - Path("tests/test_data/source_PPMD.7z"), - # Path("tests/test_data/source_PPMD.zip"), # PPMd is not supported by ZipFile - Path("tests/test_data/source_STORE.7z"), - Path("tests/test_data/source_LZMA_SOLID.7z"), - Path("tests/test_data/source_LZMA2_SOLID.7z"), - Path("tests/test_data/source_PPMD_SOLID.7z"), - Path("tests/test_data/source_BZIP2_SOLID.7z"), - Path("tests/test_data/source_STORE.rar"), - Path("tests/test_data/source_STORE.zip"), -) + +from archivefile import ArchiveMemberNotAFileError + +if TYPE_CHECKING: + from archivefile import ArchiveFile unlicense = """\ This is free and unencumbered software released into the public domain. @@ -60,33 +36,32 @@ For more information, please refer to """ -# Alias the pre-configured parametrize function for reusability -parametrize_files = pytest.mark.parametrize("file", files, ids=lambda x: x.name) + +def test_read_text_file(archive_file: ArchiveFile) -> None: + member = archive_file.read_text("pyanilist-main/UNLICENSE") + assert member.strip() == unlicense.strip() -@parametrize_files -def test_read_text_file(file: Path) -> None: - with ArchiveFile(file) as archive: - member = archive.read_text("pyanilist-main/UNLICENSE") - assert member.strip() == unlicense.strip() +def test_read_bytes_file(archive_file: ArchiveFile) -> None: + member = archive_file.read_bytes("pyanilist-main/UNLICENSE") + assert member.decode().strip() == unlicense.strip() -@parametrize_files -def test_read_bytes_file(file: Path) -> None: - with ArchiveFile(file) as archive: - member = archive.read_bytes("pyanilist-main/UNLICENSE") - assert member.decode().strip() == unlicense.strip() +def test_read_text_folder(archive_file: ArchiveFile) -> None: + filename = archive_file.file.as_posix() + message = rf"Archive member 'pyanilist-main/src/' in file {filename!r} exists but is not a file." + with pytest.raises(ArchiveMemberNotAFileError, match=message) as exc: + archive_file.read_text("pyanilist-main/src/") + assert exc.value.member == "pyanilist-main/src/" + assert exc.value.file == archive_file.file -@parametrize_files -def test_read_text_folder(file: Path) -> None: - with ArchiveFile(file) as archive: - member = archive.read_text("pyanilist-main/src/") - assert member == "" +def test_read_bytes_folder(archive_file: ArchiveFile) -> None: + filename = archive_file.file.as_posix() + message = rf"Archive member 'pyanilist-main/src/' in file {filename!r} exists but is not a file." + with pytest.raises(ArchiveMemberNotAFileError, match=message) as exc: + archive_file.read_bytes("pyanilist-main/src/") -@parametrize_files -def test_read_bytes_folder(file: Path) -> None: - with ArchiveFile(file) as archive: - member = archive.read_bytes("pyanilist-main/src/") - assert member == b"" + assert exc.value.member == "pyanilist-main/src/" + assert exc.value.file == archive_file.file diff --git a/tests/test_utils.py b/tests/test_utils.py index ac10fc4..7fd8c8a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,36 +1,9 @@ from __future__ import annotations -import pytest -from archivefile._utils import clamp_compression_level, is_archive +from archivefile import is_archive def test_is_archive() -> None: - assert is_archive("tests/test_data/source_BEST.rar") is True - assert is_archive("tests/test_data/source_PPMD.zip") is True + assert is_archive("tests/test_data/source_LZMA.zip") is True assert is_archive("src/archivefile/__init__.py") is False assert is_archive("non-existent-file.py") is False - - -@pytest.mark.parametrize( - "level,expected", - [ - (-1212, 0), - (-5, 0), - (-1, 0), - (0, 0), - (1, 1), - (2, 2), - (3, 3), - (4, 4), - (5, 5), - (6, 6), - (7, 7), - (8, 8), - (9, 9), - (10, 9), - (11, 9), - (1123, 9), - ], -) -def test_clamp_compression_level(level: int, expected: int) -> None: - assert clamp_compression_level(level) == expected diff --git a/tests/test_write.py b/tests/test_write.py deleted file mode 100644 index 7956bfc..0000000 --- a/tests/test_write.py +++ /dev/null @@ -1,158 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from uuid import uuid4 - -import pytest -from archivefile import ArchiveFile, CompressionType - -modes = ( - "w", - "w:", - "w:gz", - "w:bz2", - "w:xz", - "x:", - "x:", - "x:gz", - "x:bz2", - "x:xz", - "a", - "a:", -) - -extensions = ("zip", "cbz") + ("tar", "tar.bz2", "tar.gz", "tar.xz", "cbt") + ("7z", "cb7") - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_str(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = "Hello World" - file.write_text(text) - - with ArchiveFile(archive_file, mode=mode) as archive: - archive.write(file) - - with ArchiveFile(archive_file) as archive: - assert archive.read_text(file.name).strip() == text - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_str_with_compression(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = "Hello World" - file.write_text(text) - - with ArchiveFile(archive_file, mode=mode, compression_level=0, compression_type=CompressionType.BZIP2) as archive: - archive.write(file) - - with ArchiveFile(archive_file) as archive: - assert archive.read_text(file.name).strip() == text - - -@pytest.mark.parametrize("extension", ("zip", "cbz")) -@pytest.mark.parametrize("mode", modes) -def test_write_str_with_bzip2_compression(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = "Hello World" - file.write_text(text) - - with ArchiveFile(archive_file, mode=mode, compression_level=0, compression_type=CompressionType.BZIP2) as archive: - assert archive.compression_level == 1 - archive.write(file) - - with ArchiveFile(archive_file) as archive: - assert archive.read_text(file.name).strip() == text - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_zip_bytes(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = b"Hello World" - file.write_bytes(text) - - with ArchiveFile(archive_file, mode=mode) as archive: - archive.write(file) - - with ArchiveFile(archive_file) as archive: - assert archive.read_bytes(file.name) == text - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_bytes_with_compression(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = b"Hello World" - file.write_bytes(text) - - with ArchiveFile( - archive_file, mode=mode, compression_level=1, compression_type=CompressionType.DEFLATED - ) as archive: - archive.write(file) - - with ArchiveFile(archive_file) as archive: - assert archive.read_bytes(file.name) == text - - -@pytest.mark.parametrize("extension", ("zip", "cbz")) -@pytest.mark.parametrize("mode", modes) -def test_write_bytes_with_bzip2_compression(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = b"Hello World" - file.write_bytes(text) - - with ArchiveFile( - archive_file, mode=mode, compression_level=0, compression_type=CompressionType.DEFLATED - ) as archive: - assert archive.compression_level == 0 - archive.write(file) - - with ArchiveFile(archive_file) as archive: - assert archive.read_bytes(file.name) == text - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_str_by_arcname(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = "Hello World" - file.write_text(text) - - with ArchiveFile(archive_file, mode=mode) as archive: - archive.write(file, arcname=file.resolve()) - - with ArchiveFile(archive_file) as archive: - assert archive.read_text(file.resolve()).strip() == text - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_zip_bytes_by_arcname(tmp_path: Path, mode: str, extension: str) -> None: - archive_file = tmp_path / f"{uuid4()}.{extension}" - file = tmp_path / "README.md" - file.touch() - text = b"Hello World" - file.write_bytes(text) - - with ArchiveFile(archive_file, mode=mode) as archive: - archive.write(file, arcname=file.resolve()) - - with ArchiveFile(archive_file) as archive: - assert archive.read_bytes(file.resolve()).strip() == text diff --git a/tests/test_write_text_bytes.py b/tests/test_write_text_bytes.py deleted file mode 100644 index c0c2e87..0000000 --- a/tests/test_write_text_bytes.py +++ /dev/null @@ -1,49 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from uuid import uuid4 - -import pytest -from archivefile import ArchiveFile - -modes = ( - "w", - "w:", - "w:gz", - "w:bz2", - "w:xz", - "x:", - "x:", - "x:gz", - "x:bz2", - "x:xz", - "a", - "a:", -) - -extensions = ("tar", "tar.bz2", "tar.gz", "tar.xz", "cbt") + ("7z", "cb7") + ("zip", "cbz") - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_text(tmp_path: Path, mode: str, extension: str) -> None: - dir = tmp_path / f"{uuid4()}.{extension}" - data = "Hello World" - with ArchiveFile(dir, mode) as archive: - print(archive) - archive.write_text(data, arcname="test.txt") - - with ArchiveFile(dir, "r") as archive: - assert archive.read_text("test.txt") == data - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_write_bytes(tmp_path: Path, mode: str, extension: str) -> None: - dir = tmp_path / f"{uuid4()}.{extension}" - data = b"Hello World" - with ArchiveFile(dir, mode) as archive: - archive.write_bytes(data, arcname=Path("test.dat")) - - with ArchiveFile(dir, "r") as archive: - assert archive.read_bytes("test.dat") == data diff --git a/tests/test_writeall.py b/tests/test_writeall.py deleted file mode 100644 index 96b1270..0000000 --- a/tests/test_writeall.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from uuid import uuid4 - -import pytest -from archivefile import ArchiveFile - -modes = ( - "w", - "w:", - "w:gz", - "w:bz2", - "w:xz", - "x:", - "x:", - "x:gz", - "x:bz2", - "x:xz", - "a", - "a:", -) - -extensions = ("zip", "cbz") + ("tar", "tar.bz2", "tar.gz", "tar.xz", "cbt") + ("7z", "cb7") - - -ARCHIVE_DIR = Path("src/archivefile").resolve() - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_writeall(tmp_path: Path, mode: str, extension: str) -> None: - dir = tmp_path / f"{uuid4()}.{extension}" - with ArchiveFile(dir, mode) as archive: - archive.writeall(ARCHIVE_DIR, glob="*.py") - - with ArchiveFile(dir, "r") as archive: - dest = tmp_path / str(uuid4()) - dest.mkdir(parents=True, exist_ok=True) - archive.extractall(destination=dest) - - assert len(tuple(ARCHIVE_DIR.rglob("*.py"))) == len(tuple(dest.rglob("*.*"))) - - -@pytest.mark.parametrize("extension", extensions) -@pytest.mark.parametrize("mode", modes) -def test_writeall_with_root(tmp_path: Path, mode: str, extension: str) -> None: - dir = tmp_path / f"{uuid4()}.{extension}" - with ArchiveFile(dir, mode) as archive: - archive.writeall(ARCHIVE_DIR, glob="*.py", root=ARCHIVE_DIR.parent.parent) - - with ArchiveFile(dir, "r") as archive: - dest = tmp_path / str(uuid4()) - dest.mkdir(parents=True, exist_ok=True) - archive.extractall(destination=dest) - - assert len(tuple(ARCHIVE_DIR.rglob("*.py"))) == len(tuple(dest.rglob("*.*"))) diff --git a/uv.lock b/uv.lock index a53099e..531b02b 100644 --- a/uv.lock +++ b/uv.lock @@ -1,41 +1,22 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.13'", "python_full_version < '3.13'", ] -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - [[package]] name = "archivefile" version = "1.0.0" source = { editable = "." } -dependencies = [ - { name = "py7zr" }, - { name = "pydantic" }, - { name = "rarfile" }, - { name = "typing-extensions" }, -] [package.optional-dependencies] -all = [ - { name = "bigtree" }, - { name = "rich" }, -] -bigtree = [ - { name = "bigtree" }, +7z = [ + { name = "py7zr" }, ] -rich = [ - { name = "rich" }, +rar = [ + { name = "rarfile" }, ] [package.dev-dependencies] @@ -47,6 +28,7 @@ dev = [ { name = "mypy" }, { name = "pytest" }, { name = "ruff" }, + { name = "typing-extensions" }, ] docs = [ { name = "mkdocs-autorefs" }, @@ -58,6 +40,7 @@ lint = [ { name = "mypy" }, { name = "pytest" }, { name = "ruff" }, + { name = "typing-extensions" }, ] test = [ { name = "coverage", extra = ["toml"] }, @@ -66,16 +49,10 @@ test = [ [package.metadata] requires-dist = [ - { name = "bigtree", marker = "extra == 'all'", specifier = ">=0.19.3" }, - { name = "bigtree", marker = "extra == 'bigtree'", specifier = ">=0.19.3" }, - { name = "py7zr", specifier = ">=0.21.1" }, - { name = "pydantic", specifier = ">=2.8.2" }, - { name = "rarfile", specifier = ">=4.2" }, - { name = "rich", marker = "extra == 'all'", specifier = ">=13.7.1" }, - { name = "rich", marker = "extra == 'rich'", specifier = ">=13.7.1" }, - { name = "typing-extensions", specifier = ">=4.12.2" }, + { name = "py7zr", marker = "extra == '7z'", specifier = ">=1.0.0" }, + { name = "rarfile", marker = "extra == 'rar'", specifier = ">=4.2" }, ] -provides-extras = ["bigtree", "rich", "all"] +provides-extras = ["rar", "7z"] [package.metadata.requires-dev] dev = [ @@ -86,6 +63,7 @@ dev = [ { name = "mypy", specifier = ">=1.16.0" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "ruff", specifier = ">=0.11.12" }, + { name = "typing-extensions", specifier = ">=4.12.2" }, ] docs = [ { name = "mkdocs-autorefs", specifier = ">=1.3.0" }, @@ -97,6 +75,7 @@ lint = [ { name = "mypy", specifier = ">=1.16.0" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "ruff", specifier = ">=0.11.12" }, + { name = "typing-extensions", specifier = ">=4.12.2" }, ] test = [ { name = "coverage", extras = ["toml"], specifier = ">=7.6.10" }, @@ -125,15 +104,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/37/fb6973edeb700f6e3d6ff222400602ab1830446c25c7b4676d8de93e65b8/backrefs-5.8-py39-none-any.whl", hash = "sha256:a66851e4533fb5b371aa0628e1fee1af05135616b86140c9d787a2ffdf4b8fdc", size = 380336, upload-time = "2025-02-25T16:53:29.858Z" }, ] -[[package]] -name = "bigtree" -version = "0.19.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b9/9c/5ac16d8009b75156a185ed201ec4232222f23a9a3a77e2097d93bb0eb027/bigtree-0.19.4.tar.gz", hash = "sha256:09634a48477514eb5fd39620b8e9ce0fd08c9a280b69333ecef2d70b9e4ef6e6", size = 1237816, upload-time = "2024-08-15T15:31:53.273Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/00/4e3cc105f88c78169ef15f9c5be15e0a2bf908803809ff8b56b3bc2b33d8/bigtree-0.19.4-py3-none-any.whl", hash = "sha256:2652266ced7749d675f5541904cb97a19b48f6fa3254f437d14f21ce36416a27", size = 76883, upload-time = "2024-08-15T15:31:51.663Z" }, -] - [[package]] name = "brotli" version = "1.1.0" @@ -237,59 +207,59 @@ wheels = [ [[package]] name = "cffi" -version = "1.17.0" +version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/bf/82c351342972702867359cfeba5693927efe0a8dd568165490144f554b18/cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", size = 516073, upload-time = "2024-08-06T17:48:39.225Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/2a/9071bf1e20bf9f695643b6c3e0f838f340b95ee29de0d1bb7968772409be/cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", size = 181841, upload-time = "2024-08-06T17:46:22.035Z" }, - { url = "https://files.pythonhosted.org/packages/4b/42/60116f10466d692b64aef32ac40fd79b11344ab6ef889ff8e3d047f2fcb2/cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", size = 178242, upload-time = "2024-08-06T17:46:24.879Z" }, - { url = "https://files.pythonhosted.org/packages/26/8e/a53f844454595c6e9215e56cda123db3427f8592f2c7b5ef1be782f620d6/cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", size = 425676, upload-time = "2024-08-06T17:46:26.692Z" }, - { url = "https://files.pythonhosted.org/packages/60/ac/6402563fb40b64c7ccbea87836d9c9498b374629af3449f3d8ff34df187d/cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", size = 447842, upload-time = "2024-08-06T17:46:28.406Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e7/e2ffdb8de59f48f17b196813e9c717fbed2364e39b10bdb3836504e89486/cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", size = 455224, upload-time = "2024-08-06T17:46:30.166Z" }, - { url = "https://files.pythonhosted.org/packages/59/55/3e8968e92fe35c1c368959a070a1276c10cae29cdad0fd0daa36c69e237e/cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", size = 436341, upload-time = "2024-08-06T17:46:32.327Z" }, - { url = "https://files.pythonhosted.org/packages/7f/df/700aaf009dfbfa04acb1ed487586c03c788c6a312f0361ad5f298c5f5a7d/cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", size = 445861, upload-time = "2024-08-06T17:46:34.407Z" }, - { url = "https://files.pythonhosted.org/packages/5a/70/637f070aae533ea11ab77708a820f3935c0edb4fbcef9393b788e6f426a5/cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", size = 460982, upload-time = "2024-08-06T17:46:36.391Z" }, - { url = "https://files.pythonhosted.org/packages/f7/1a/7d4740fa1ccc4fcc888963fc3165d69ef1a2c8d42c8911c946703ff5d4a5/cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", size = 438434, upload-time = "2024-08-06T17:46:38.325Z" }, - { url = "https://files.pythonhosted.org/packages/d0/d9/c48cc38aaf6f53a8b5d2dbf6fe788410fcbab33b15a69c56c01d2b08f6a2/cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", size = 461219, upload-time = "2024-08-06T17:46:40.084Z" }, - { url = "https://files.pythonhosted.org/packages/26/ec/b6a7f660a7f27bd2bb53fe99a2ccafa279088395ec8639b25b8950985b2d/cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", size = 171406, upload-time = "2024-08-06T17:46:41.925Z" }, - { url = "https://files.pythonhosted.org/packages/08/42/8c00824787e6f5ec55194f5cd30c4ba4b9d9d5bb0d4d0007b1bb948d4ad4/cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", size = 180809, upload-time = "2024-08-06T17:46:43.533Z" }, - { url = "https://files.pythonhosted.org/packages/53/cc/9298fb6235522e00e47d78d6aa7f395332ef4e5f6fe124f9a03aa60600f7/cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", size = 181912, upload-time = "2024-08-06T17:46:45.92Z" }, - { url = "https://files.pythonhosted.org/packages/e7/79/dc5334fbe60635d0846c56597a8d2af078a543ff22bc48d36551a0de62c2/cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", size = 178297, upload-time = "2024-08-06T17:46:48.122Z" }, - { url = "https://files.pythonhosted.org/packages/39/d7/ef1b6b16b51ccbabaced90ff0d821c6c23567fc4b2e4a445aea25d3ceb92/cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", size = 444909, upload-time = "2024-08-06T17:46:50.252Z" }, - { url = "https://files.pythonhosted.org/packages/29/b8/6e3c61885537d985c78ef7dd779b68109ba256263d74a2f615c40f44548d/cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", size = 468854, upload-time = "2024-08-06T17:46:59.483Z" }, - { url = "https://files.pythonhosted.org/packages/0b/49/adad1228e19b931e523c2731e6984717d5f9e33a2f9971794ab42815b29b/cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", size = 476890, upload-time = "2024-08-06T17:47:01.739Z" }, - { url = "https://files.pythonhosted.org/packages/76/54/c00f075c3e7fd14d9011713bcdb5b4f105ad044c5ad948db7b1a0a7e4e78/cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", size = 459374, upload-time = "2024-08-06T17:47:04.267Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b9/f163bb3fa4fbc636ee1f2a6a4598c096cdef279823ddfaa5734e556dd206/cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", size = 466891, upload-time = "2024-08-06T17:47:06.826Z" }, - { url = "https://files.pythonhosted.org/packages/31/52/72bbc95f6d06ff2e88a6fa13786be4043e542cb24748e1351aba864cb0a7/cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91", size = 477658, upload-time = "2024-08-06T17:47:08.616Z" }, - { url = "https://files.pythonhosted.org/packages/67/20/d694811457eeae0c7663fa1a7ca201ce495533b646c1180d4ac25684c69c/cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", size = 453890, upload-time = "2024-08-06T17:47:10.496Z" }, - { url = "https://files.pythonhosted.org/packages/dc/79/40cbf5739eb4f694833db5a27ce7f63e30a9b25b4a836c4f25fb7272aacc/cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", size = 478254, upload-time = "2024-08-06T17:47:12.263Z" }, - { url = "https://files.pythonhosted.org/packages/e9/eb/2c384c385cca5cae67ca10ac4ef685277680b8c552b99aedecf4ea23ff7e/cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", size = 171285, upload-time = "2024-08-06T17:47:14.209Z" }, - { url = "https://files.pythonhosted.org/packages/ca/42/74cb1e0f1b79cb64672f3cb46245b506239c1297a20c0d9c3aeb3929cb0c/cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", size = 180842, upload-time = "2024-08-06T17:47:16.151Z" }, - { url = "https://files.pythonhosted.org/packages/1a/1f/7862231350cc959a3138889d2c8d33da7042b22e923457dfd4cd487d772a/cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", size = 182826, upload-time = "2024-08-06T17:47:18.638Z" }, - { url = "https://files.pythonhosted.org/packages/8b/8c/26119bf8b79e05a1c39812064e1ee7981e1f8a5372205ba5698ea4dd958d/cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", size = 178494, upload-time = "2024-08-06T17:47:20.216Z" }, - { url = "https://files.pythonhosted.org/packages/61/94/4882c47d3ad396d91f0eda6ef16d45be3d752a332663b7361933039ed66a/cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", size = 454459, upload-time = "2024-08-06T17:47:22.792Z" }, - { url = "https://files.pythonhosted.org/packages/0f/7c/a6beb119ad515058c5ee1829742d96b25b2b9204ff920746f6e13bf574eb/cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", size = 478502, upload-time = "2024-08-06T17:47:25.138Z" }, - { url = "https://files.pythonhosted.org/packages/61/8a/2575cd01a90e1eca96a30aec4b1ac101a6fae06c49d490ac2704fa9bc8ba/cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", size = 485381, upload-time = "2024-08-06T17:47:26.888Z" }, - { url = "https://files.pythonhosted.org/packages/cd/66/85899f5a9f152db49646e0c77427173e1b77a1046de0191ab3b0b9a5e6e3/cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", size = 470907, upload-time = "2024-08-06T17:47:28.877Z" }, - { url = "https://files.pythonhosted.org/packages/00/13/150924609bf377140abe6e934ce0a57f3fc48f1fd956ec1f578ce97a4624/cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", size = 479074, upload-time = "2024-08-06T17:47:30.826Z" }, - { url = "https://files.pythonhosted.org/packages/17/fd/7d73d7110155c036303b0a6462c56250e9bc2f4119d7591d27417329b4d1/cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", size = 484225, upload-time = "2024-08-06T17:47:32.965Z" }, - { url = "https://files.pythonhosted.org/packages/fc/83/8353e5c9b01bb46332dac3dfb18e6c597a04ceb085c19c814c2f78a8c0d0/cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", size = 488388, upload-time = "2024-08-06T17:47:34.811Z" }, - { url = "https://files.pythonhosted.org/packages/73/0c/f9d5ca9a095b1fc88ef77d1f8b85d11151c374144e4606da33874e17b65b/cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", size = 172096, upload-time = "2024-08-06T17:47:36.618Z" }, - { url = "https://files.pythonhosted.org/packages/72/21/8c5d285fe20a6e31d29325f1287bb0e55f7d93630a5a44cafdafb5922495/cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", size = 181478, upload-time = "2024-08-06T17:47:38.321Z" }, - { url = "https://files.pythonhosted.org/packages/17/8f/581f2f3c3464d5f7cf87c2f7a5ba9acc6976253e02d73804240964243ec2/cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", size = 182638, upload-time = "2024-08-06T17:47:39.858Z" }, - { url = "https://files.pythonhosted.org/packages/8d/1c/c9afa66684b7039f48018eb11b229b659dfb32b7a16b88251bac106dd1ff/cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", size = 178453, upload-time = "2024-08-06T17:47:41.813Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/1a134d479d3a5a1ff2fabbee551d1d3f1dd70f453e081b5f70d604aae4c0/cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", size = 454441, upload-time = "2024-08-06T17:47:43.735Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b4/e1569475d63aad8042b0935dbf62ae2a54d1e9142424e2b0e924d2d4a529/cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", size = 478543, upload-time = "2024-08-06T17:47:45.641Z" }, - { url = "https://files.pythonhosted.org/packages/d2/40/a9ad03fbd64309dec5bb70bc803a9a6772602de0ee164d7b9a6ca5a89249/cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", size = 485463, upload-time = "2024-08-06T17:47:47.45Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1a/f10be60e006dd9242a24bcc2b1cd55c34c578380100f742d8c610f7a5d26/cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", size = 470854, upload-time = "2024-08-06T17:47:49.179Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/c035ed21aa3d39432bd749fe331ee90e4bc83ea2dbed1f71c4bc26c41084/cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", size = 479096, upload-time = "2024-08-06T17:47:51.596Z" }, - { url = "https://files.pythonhosted.org/packages/00/cb/6f7edde01131de9382c89430b8e253b8c8754d66b63a62059663ceafeab2/cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", size = 484013, upload-time = "2024-08-06T17:47:53.888Z" }, - { url = "https://files.pythonhosted.org/packages/b9/83/8e4e8c211ea940210d293e951bf06b1bfb90f2eeee590e9778e99b4a8676/cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", size = 488119, upload-time = "2024-08-06T17:47:55.618Z" }, - { url = "https://files.pythonhosted.org/packages/5e/52/3f7cfbc4f444cb4f73ff17b28690d12436dde665f67d68f1e1687908ab6c/cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", size = 172122, upload-time = "2024-08-06T17:47:57.316Z" }, - { url = "https://files.pythonhosted.org/packages/94/19/cf5baa07ee0f0e55eab7382459fbddaba0fdb0ba45973dd92556ae0d02db/cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", size = 181504, upload-time = "2024-08-06T17:47:59.05Z" }, + { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191, upload-time = "2024-09-04T20:43:30.027Z" }, + { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592, upload-time = "2024-09-04T20:43:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, + { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, + { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, + { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, + { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, + { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804, upload-time = "2024-09-04T20:43:48.186Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299, upload-time = "2024-09-04T20:43:49.812Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, + { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, ] [[package]] @@ -480,38 +450,50 @@ wheels = [ [[package]] name = "inflate64" -version = "1.0.0" +version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/99/18f9940d4a3f2cabc4396a587ddf1bd93236bdb372d9e78e2b0365e40990/inflate64-1.0.0.tar.gz", hash = "sha256:3278827b803cf006a1df251f3e13374c7d26db779e5a33329cc11789b804bc2d", size = 895853, upload-time = "2023-11-05T09:06:04.917Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/a7/974e6daa6c353cf080b540c18f11840e81b36d18106963a0a857b1fc2adf/inflate64-1.0.3.tar.gz", hash = "sha256:a89edd416c36eda0c3a5d32f31ff1555db2c5a3884aa8df95e8679f8203e12ee", size = 902876, upload-time = "2025-06-01T04:43:20.35Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/cf/06af80e81dd4bbb7e883291cf1726035d526f066a37c4ed4d4cd88a7a49d/inflate64-1.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a90c0bdf4a7ecddd8a64cc977181810036e35807f56b0bcacee9abb0fcfd18dc", size = 59418, upload-time = "2023-11-05T09:04:26.354Z" }, - { url = "https://files.pythonhosted.org/packages/c9/4b/6f18918220b1a8e935121cece1dc917e62fa593fc637a621470f9b9a601a/inflate64-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:57fe7c14aebf1c5a74fc3b70d355be1280a011521a76aa3895486e62454f4242", size = 36231, upload-time = "2023-11-05T09:04:28.504Z" }, - { url = "https://files.pythonhosted.org/packages/aa/f4/f4b5dbd78dd5af66b6ca32778ebaa9c14d67b68ea84e96592ccf40786a41/inflate64-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d90730165f471d61a1a694a5e354f3ffa938227e8dcecb62d5d728e8069cee94", size = 35738, upload-time = "2023-11-05T09:04:30.182Z" }, - { url = "https://files.pythonhosted.org/packages/10/23/26289a700550767cf5eb7550f78ad826529706287393f224bbaee3c1b1e2/inflate64-1.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:543f400201f5c101141af3c79c82059e1aa6ef4f1584a7f1fa035fb2e465097f", size = 92855, upload-time = "2023-11-05T09:04:32.402Z" }, - { url = "https://files.pythonhosted.org/packages/b8/f4/e387a50f5027194eac4f9712d57b97e3e1a012402eaae98bcf1ebe8a97d1/inflate64-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ceca14f7ec19fb44b047f56c50efb7521b389d222bba2b0a10286a0caeb03fa", size = 93141, upload-time = "2023-11-05T09:04:34.886Z" }, - { url = "https://files.pythonhosted.org/packages/33/c8/e516aecd9ed0dc75d8df041ed4ef80f2e2be39d0e516c7269b7f274e760a/inflate64-1.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b559937a42f0c175b4d2dfc7eb53b97bdc87efa9add15ed5549c6abc1e89d02f", size = 95262, upload-time = "2023-11-05T09:04:36.987Z" }, - { url = "https://files.pythonhosted.org/packages/0b/aa/ed3ab5f8c13afc432fb382edf97cede7a6f9be73ecf98bfe64b686c8d223/inflate64-1.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5ff8bd2a562343fcbc4eea26fdc368904a3b5f6bb8262344274d3d74a1de15bb", size = 95912, upload-time = "2023-11-05T09:04:39.401Z" }, - { url = "https://files.pythonhosted.org/packages/e0/64/5637c4f67ed15518c0765b85b528ed79536caaf8ba167a9f7173e334d4a8/inflate64-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:0fe481f31695d35a433c3044ac8fd5d9f5069aaad03a0c04b570eb258ce655aa", size = 35166, upload-time = "2023-11-05T09:04:41.819Z" }, - { url = "https://files.pythonhosted.org/packages/af/92/701b3c76b1cf244026c3e78dff8487955cf6960c1d9f350e2820a0d1a5d9/inflate64-1.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a45f6979ad5874d4d4898c2fc770b136e61b96b850118fdaec5a5af1b9123a", size = 59450, upload-time = "2023-11-05T09:04:43.941Z" }, - { url = "https://files.pythonhosted.org/packages/bb/1d/af0253fafc27cadd29e3b111ebb3011b8c913a3554b403c90c7595f5933e/inflate64-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:022ca1cc928e7365a05f7371ff06af143c6c667144965e2cf9a9236a2ae1c291", size = 36267, upload-time = "2023-11-05T09:04:45.497Z" }, - { url = "https://files.pythonhosted.org/packages/b6/22/7949030be11f4754bd6ed7067e9bebdf614013b89ccd4638330a85821b51/inflate64-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46792ecf3565d64fd2c519b0a780c03a57e195613c9954ef94e739a057b3fd06", size = 35740, upload-time = "2023-11-05T09:04:46.983Z" }, - { url = "https://files.pythonhosted.org/packages/e4/87/c6ce0093a345c04811f6171a367665dec17dcc4617ca150dd37e9ae7bd33/inflate64-1.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a70ea2e456c15f7aa7c74b8ab8f20b4f8940ec657604c9f0a9de3342f280fff", size = 95896, upload-time = "2023-11-05T09:04:48.913Z" }, - { url = "https://files.pythonhosted.org/packages/62/d6/fe113b12773cad2c093d381c2b1629f9cfa240c9ad86a7f9f9079e7a51b5/inflate64-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e243ea9bd36a035059f2365bd6d156ff59717fbafb0255cb0c75bf151bf6904", size = 96007, upload-time = "2023-11-05T09:04:50.688Z" }, - { url = "https://files.pythonhosted.org/packages/f0/a6/9165bee4b7fc5af949fec12a2cea7ad73bf9ee97dfb96a0276274c48e709/inflate64-1.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4dc392dec1cd11cacda3d2637214ca45e38202e8a4f31d4a4e566d6e90625fc4", size = 98297, upload-time = "2023-11-05T09:04:52.516Z" }, - { url = "https://files.pythonhosted.org/packages/ee/72/0aeb360101eeed32696fc6c623bc1780fac895a9fc2e93b582cb1e22ca54/inflate64-1.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8b402a50eda7ee75f342fc346d33a41bca58edc222a4b17f9be0db1daed459fa", size = 98858, upload-time = "2023-11-05T09:04:54.786Z" }, - { url = "https://files.pythonhosted.org/packages/94/4a/8301ad59b57d9de504b0fdce22bf980dfb231753e6d7aed12af938f7f9fd/inflate64-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f5924499dc8800928c0ee4580fa8eb4ffa880b2cce4431537d0390e503a9c9ee", size = 35167, upload-time = "2023-11-05T09:04:56.885Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/47021b8919c1dc276d0502296f15ffac1cd648b94b35cadb14cb812b6199/inflate64-1.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0c644bf7208e20825ca3bbb5fb1f7f495cfcb49eb01a5f67338796d44a42f2bf", size = 59509, upload-time = "2023-11-05T09:04:58.521Z" }, - { url = "https://files.pythonhosted.org/packages/e0/c9/00701be8e48dc9c9b9488001d9c66d6cb6f6bb0c48af9abf33a69726d130/inflate64-1.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9964a4eaf26a9d36f82a1d9b12c28e35800dd3d99eb340453ed12ac90c2976a8", size = 36305, upload-time = "2023-11-05T09:05:00.337Z" }, - { url = "https://files.pythonhosted.org/packages/25/c0/11dea5e298b2e7d61f0fbd1005553e8796e35536751980b676547fcc57ef/inflate64-1.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2cccded63865640d03253897be7232b2bbac295fe43914c61f86a57aa23bb61d", size = 35756, upload-time = "2023-11-05T09:05:02.596Z" }, - { url = "https://files.pythonhosted.org/packages/86/ba/4debdaaafdc21853621caf463a498a754ee4352893454c596dbd65294e9f/inflate64-1.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d491f104fb3701926ebd82b8c9250dfba0ddcab584504e26f1e4adb26730378d", size = 96127, upload-time = "2023-11-05T09:05:04.575Z" }, - { url = "https://files.pythonhosted.org/packages/89/81/8f559c199ec13d0b70d0dc46811490b2976873c96c564941583777e9b343/inflate64-1.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ebad4a6cd2a2c1d81be0b09d4006479f3b258803c49a9224ef8ca0b649072fa", size = 96903, upload-time = "2023-11-05T09:05:06.361Z" }, - { url = "https://files.pythonhosted.org/packages/46/41/39ac4c7e17d0690578b716a0ff34e00600616994795b0645fd61fc600c0f/inflate64-1.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6823b2c0cff3a8159140f3b17ec64fb8ec0e663b45a6593618ecdde8aeecb5b2", size = 98855, upload-time = "2023-11-05T09:05:08.895Z" }, - { url = "https://files.pythonhosted.org/packages/44/dd/be5d69492c180f94a6af8a15564ce365bdcb84bd1a6fb32949d6913959aa/inflate64-1.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:228d504239d27958e71fc77e3119a6ac4528127df38468a0c95a5bd3927204b8", size = 99884, upload-time = "2023-11-05T09:05:10.695Z" }, - { url = "https://files.pythonhosted.org/packages/8c/0d/a5266bd4f2cdb7fad1eae3ffe4dcc16f9769323660a0a6cfbe9cc1d2cf03/inflate64-1.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae2572e06bcfe15e3bbf77d4e4a6d6c55e2a70d6abceaaf60c5c3653ddb96dfd", size = 35334, upload-time = "2023-11-05T09:05:12.162Z" }, - { url = "https://files.pythonhosted.org/packages/53/91/43238dd8a7e5bab71abae872c09931db4b31aebf672afccb305f79aacb3e/inflate64-1.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f79542478e49e471e8b23556700e6f688a40dc93e9a746f77a546c13251b59b1", size = 34648, upload-time = "2023-11-05T09:05:42.207Z" }, - { url = "https://files.pythonhosted.org/packages/ef/6f/ce090934a80c1fd0b5b07c125ed6eb2845f11a78af344d69c0f051dcab97/inflate64-1.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a270be6b10cde01258c0097a663a307c62d12c78eb8f62f8e29f205335942c9", size = 36473, upload-time = "2023-11-05T09:05:43.548Z" }, - { url = "https://files.pythonhosted.org/packages/b4/fe/2cd4bf78696213b807860002c182dd1751ba52c1559143b1b8daa7904733/inflate64-1.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1616a87ff04f583e9558cc247ec0b72a30d540ee0c17cc77823be175c0ec92f0", size = 36478, upload-time = "2023-11-05T09:05:44.917Z" }, - { url = "https://files.pythonhosted.org/packages/43/dd/e62444c0ef7d1228b622e6d3dacf9ea237d8807a78619a83832a3b4a5adf/inflate64-1.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:137ca6b315f0157a786c3a755a09395ca69aed8bcf42ad3437cb349f5ebc86d2", size = 35630, upload-time = "2023-11-05T09:05:46.988Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7b/bf2950b18ddb087085767f8e9da0102115591ff61e50ff47baedb91994a0/inflate64-1.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:35abad47221ac8cb4cf6a9ef784916ada3f95115bd4f09e0f5f146b4463dcc93", size = 58607, upload-time = "2025-06-01T04:42:05.23Z" }, + { url = "https://files.pythonhosted.org/packages/94/1f/97d91ce622b13d7b80e68104ac4b454eba4f96e18bec90d6e8c93874d647/inflate64-1.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:518af99243b6cb4834c52c35b2965f38cc97aacbeb63d3e9cf820a9533957d37", size = 35942, upload-time = "2025-06-01T04:42:07.277Z" }, + { url = "https://files.pythonhosted.org/packages/d9/29/68c45e25848ebc6cc75f846e782b5fb4fd3a03ac5101fe1d4c0c7e3d7d95/inflate64-1.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dad8527cb556fa3fb96dcf1631ea7c295bdc31ff05f2fb54363f6878c4eca9fa", size = 35938, upload-time = "2025-06-01T04:42:09.031Z" }, + { url = "https://files.pythonhosted.org/packages/7f/55/e60519847063cc7115b1a8988ee62d05df9932d8b3631ff2f2ef43e32678/inflate64-1.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0efe4377c41a5b73f505d7ac613b85cd855d10b27e0e7e2ad3d7fceecfbb69a4", size = 93173, upload-time = "2025-06-01T04:42:10.458Z" }, + { url = "https://files.pythonhosted.org/packages/62/34/3a0a3bbaf59d03323fc2860871847346855cae4affa8dd9bdb5ffc34668d/inflate64-1.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8221b09edb0e94107b8c33da31f5e49ff9c49c96ab91956cc428891e39d2fd4e", size = 93520, upload-time = "2025-06-01T04:42:11.828Z" }, + { url = "https://files.pythonhosted.org/packages/d1/50/7db3ba56956ae235f1582fd652788975ad8f2dc32aabedd702e95640a9b7/inflate64-1.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a0302b10bfed4b741be6221f52e83eabc337baf784dd0ca8ab8ca56458291952", size = 95880, upload-time = "2025-06-01T04:42:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/01/0d/b48bcc21a8107a03a3bcc7b709d61de0affaea2078a388ef513b2410ad1e/inflate64-1.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6df9b82179fc4616f315cd326a4d401649683b51314dcf59edac4cb5dcfc34d", size = 96437, upload-time = "2025-06-01T04:42:15.404Z" }, + { url = "https://files.pythonhosted.org/packages/92/5d/bf777333a4c720d9652a4f7882f2c9739e4c538762cd549c9f52dedfd7bb/inflate64-1.0.3-cp310-cp310-win32.whl", hash = "sha256:8316c03d0d85de87bbff1641fb43a3367653beddaace3b50c35f49af5af8045c", size = 32984, upload-time = "2025-06-01T04:42:17.163Z" }, + { url = "https://files.pythonhosted.org/packages/64/2f/c071302640737e6c34e8f31e28064dfabdfaed96680cc42cb486fb522bd6/inflate64-1.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:8c88db9b53f31c06e99246af902643d6037912fd2ffb2ee58d12b3f705cad7d6", size = 35602, upload-time = "2025-06-01T04:42:18.835Z" }, + { url = "https://files.pythonhosted.org/packages/51/a9/210a6f9604952da0618130d32bd3dfd9c69b7f5c85ebbbf5ed1849994faa/inflate64-1.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:849cfc0f1395d9497a19356d90a41163471e2612a995c1cc0d39a1fc4fd4e442", size = 33226, upload-time = "2025-06-01T04:42:20.401Z" }, + { url = "https://files.pythonhosted.org/packages/91/24/834554f73973d2753c40d4e4a27a61e391e14d658e673a44b034891092ff/inflate64-1.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:faa2cb8301efc89ccb187ed4f7840ce0335da42ba53723077d0125b4b22789ce", size = 58609, upload-time = "2025-06-01T04:42:22.093Z" }, + { url = "https://files.pythonhosted.org/packages/00/78/6f2048fe0b75e757d1da5dda5316be0cf9472e14539afd8dbc75c4adf0c1/inflate64-1.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e47b63739611998142533e6e22cc3f947f4043e7e3bc7d70f94ffc4e4b1aa2b2", size = 35944, upload-time = "2025-06-01T04:42:23.842Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ab/eeb7ae75ca800c17268a13dd8b54dae5421bcb3f87d5b280213277ccbdaa/inflate64-1.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c0128fccc72259d99580ff60682575da66322eba8faa3dab4a75232b519defed", size = 35941, upload-time = "2025-06-01T04:42:25.553Z" }, + { url = "https://files.pythonhosted.org/packages/9b/7a/2664a6ef98f33c484fd07d7be7770a8b8e09f66c8db2f27613e6db9b852c/inflate64-1.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dca452520ce5f286684577f02b06f669b9903380327d11231b5bdd3c6f27f2f", size = 96262, upload-time = "2025-06-01T04:42:27.317Z" }, + { url = "https://files.pythonhosted.org/packages/51/f5/a7db594bef3baab4036ae2c89863522944c0380684c98072955f97117093/inflate64-1.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9724aaa82a5181dd97f9e31134ede30f41a7add8b35073656e02fd16418c93c", size = 96419, upload-time = "2025-06-01T04:42:29.243Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fb/11d45796eb7c2c5261651e1c63e2b9386780eeec21aa13b5d489558be099/inflate64-1.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4b95b4866a5b5d1ca79f9c431f9f5d39586249c1b94985bdd5cc0704b70eebd2", size = 98866, upload-time = "2025-06-01T04:42:30.542Z" }, + { url = "https://files.pythonhosted.org/packages/0c/a4/ead0f01fa73d1f31533f09c4419b44cae9ce771fc0785db35d417779bf7b/inflate64-1.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3009f85dec641b9af0b41ac0e5c849710e69c90955797ee760c2abfb302fa768", size = 99358, upload-time = "2025-06-01T04:42:32.392Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/dac912786228296baa992f66b9c884e2aa6ee8ea93e9e2d0587092616993/inflate64-1.0.3-cp311-cp311-win32.whl", hash = "sha256:a36c0fa721acb800bbb9cbf5054ea0d9de4469e43b8b1fcd9d2bbb400ed4ccc0", size = 32986, upload-time = "2025-06-01T04:42:34.169Z" }, + { url = "https://files.pythonhosted.org/packages/e7/a2/74950c87d3bf8e79205fefcce5c37b4f1c066182a6f2b108bf1a915c873c/inflate64-1.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:8b14af86981e3f691bde23bd291e6bfe4114ddee50046a6f690d7a5b625c41b0", size = 35600, upload-time = "2025-06-01T04:42:35.839Z" }, + { url = "https://files.pythonhosted.org/packages/65/08/1cae66490f22f186b4e8fc6c38e020b39f28d4db70126b37d85ed8c73815/inflate64-1.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:0856bdd440f7035803f25846015166bfd3daf59e659e43b6596cea37b389c839", size = 33227, upload-time = "2025-06-01T04:42:37.061Z" }, + { url = "https://files.pythonhosted.org/packages/b9/5b/c70411e396ea594153edca9607af736d11dd336cb76ddb028c5dc0ee39d3/inflate64-1.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a25967a307aacf20ae979264fb7a1ad27b25a56fbc7e96dd28fcc12d54727479", size = 58663, upload-time = "2025-06-01T04:42:38.269Z" }, + { url = "https://files.pythonhosted.org/packages/4b/90/beb038045b076595da4f25c8dc5c0e7572f1fc56d71220e6ee6d194f92e6/inflate64-1.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:54dc4d1a17084ff15127c5e88c8dd1aa57e48f292c1ac1f4c65f226b6fd93d9c", size = 35965, upload-time = "2025-06-01T04:42:39.669Z" }, + { url = "https://files.pythonhosted.org/packages/24/17/3a7561b21a7d5b3ca0fbc3d9e0691218c687fc82422bfc0568692bbd31e5/inflate64-1.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d8fb0bc154147437df1d45c9466b2c06c745e49d238de356b709cd6b5c45769", size = 35974, upload-time = "2025-06-01T04:42:40.897Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c5/89559de5b79b14f8c229f8f96fed9d39ded32169de3d350b76099ab2b29d/inflate64-1.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:478b51748e3754200a11520fccec836fa5719b7f7fb5f90d67594e9940978834", size = 96157, upload-time = "2025-06-01T04:42:42.607Z" }, + { url = "https://files.pythonhosted.org/packages/63/b9/a0bb6c58993a531ebaa7f83e15bfcb888b2e88b89d8173ad33d3cba3193f/inflate64-1.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0cf0906c46a3224ffc96bd33c5fc108f4239c2552fbd1d10488a47ce7882465", size = 97037, upload-time = "2025-06-01T04:42:43.974Z" }, + { url = "https://files.pythonhosted.org/packages/42/18/254ea3bc97df9d695805aed2690cf2c23c951689fe0e873f76e4ae35e240/inflate64-1.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3dc36f76668d9174f17c27d19d0e95cb54cac0194ecb75cabbeed6244e75ab34", size = 98979, upload-time = "2025-06-01T04:42:45.632Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6a/0ae6da63c9c35a7c43da1e6d0a831772fbc3c2b49a2fb2a4f75ccaa596de/inflate64-1.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f7f25b374af2c3d5d9fc016ad3907545d0a4a31c7765830f126da9fcbd5f04c9", size = 100107, upload-time = "2025-06-01T04:42:47.11Z" }, + { url = "https://files.pythonhosted.org/packages/6d/da/319c627d9577dcfeb52f9f86277370676923a9d031295b61912b05a0f567/inflate64-1.0.3-cp312-cp312-win32.whl", hash = "sha256:9f5607153f294cb7ba37fdb6e744fe5c188d4b431fd6ff7b77530f39422eb026", size = 32970, upload-time = "2025-06-01T04:42:48.416Z" }, + { url = "https://files.pythonhosted.org/packages/5a/67/fef6de9945f9b72b8116c2dff3f9f24d7f53eb5f7f5c3c0613b9593f5d75/inflate64-1.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:34b793dd49fcc5c46e96e7156584de47fe9745ef2b45c4976f9c7764ea0137de", size = 35756, upload-time = "2025-06-01T04:42:49.619Z" }, + { url = "https://files.pythonhosted.org/packages/a3/d7/94fd3e1af92806fe21db1d2a9af9a0f41d4031fa55b4bb4ea99857e18bbe/inflate64-1.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:cd180b2a8709131a0768056f57cb0327813d55a214e76d7aed41b4413345a76b", size = 33209, upload-time = "2025-06-01T04:42:51.024Z" }, + { url = "https://files.pythonhosted.org/packages/26/7c/7a8ff64270a93dd06f0fdc7b848aef57d52958abeacc6b8e96797f94fb7d/inflate64-1.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1d5340fe27f88a2946968f7de1ebe996be6c8d59fd4a1ac00aacc5bcafcc6583", size = 58662, upload-time = "2025-06-01T04:42:52.26Z" }, + { url = "https://files.pythonhosted.org/packages/6b/69/b3b87d25a8d31dc0a4f0a9e441f2e02e198cff4259b5ecb877b73505c8dc/inflate64-1.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:75b1625b027111270a5bb89fb6cb83930eacf4538881fb8ef901e00839272dc7", size = 35962, upload-time = "2025-06-01T04:42:53.575Z" }, + { url = "https://files.pythonhosted.org/packages/d0/53/62fd8e9f2016936ddf87e5678994f25c97bb2e4d82215f28a15bfaebc9b9/inflate64-1.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1ced5841cbe81cb158c1fc0df7837e0f3c38b2f3b5b0c8f2a6490eb78b3a4f7a", size = 35966, upload-time = "2025-06-01T04:42:54.799Z" }, + { url = "https://files.pythonhosted.org/packages/73/1d/6b4aac08cdf286164e652acbe542ef0da81d294b69ca48ff390066d370ff/inflate64-1.0.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b89fddc67a3a2edc764cac2ef7cf0de76e2c98fce0800f55fa8974bcb01a10a9", size = 96242, upload-time = "2025-06-01T04:42:56.099Z" }, + { url = "https://files.pythonhosted.org/packages/3e/44/17e812a3e4dd86fb03d5d271927b86615c7e8782325ca878f2c9bae10069/inflate64-1.0.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e32f7fb9c4120cdc27024249687fdaace2dc88857be6c031ae276d085a54166", size = 97090, upload-time = "2025-06-01T04:42:57.449Z" }, + { url = "https://files.pythonhosted.org/packages/de/f4/de5ddfd39b36a1754b0d2c8ccb7c38ab0382429d128d030c3cba6bd05627/inflate64-1.0.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:14752a079cb4ab3d9653d39a818f2e0daf3c0b445efc332c343caeff908de2b7", size = 98891, upload-time = "2025-06-01T04:42:58.757Z" }, + { url = "https://files.pythonhosted.org/packages/ed/0d/dc0a597ce6de35f8f0a07ecc8af67cad17ca7d2f4997acc1cdf101ef4e06/inflate64-1.0.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:14b811164f0c8048a90570c4213596eee277ab6454c86f1f80a5ace536e3b570", size = 99961, upload-time = "2025-06-01T04:43:00.132Z" }, + { url = "https://files.pythonhosted.org/packages/11/69/9e78965c491d7a389e002fc02af8863b62e5a376e8ebbd60543cfcf17808/inflate64-1.0.3-cp313-cp313-win32.whl", hash = "sha256:61a24f463e6dac38ddf2d4c011a54247f86cf676e869797de0e344ef7a4be456", size = 32971, upload-time = "2025-06-01T04:43:01.435Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9d/21c2baa41ac3aa762bcbb66a7a9f00b7857489fe7531a2e7d35df262da94/inflate64-1.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:5b077eaf7d6e99823751bd30e450102419cd71b6db4b3765e752e843fc040906", size = 35753, upload-time = "2025-06-01T04:43:02.65Z" }, + { url = "https://files.pythonhosted.org/packages/74/62/14784f5b15f31a3dff1d954e14891ab8942cd3a7e88649705a00d23a4c36/inflate64-1.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:abc83da55d66d8e8cf1a782d5870f1aab4f2380d489af8c15825ee003645a974", size = 33211, upload-time = "2025-06-01T04:43:03.852Z" }, ] [[package]] @@ -544,18 +526,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349, upload-time = "2024-08-16T15:55:16.176Z" }, ] -[[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, upload-time = "2023-06-03T06:41:14.443Z" } -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, upload-time = "2023-06-03T06:41:11.019Z" }, -] - [[package]] name = "markupsafe" version = "2.1.5" @@ -594,15 +564,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127, upload-time = "2024-02-02T16:30:44.418Z" }, ] -[[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, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - [[package]] name = "mergedeep" version = "1.3.4" @@ -833,22 +794,22 @@ wheels = [ [[package]] name = "psutil" -version = "6.0.0" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067, upload-time = "2024-06-18T21:40:10.559Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961, upload-time = "2024-06-18T21:41:11.662Z" }, - { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478, upload-time = "2024-06-18T21:41:16.18Z" }, - { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455, upload-time = "2024-06-18T21:41:29.048Z" }, - { url = "https://files.pythonhosted.org/packages/cd/5f/60038e277ff0a9cc8f0c9ea3d0c5eb6ee1d2470ea3f9389d776432888e47/psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", size = 292046, upload-time = "2024-06-18T21:41:33.53Z" }, - { url = "https://files.pythonhosted.org/packages/8b/20/2ff69ad9c35c3df1858ac4e094f20bd2374d33c8643cf41da8fd7cdcb78b/psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", size = 253560, upload-time = "2024-06-18T21:41:46.067Z" }, - { url = "https://files.pythonhosted.org/packages/73/44/561092313ae925f3acfaace6f9ddc4f6a9c748704317bad9c8c8f8a36a79/psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", size = 257399, upload-time = "2024-06-18T21:41:52.1Z" }, - { url = "https://files.pythonhosted.org/packages/7c/06/63872a64c312a24fb9b4af123ee7007a306617da63ff13bcc1432386ead7/psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0", size = 251988, upload-time = "2024-06-18T21:41:57.337Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, ] [[package]] name = "py7zr" -version = "0.22.0" +version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, @@ -859,44 +820,57 @@ dependencies = [ { name = "pybcj" }, { name = "pycryptodomex" }, { name = "pyppmd" }, - { name = "pyzstd" }, + { name = "pyzstd", version = "0.16.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" }, + { name = "pyzstd", version = "0.17.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" }, { name = "texttable" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/26/c3/0e05c711c16af0b9c47f3f77323303b338b9a871ba020d95d2b8dd6605ae/py7zr-0.22.0.tar.gz", hash = "sha256:c6c7aea5913535184003b73938490f9a4d8418598e533f9ca991d3b8e45a139e", size = 4992926, upload-time = "2024-08-08T13:10:01.514Z" } +sdist = { url = "https://files.pythonhosted.org/packages/97/62/d6f18967875aa60182198a0dd287d3a50d8aea1d844239ea00c016f7be88/py7zr-1.0.0.tar.gz", hash = "sha256:f6bfee81637c9032f6a9f0eb045a4bfc7a7ff4138becfc42d7cb89b54ffbfef1", size = 4965058, upload-time = "2025-06-02T11:03:37.472Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/59/dd1750002c0f46099281116f8165247bc62dc85edad41cdd26e7b26de19d/py7zr-0.22.0-py3-none-any.whl", hash = "sha256:993b951b313500697d71113da2681386589b7b74f12e48ba13cc12beca79d078", size = 67906, upload-time = "2024-08-08T13:09:58.092Z" }, + { url = "https://files.pythonhosted.org/packages/73/56/63f27ec4e263a5f7f11a0630515938263fd9ba8227bda94136486b58e45d/py7zr-1.0.0-py3-none-any.whl", hash = "sha256:6f42d2ff34c808e9026ad11b721c13b41b0673cf2b4e8f8fb34f9d65ae143dd1", size = 69677, upload-time = "2025-06-02T11:03:35.082Z" }, ] [[package]] name = "pybcj" -version = "1.0.2" +version = "1.0.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/d2/22e808b9d25ce3b43f5c8a9e22d873d403485ba55d84a4d6d5d044881762/pybcj-1.0.2.tar.gz", hash = "sha256:c7f5bef7f47723c53420e377bc64d2553843bee8bcac5f0ad076ab1524780018", size = 2111002, upload-time = "2023-11-05T06:47:00.756Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/75/bbcf098abf68081fa27c09d642790daa99d9156132c8b0893e3fecd946ab/pybcj-1.0.6.tar.gz", hash = "sha256:70bbe2dc185993351955bfe8f61395038f96f5de92bb3a436acb01505781f8f2", size = 2112413, upload-time = "2025-04-29T08:51:40.966Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/93/4735636b5905b7597068a2c7a10a8df0f668f28659207c274d64a4468b97/pybcj-1.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7bff28d97e47047d69a4ac6bf59adda738cf1d00adde8819117fdb65d966bdbc", size = 32556, upload-time = "2023-11-05T06:45:47.655Z" }, - { url = "https://files.pythonhosted.org/packages/a6/37/443cd704397b6df54ff0822032e4815aca4e9badabc5ce1faac34235a40c/pybcj-1.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:198e0b4768b4025eb3309273d7e81dc53834b9a50092be6e0d9b3983cfd35c35", size = 23751, upload-time = "2023-11-05T06:45:49.762Z" }, - { url = "https://files.pythonhosted.org/packages/9a/aa/5a19ed8661e979a4d3237a11706f9a16a474a2227fdd99ccb284be100a98/pybcj-1.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa26415b4a118ea790de9d38f244312f2510a9bb5c65e560184d241a6f391a2d", size = 23980, upload-time = "2023-11-05T06:45:51.523Z" }, - { url = "https://files.pythonhosted.org/packages/fe/5f/638ce03948905d267c8c0ccab81b8b4943a0324f63d8bdb0a0e2a85d4503/pybcj-1.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fabb2be57e4ca28ea36c13146cdf97d73abd27c51741923fc6ba1e8cd33e255c", size = 50155, upload-time = "2023-11-05T06:45:53.546Z" }, - { url = "https://files.pythonhosted.org/packages/09/70/8b6a6cc2a5721f67f629bdc17875c0d603d57f360a19b099a7b4de19383d/pybcj-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d6d613bae6f27678d5e44e89d61018779726aa6aa950c516d33a04b8af8c59", size = 49729, upload-time = "2023-11-05T06:45:55.57Z" }, - { url = "https://files.pythonhosted.org/packages/89/06/2e41e34da0bb2adb3644cbf4366c344e5804a10f1153da7b3a23333f7db8/pybcj-1.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ffae79ef8a1ea81ea2748ad7b7ad9b882aa88ddf65ce90f9e944df639eccc61", size = 54310, upload-time = "2023-11-05T06:45:57.429Z" }, - { url = "https://files.pythonhosted.org/packages/b5/0f/de9e76c305d4dcd9d428a90ccac030f06c780bc30549fc449a944a6321bc/pybcj-1.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bdb4d8ff5cba3e0bd1adee7d20dbb2b4d80cb31ac04d6ea1cd06cfc02d2ecd0d", size = 53679, upload-time = "2023-11-05T06:45:59.423Z" }, - { url = "https://files.pythonhosted.org/packages/1a/41/a807ff6b77ec8e49c749ed1d0db5649fbb1150c6fb5fb391115f4f1d743a/pybcj-1.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a29be917fbc99eca204b08407e0971e0205bfdad4b74ec915930675f352b669d", size = 24690, upload-time = "2023-11-05T06:46:01.416Z" }, - { url = "https://files.pythonhosted.org/packages/27/0a/20bf70a7eb7c6b2668ff2af798254033c32a09d6c58ec9a87cd6aa843df5/pybcj-1.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a2562ebe5a0abec4da0229f8abb5e90ee97b178f19762eb925c1159be36828b3", size = 32581, upload-time = "2023-11-05T06:46:03.418Z" }, - { url = "https://files.pythonhosted.org/packages/a9/b6/43977fe4296d2778c6dc67b596bb6a851eaea80f3dd4ff454e5fca8142c2/pybcj-1.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:af19bc61ded933001cd68f004ae2042bf1a78eb498a3c685ebd655fa1be90dbe", size = 23767, upload-time = "2023-11-05T06:46:05.291Z" }, - { url = "https://files.pythonhosted.org/packages/89/c7/a61010f59406b8a45bb4865faa4b61d6b177dcfac04247fb56c7538d997d/pybcj-1.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3f4a447800850aba7724a2274ea0a4800724520c1caf38f7d0dabf2f89a5e15", size = 23976, upload-time = "2023-11-05T06:46:06.789Z" }, - { url = "https://files.pythonhosted.org/packages/10/7a/78848edbb6f12d9b86e375fc46135d9a204ededbf96682b05cb4b4fbd942/pybcj-1.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1c8af7a4761d2b1b531864d84113948daa0c4245775c63bd9874cb955f4662", size = 51246, upload-time = "2023-11-05T06:46:08.73Z" }, - { url = "https://files.pythonhosted.org/packages/9e/13/af86c86cdfb293e82dd0b6c4bbdf08645cd8993456ee3fb911c3eeed1b22/pybcj-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8007371f6f2b462f5aa05d5c2135d0a1bcf5b7bdd9bd15d86c730f588d10b7d3", size = 50754, upload-time = "2023-11-05T06:46:10.655Z" }, - { url = "https://files.pythonhosted.org/packages/39/52/88600aa374b100612a1d82fca4b03eb4315e0084a05ee314ba1b771f7190/pybcj-1.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1079ca63ff8da5c936b76863690e0bd2489e8d4e0a3a340e032095dae805dd91", size = 55334, upload-time = "2023-11-05T06:46:12.761Z" }, - { url = "https://files.pythonhosted.org/packages/56/67/3cf9747ef5b53e16a844217c6c9840be6289d05ec785500da2cc55cc25f2/pybcj-1.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e9a785eb26884429d9b9f6326e68c3638828c83bf6d42d2463c97ad5385caff2", size = 54714, upload-time = "2023-11-05T06:46:14.907Z" }, - { url = "https://files.pythonhosted.org/packages/78/81/a71197903b503f54b85f4d352f909e701e9d26953577bd34d3fbe0520d5d/pybcj-1.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:9ea46e2d45469d13b7f25b08efcdb140220bab1ac5a850db0954591715b8caaa", size = 24693, upload-time = "2023-11-05T06:46:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/83/60/a3b43836895654aa93b5a8422adc3717359db98da9147abfabffef79f1e7/pybcj-1.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:21b5f2460629167340403d359289a173e0729ce8e84e3ce99462009d5d5e01a4", size = 32677, upload-time = "2023-11-05T06:46:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/96c8d9577b0f5a701e4497408e6a331a08eb902aca8dfd4c5bb1eaab4779/pybcj-1.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2940fb85730b9869254559c491cd83cf777e56c76a8a60df60e4be4f2a4248d7", size = 23813, upload-time = "2023-11-05T06:46:20.465Z" }, - { url = "https://files.pythonhosted.org/packages/b7/1a/c80132feb084ec4098c0315a132799bddda8878113b5f956e21c4377f5f1/pybcj-1.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f40f3243139d675f43793a4e35c410c370f7b91ccae74e70c8b2f4877869f90e", size = 24019, upload-time = "2023-11-05T06:46:21.863Z" }, - { url = "https://files.pythonhosted.org/packages/b1/94/62c3bf8a60b4787b46e21f43277d9cb8b6037c8ee183450f035a19a2bc4b/pybcj-1.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c2b3e60b65c7ac73e44335934e1e122da8d56db87840984601b3c5dc0ae4c19", size = 51927, upload-time = "2023-11-05T06:46:23.99Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9e/4ebd092251ef8d15408388be508617d5949cbba4baa2a6cfbb7e0a9b62c0/pybcj-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:746550dc7b5af4d04bb5fa4d065f18d39c925bcb5dee30db75747cd9a58bb6e8", size = 51665, upload-time = "2023-11-05T06:46:25.761Z" }, - { url = "https://files.pythonhosted.org/packages/24/ea/da4637563468854bd361a69cd883946015f54fa119a5d9c655d26f151954/pybcj-1.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8ce9b62b6aaa5b08773be8a919ecc4e865396c969f982b685eeca6e80c82abb7", size = 56041, upload-time = "2023-11-05T06:46:27.403Z" }, - { url = "https://files.pythonhosted.org/packages/cf/b2/9b9e670818af925ed9a0168a5c021ccfcc089637d0e6651d16fd05896425/pybcj-1.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:493eab2b1f6f546730a6de0c5ceb75ce16f3767154e8ae30e2b70d41b928b7d2", size = 55606, upload-time = "2023-11-05T06:46:29.657Z" }, - { url = "https://files.pythonhosted.org/packages/72/e9/d6b1bdf3a5aca8f3981145a5228ad51d72e2477a55927604a4768765e915/pybcj-1.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:ef55b96b7f2ed823e0b924de902065ec42ade856366c287dbb073fabd6b90ec1", size = 24719, upload-time = "2023-11-05T06:46:31.018Z" }, + { url = "https://files.pythonhosted.org/packages/87/9d/b138d33ff49d4d15e778b940702bfd4e6d3a4b0eae1ed53be01ca6e7177b/pybcj-1.0.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0fc8eda59e9e52d807f411de6db30aadd7603aa0cb0a830f6f45226b74be1926", size = 31749, upload-time = "2025-04-29T08:50:43.399Z" }, + { url = "https://files.pythonhosted.org/packages/17/05/97b819f60d58eb18f97cb82e662b0d023421b77be18915a62bc364ce854f/pybcj-1.0.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0495443e8691510129f0c589ed956af4962c22b7963c5730b0c80c9c5b818c06", size = 23536, upload-time = "2025-04-29T08:50:44.823Z" }, + { url = "https://files.pythonhosted.org/packages/31/61/9505b304b8ba381dea8c58816bbc2d7d41300c26d115a69010b0576898e8/pybcj-1.0.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c7998b546c3856dbe9ae879cb90393df80507f65097e7019785852769f4a990", size = 23942, upload-time = "2025-04-29T08:50:45.939Z" }, + { url = "https://files.pythonhosted.org/packages/49/04/a1ceee49ee3769c5bbd935701906524191d6fd98ad772fdf64d78f71703f/pybcj-1.0.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:335c859f85e718924f48b3ac967cda5528ccbef1e448a4462652cca688eee477", size = 50156, upload-time = "2025-04-29T08:50:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/96/9d/d3d94dadb3eb59873c86bc7046ef6db4ff7d006ec06846ada1d86c7b72f7/pybcj-1.0.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:186fbb849883ac80764d96dbd253503dd9cecbcf6133504a0c9d6a2df81d5746", size = 49733, upload-time = "2025-04-29T08:50:48.161Z" }, + { url = "https://files.pythonhosted.org/packages/cc/52/19671ac80b1dd53aa05b130c57267d35346e8a0d084fb08c37b51490730c/pybcj-1.0.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:437bd5f5e6579bde404404ad2de915d1306c389595c68d0eb8933fee1408e951", size = 54307, upload-time = "2025-04-29T08:50:50.062Z" }, + { url = "https://files.pythonhosted.org/packages/56/bc/938a9bf9fd9a0442d2b0b374431a07e275ed6796b35e278419e230341973/pybcj-1.0.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:933d6be8f07c653ff3eba16900376b3212249be1c71caf9db17f4cd52da5076c", size = 53676, upload-time = "2025-04-29T08:50:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/62/43/1b8a2d5261ef5da7e5345b7ea0424df1a0f0823b8883919a50d454243fe8/pybcj-1.0.6-cp310-cp310-win_amd64.whl", hash = "sha256:90e169b669bbed30e22d36ba97d23dcfc71e044d3be41c8010fd6a53950725e5", size = 24854, upload-time = "2025-04-29T08:50:52.227Z" }, + { url = "https://files.pythonhosted.org/packages/81/bd/56afdb78095cc98d3646542c2bcd30b473048e6be6d01338381b83dd46d7/pybcj-1.0.6-cp310-cp310-win_arm64.whl", hash = "sha256:06441026c773f8abeb7816566acfffe7cd65a9b69094197a9de64d0496cd4c3c", size = 23063, upload-time = "2025-04-29T08:50:53.714Z" }, + { url = "https://files.pythonhosted.org/packages/24/03/04ff0abb08d6c29be1398449254c42a96c65ff761f9ee94585b6c8a849ea/pybcj-1.0.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0275564a1afc4b2d1a6ff465384fb73a64622a88b6e4856cb7964ba2335a06e", size = 31753, upload-time = "2025-04-29T08:50:54.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/54/bad24337182812d8da48033b3adbcbac13e61ebc177562a5f8071d3e5877/pybcj-1.0.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fa794b134b4ee183a4ceb739e9c3a445a24ee12e7e3231c37820f66848db4c52", size = 23533, upload-time = "2025-04-29T08:50:56.01Z" }, + { url = "https://files.pythonhosted.org/packages/3f/09/a5c319c0fd8cf0ba5ff1898065eb45a79efb313d16bbc98921594b9a3cae/pybcj-1.0.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d8945e8157c7fa469db110fc78579d154a31d121d14705b26d7d3ec3a471c8e", size = 23941, upload-time = "2025-04-29T08:50:57.464Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/8a643eb8aa1352a95465cceb77440a05d1b669dae19ad5bcf84b418a67c8/pybcj-1.0.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7109177b4f77526a6ce4b565ee37483f5a5dd29bc92eaea6739b3c58618aeb7", size = 51242, upload-time = "2025-04-29T08:50:58.458Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f9/b3b26b19d874605d5e00e549b4106637e88af9014775d17ba5122393431e/pybcj-1.0.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c48cbc9ebed137ac8759d0f2c3d12b999581dae7b4f84d974888c402f00fdb78", size = 50746, upload-time = "2025-04-29T08:50:59.855Z" }, + { url = "https://files.pythonhosted.org/packages/e9/8a/11205743c537b7285d386db3243e3793f1d337d586b20854d17d412e4c87/pybcj-1.0.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6dccff82008e3cb5e5e639737320c02341b8718e189b9ece13f0230e0d57e7af", size = 55311, upload-time = "2025-04-29T08:51:00.951Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3e/cab50b337b1a40596cc73547e71c2446f9991f4e22f7c884fb95068a39ad/pybcj-1.0.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e4e68cfc4fb099e8200386ac2255a9f514b8bb056189273bcce874bda3597459", size = 54700, upload-time = "2025-04-29T08:51:02.029Z" }, + { url = "https://files.pythonhosted.org/packages/d2/a6/530e84fe22ccf9afc0187fa78278cfbf1f0c11fe76503119fc2809ae2728/pybcj-1.0.6-cp311-cp311-win_amd64.whl", hash = "sha256:13747c01b60bf955878267718f28c36e2bbb81fb8495b0173b21083c7d08a4a4", size = 24848, upload-time = "2025-04-29T08:51:03.123Z" }, + { url = "https://files.pythonhosted.org/packages/ae/78/bdbf1f29bc94cf3c8d61c80dfea24e02955c9cf8309c25aec54a82fb1a82/pybcj-1.0.6-cp311-cp311-win_arm64.whl", hash = "sha256:6f81d6106c50c5e91c16ad58584fd7ab9eb941360188547e0184b1ede9e47f1d", size = 23069, upload-time = "2025-04-29T08:51:04.11Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/42afc83cda05aed0aa77bcbd711c418437409b049ebd6c61d8d49afbd84e/pybcj-1.0.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f5d1dbc76f615595d7d8f3846c07f607fb1e2305d085c34556b32dacf8e88d12", size = 31805, upload-time = "2025-04-29T08:51:05.573Z" }, + { url = "https://files.pythonhosted.org/packages/b0/4f/81f46d380b61d9adc305065e966b8787c2d10650e60fc76eb1569f4ec9f2/pybcj-1.0.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1398f556ed2afe16ae363a2b6e8cf6aeda3aa21861757286bc6c498278886c60", size = 23586, upload-time = "2025-04-29T08:51:07.044Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b5/0d27992fbc24573aee833c1d1dc3d6fa035c9ecb19e453bde1e4babe6512/pybcj-1.0.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e269cfc7b6286af87c5447c9f8c685f19cff011cac64947ffb4cd98919696a7f", size = 23961, upload-time = "2025-04-29T08:51:08.077Z" }, + { url = "https://files.pythonhosted.org/packages/c5/8d/359c8906b0337ed33e3bcb100640861a08222dbddc820b1382b58e1bf265/pybcj-1.0.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7393d0b0dcaa0b1a7850245def78fa14438809e9a3f73b1057a975229d623fd3", size = 51928, upload-time = "2025-04-29T08:51:09.515Z" }, + { url = "https://files.pythonhosted.org/packages/03/4d/3ff0565ff69390f110c4d497ca96a8c757584c334dabad8451e35d6db210/pybcj-1.0.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e252891698d3e01d0f60eb5adfe849038cd2d429cb9510f915a0759301f1884d", size = 51670, upload-time = "2025-04-29T08:51:10.608Z" }, + { url = "https://files.pythonhosted.org/packages/1a/af/49401daf3e01014fc8576b24677b054399f891a20e6f13807a4cc0e06805/pybcj-1.0.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ae5c891fcda9d5a6826a1b8e843b1e52811358594121553e6683e65b13eccce7", size = 56012, upload-time = "2025-04-29T08:51:11.646Z" }, + { url = "https://files.pythonhosted.org/packages/f5/fe/3e5e12e4d489f84e5e0ff7331cf39395c0b176e4ddae303697828d276a64/pybcj-1.0.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:eac3cb317df1cefed2783ce9cafdae61899dd02f2f4749dc0f4494a7c425745f", size = 55565, upload-time = "2025-04-29T08:51:12.739Z" }, + { url = "https://files.pythonhosted.org/packages/7b/42/6856e9913bbb72e77029e953dadd9d835ebd4222cd1856b90a37f494c353/pybcj-1.0.6-cp312-cp312-win_amd64.whl", hash = "sha256:72ebec5cda5a48de169c2d7548ea2ce7f48732de0175d7e0e665ca7360eaa4c4", size = 24874, upload-time = "2025-04-29T08:51:14.303Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3e/94a5261ba2da1adb3555a2f0cebe2e9c1b23b0f91961cb6a268aea042a38/pybcj-1.0.6-cp312-cp312-win_arm64.whl", hash = "sha256:8f1f75a01e45d01ecf88d31910ca1ace5d345e3bfb7c18db0af3d0c393209b63", size = 23076, upload-time = "2025-04-29T08:51:15.323Z" }, + { url = "https://files.pythonhosted.org/packages/77/cf/bda2eebe8f3fd0ed9967092a3a637d30227195ff44419b1d11a526d9e0b5/pybcj-1.0.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3e6800eb599ce766e588095eedb2a2c45a93928d1880420e8ecfad7eff0c73dc", size = 31807, upload-time = "2025-04-29T08:51:16.481Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ab/e04befe57175c0ef6f00368263e17ef79dadfaf633057dcd13711ef06678/pybcj-1.0.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:69a841ca0d3df978a2145488cec58460fa4604395321178ba421384cff26062f", size = 23586, upload-time = "2025-04-29T08:51:17.949Z" }, + { url = "https://files.pythonhosted.org/packages/c2/aa/25877ccb48f638c5cef205ed8185848e7daff53f152cdd6e014ceee86753/pybcj-1.0.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:887521da03302c96048803490073bd0423ff408a3adca2543c6ee86bc0af7578", size = 23963, upload-time = "2025-04-29T08:51:19.417Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7e/f34c68779102aaf74ccf8c78ddd307dc55e42822e5e31e35ac9efc09e3d7/pybcj-1.0.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39a5a9a2d0e1fa4ddd2617a549c11e5022888af86dc8e29537cfee7f5761127d", size = 51925, upload-time = "2025-04-29T08:51:21.075Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b2/e658bf56f4d04a83b366128920fbda93024dee851f134660491b8cc97863/pybcj-1.0.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57757bc382f326bd93eb277a9edfc8dff6c22f480da467f0c5a5d63b9d092a41", size = 51639, upload-time = "2025-04-29T08:51:22.278Z" }, + { url = "https://files.pythonhosted.org/packages/e7/21/d2f88378b258332ce2474e0ef38240fac3711edf7858c2176fa3a92b137e/pybcj-1.0.6-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb1872b24b30d8473df433f3364e828b021964229d47a07f7bfc08496dbfd23e", size = 55772, upload-time = "2025-04-29T08:51:24.508Z" }, + { url = "https://files.pythonhosted.org/packages/c1/57/110b66c34308b070c52baf1685f7bd94532bb81f05e0d58acbad8f8372c7/pybcj-1.0.6-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:5fedfeed96ab0e34207097f663b94e8c7076025c2c7af6a482e670e808ea5bb0", size = 55294, upload-time = "2025-04-29T08:51:25.632Z" }, + { url = "https://files.pythonhosted.org/packages/52/21/df6e5cb6c918d5321a4db241be78fd71d5d18561a4458eec5757b0b6a1b2/pybcj-1.0.6-cp313-cp313-win_amd64.whl", hash = "sha256:caefc3109bf172ad37b52e21dc16c84cf495b2ea2890cc7256cdf0188914508d", size = 24870, upload-time = "2025-04-29T08:51:26.736Z" }, + { url = "https://files.pythonhosted.org/packages/fd/28/2fb3dbbf2669be30faf01c371fbc0aef65bebcf75f021116b00f9c5ad8a6/pybcj-1.0.6-cp313-cp313-win_arm64.whl", hash = "sha256:b24367175528da452a19e4c55368d5c907f4584072dc6aeee8990e2a5e6910fc", size = 23079, upload-time = "2025-04-29T08:51:28.312Z" }, ] [[package]] @@ -910,105 +884,37 @@ wheels = [ [[package]] name = "pycryptodomex" -version = "3.20.0" +version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/a4/b03a16637574312c1b54c55aedeed8a4cb7d101d44058d46a0e5706c63e1/pycryptodomex-3.20.0.tar.gz", hash = "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e", size = 4794613, upload-time = "2024-01-10T11:32:34.067Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/09/668b587ddaf2aa0f94ea45bca73e7c564816fd9329a05e8f7f870425981d/pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c", size = 2430400, upload-time = "2024-01-10T11:31:44.072Z" }, - { url = "https://files.pythonhosted.org/packages/4c/c4/9b1e8fca01c4b5a0e1c6f52ba19478b2692af4694afe8c89ebbe24348604/pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3", size = 1593362, upload-time = "2024-01-10T11:31:47.048Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b9/91af61ec562b87c0932122666603a37cd17f991bc05faf9123b598d1e518/pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623", size = 2065201, upload-time = "2024-01-10T11:31:49.86Z" }, - { url = "https://files.pythonhosted.org/packages/20/7a/3162173af8597f0399b45c6aaa4939ccae908476fdf1b3a3cc30631fc9fb/pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4", size = 2139169, upload-time = "2024-01-10T11:31:53.189Z" }, - { url = "https://files.pythonhosted.org/packages/1b/43/e67f7767a76db1067008127a04617165579e6a65b5c3acb230c7383ca514/pycryptodomex-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5", size = 2167742, upload-time = "2024-01-10T11:31:56.322Z" }, - { url = "https://files.pythonhosted.org/packages/bb/29/fb592db3f98b1ed330561518ff4706e869045b0cf27632a4310444731aa1/pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed", size = 2057793, upload-time = "2024-01-10T11:31:58.39Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ca/7f296284fad77182ad2b2c198a7ece14b04cc9e6e905b1082c015f2254d3/pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7", size = 2196243, upload-time = "2024-01-10T11:32:01.309Z" }, - { url = "https://files.pythonhosted.org/packages/48/7d/0f2b09490b98cc6a902ac15dda8760c568b9c18cfe70e0ef7a16de64d53a/pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43", size = 2158708, upload-time = "2024-01-10T11:32:03.55Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1c/375adb14b71ee1c8d8232904e928b3e7af5bbbca7c04e4bec94fe8e90c3d/pycryptodomex-3.20.0-cp35-abi3-win32.whl", hash = "sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e", size = 1726798, upload-time = "2024-01-10T11:32:05.521Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e8/1b92184ab7e5595bf38000587e6f8cf9556ebd1bf0a583619bee2057afbd/pycryptodomex-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc", size = 1762906, upload-time = "2024-01-10T11:32:07.563Z" }, - { url = "https://files.pythonhosted.org/packages/eb/df/3f1ea084e43b91e6d2b6b3493cc948864c17ea5d93ff1261a03812fbfd1a/pycryptodomex-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b", size = 1569076, upload-time = "2024-01-10T11:32:14.793Z" }, - { url = "https://files.pythonhosted.org/packages/c9/f3/83ffbdfa0c8f9154bcd8866895f6cae5a3ec749da8b0840603cf936c4412/pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea", size = 1609872, upload-time = "2024-01-10T11:32:17.268Z" }, - { url = "https://files.pythonhosted.org/packages/c9/9d/c113e640aaf02af5631ae2686b742aac5cd0e1402b9d6512b1c7ec5ef05d/pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781", size = 1640752, upload-time = "2024-01-10T11:32:20.027Z" }, - { url = "https://files.pythonhosted.org/packages/e4/8a/7c621942787a20d4cb7c32f0c49f183781c6b8753e6ba4f92e57a6d8b1f5/pycryptodomex-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499", size = 1744274, upload-time = "2024-01-10T11:32:22.083Z" }, -] - -[[package]] -name = "pydantic" -version = "2.8.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/99/d0a5dca411e0a017762258013ba9905cd6e7baa9a3fd1fe8b6529472902e/pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a", size = 739834, upload-time = "2024-07-04T02:59:49.416Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/fa/b7f815b8c9ad021c07f88875b601222ef5e70619391ade4a49234d12d278/pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8", size = 423875, upload-time = "2024-07-04T02:59:45.33Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/12/e3/0d5ad91211dba310f7ded335f4dad871172b9cc9ce204f5a56d76ccd6247/pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4", size = 388371, upload-time = "2024-07-03T17:04:13.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/9d/f30f080f745682e762512f3eef1f6e392c7d74a102e6e96de8a013a5db84/pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3", size = 1837257, upload-time = "2024-07-03T17:00:00.937Z" }, - { url = "https://files.pythonhosted.org/packages/f2/89/77e7aebdd4a235497ac1e07f0a99e9f40e47f6e0f6783fe30500df08fc42/pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6", size = 1776715, upload-time = "2024-07-03T17:00:12.346Z" }, - { url = "https://files.pythonhosted.org/packages/18/50/5a4e9120b395108c2a0441a425356c0d26a655d7c617288bec1c28b854ac/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a", size = 1789023, upload-time = "2024-07-03T17:00:15.542Z" }, - { url = "https://files.pythonhosted.org/packages/c7/e5/f19e13ba86b968d024b56aa53f40b24828652ac026e5addd0ae49eeada02/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3", size = 1775598, upload-time = "2024-07-03T17:00:18.332Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c7/f3c29bed28bd022c783baba5bf9946c4f694cb837a687e62f453c81eb5c6/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1", size = 1977691, upload-time = "2024-07-03T17:00:21.723Z" }, - { url = "https://files.pythonhosted.org/packages/41/3e/f62c2a05c554fff34570f6788617e9670c83ed7bc07d62a55cccd1bc0be6/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953", size = 2693214, upload-time = "2024-07-03T17:00:25.34Z" }, - { url = "https://files.pythonhosted.org/packages/ae/49/8a6fe79d35e2f3bea566d8ea0e4e6f436d4f749d7838c8e8c4c5148ae706/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98", size = 2061047, upload-time = "2024-07-03T17:00:29.176Z" }, - { url = "https://files.pythonhosted.org/packages/51/c6/585355c7c8561e11197dbf6333c57dd32f9f62165d48589b57ced2373d97/pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a", size = 1895106, upload-time = "2024-07-03T17:00:31.501Z" }, - { url = "https://files.pythonhosted.org/packages/ce/23/829f6b87de0775919e82f8addef8b487ace1c77bb4cb754b217f7b1301b6/pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a", size = 1968506, upload-time = "2024-07-03T17:00:33.586Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2f/f8ca8f0c40b3ee0a4d8730a51851adb14c5eda986ec09f8d754b2fba784e/pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840", size = 2110217, upload-time = "2024-07-03T17:00:36.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a0/1876656c7b17eb69cc683452cce6bb890dd722222a71b3de57ddb512f561/pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250", size = 1709669, upload-time = "2024-07-03T17:00:38.853Z" }, - { url = "https://files.pythonhosted.org/packages/be/4a/576524eefa9b301c088c4818dc50ff1c51a88fe29efd87ab75748ae15fd7/pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c", size = 1902386, upload-time = "2024-07-03T17:00:41.491Z" }, - { url = "https://files.pythonhosted.org/packages/61/db/f6a724db226d990a329910727cfac43539ff6969edc217286dd05cda3ef6/pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312", size = 1834507, upload-time = "2024-07-03T17:00:44.754Z" }, - { url = "https://files.pythonhosted.org/packages/9b/83/6f2bfe75209d557ae1c3550c1252684fc1827b8b12fbed84c3b4439e135d/pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88", size = 1773527, upload-time = "2024-07-03T17:00:47.141Z" }, - { url = "https://files.pythonhosted.org/packages/93/ef/513ea76d7ca81f2354bb9c8d7839fc1157673e652613f7e1aff17d8ce05d/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc", size = 1787879, upload-time = "2024-07-03T17:00:49.729Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/ac294caecf235f0cc651de6232f1642bb793af448d1cfc541b0dc1fd72b8/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43", size = 1774694, upload-time = "2024-07-03T17:00:52.201Z" }, - { url = "https://files.pythonhosted.org/packages/46/a4/08f12b5512f095963550a7cb49ae010e3f8f3f22b45e508c2cb4d7744fce/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6", size = 1976369, upload-time = "2024-07-03T17:00:55.025Z" }, - { url = "https://files.pythonhosted.org/packages/15/59/b2495be4410462aedb399071c71884042a2c6443319cbf62d00b4a7ed7a5/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121", size = 2691250, upload-time = "2024-07-03T17:00:57.166Z" }, - { url = "https://files.pythonhosted.org/packages/3c/ae/fc99ce1ba791c9e9d1dee04ce80eef1dae5b25b27e3fc8e19f4e3f1348bf/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1", size = 2061462, upload-time = "2024-07-03T17:00:59.381Z" }, - { url = "https://files.pythonhosted.org/packages/44/bb/eb07cbe47cfd638603ce3cb8c220f1a054b821e666509e535f27ba07ca5f/pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b", size = 1893923, upload-time = "2024-07-03T17:01:01.943Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ef/5a52400553b8faa0e7f11fd7a2ba11e8d2feb50b540f9e7973c49b97eac0/pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27", size = 1966779, upload-time = "2024-07-03T17:01:04.864Z" }, - { url = "https://files.pythonhosted.org/packages/4c/5b/fb37fe341344d9651f5c5f579639cd97d50a457dc53901aa8f7e9f28beb9/pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b", size = 2109044, upload-time = "2024-07-03T17:01:07.241Z" }, - { url = "https://files.pythonhosted.org/packages/70/1a/6f7278802dbc66716661618807ab0dfa4fc32b09d1235923bbbe8b3a5757/pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a", size = 1708265, upload-time = "2024-07-03T17:01:11.061Z" }, - { url = "https://files.pythonhosted.org/packages/35/7f/58758c42c61b0bdd585158586fecea295523d49933cb33664ea888162daf/pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2", size = 1901750, upload-time = "2024-07-03T17:01:13.335Z" }, - { url = "https://files.pythonhosted.org/packages/6f/47/ef0d60ae23c41aced42921728650460dc831a0adf604bfa66b76028cb4d0/pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231", size = 1839225, upload-time = "2024-07-03T17:01:15.981Z" }, - { url = "https://files.pythonhosted.org/packages/6a/23/430f2878c9cd977a61bb39f71751d9310ec55cee36b3d5bf1752c6341fd0/pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9", size = 1768604, upload-time = "2024-07-03T17:01:18.188Z" }, - { url = "https://files.pythonhosted.org/packages/9e/2b/ec4e7225dee79e0dc80ccc3c35ab33cc2c4bbb8a1a7ecf060e5e453651ec/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f", size = 1789767, upload-time = "2024-07-03T17:01:20.86Z" }, - { url = "https://files.pythonhosted.org/packages/64/b0/38b24a1fa6d2f96af3148362e10737ec073768cd44d3ec21dca3be40a519/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52", size = 1772061, upload-time = "2024-07-03T17:01:23.9Z" }, - { url = "https://files.pythonhosted.org/packages/5e/da/bb73274c42cb60decfa61e9eb0c9029da78b3b9af0a9de0309dbc8ff87b6/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237", size = 1974573, upload-time = "2024-07-03T17:01:26.318Z" }, - { url = "https://files.pythonhosted.org/packages/c8/65/41693110fb3552556180460daffdb8bbeefb87fc026fd9aa4b849374015c/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe", size = 2625596, upload-time = "2024-07-03T17:01:28.775Z" }, - { url = "https://files.pythonhosted.org/packages/09/b3/a5a54b47cccd1ab661ed5775235c5e06924753c2d4817737c5667bfa19a8/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e", size = 2099064, upload-time = "2024-07-03T17:01:30.962Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/443a7a6ea54beaba45ff3a59f3d3e6e3004b7460bcfb0be77bcf98719d3b/pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24", size = 1900345, upload-time = "2024-07-03T17:01:33.634Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e6/9aca9ffae60f9cdf0183069de3e271889b628d0fb175913fcb3db5618fb1/pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1", size = 1968252, upload-time = "2024-07-03T17:01:36.291Z" }, - { url = "https://files.pythonhosted.org/packages/46/5e/6c716810ea20a6419188992973a73c2fb4eb99cd382368d0637ddb6d3c99/pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd", size = 2119191, upload-time = "2024-07-03T17:01:38.905Z" }, - { url = "https://files.pythonhosted.org/packages/06/fc/6123b00a9240fbb9ae0babad7a005d51103d9a5d39c957a986f5cdd0c271/pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688", size = 1717788, upload-time = "2024-07-03T17:01:41.329Z" }, - { url = "https://files.pythonhosted.org/packages/d5/36/e61ad5a46607a469e2786f398cd671ebafcd9fb17f09a2359985c7228df5/pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d", size = 1898188, upload-time = "2024-07-03T17:01:44.155Z" }, - { url = "https://files.pythonhosted.org/packages/49/75/40b0e98b658fdba02a693b3bacb4c875a28bba87796c7b13975976597d8c/pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686", size = 1838688, upload-time = "2024-07-03T17:01:46.508Z" }, - { url = "https://files.pythonhosted.org/packages/75/02/d8ba2d4a266591a6a623c68b331b96523d4b62ab82a951794e3ed8907390/pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a", size = 1768409, upload-time = "2024-07-03T17:01:49.013Z" }, - { url = "https://files.pythonhosted.org/packages/91/ae/25ecd9bc4ce4993e99a1a3c9ab111c082630c914260e129572fafed4ecc2/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b", size = 1789317, upload-time = "2024-07-03T17:01:51.78Z" }, - { url = "https://files.pythonhosted.org/packages/7a/80/72057580681cdbe55699c367963d9c661b569a1d39338b4f6239faf36cdc/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19", size = 1771949, upload-time = "2024-07-03T17:01:53.881Z" }, - { url = "https://files.pythonhosted.org/packages/a2/be/d9bbabc55b05019013180f141fcaf3b14dbe15ca7da550e95b60c321009a/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac", size = 1974392, upload-time = "2024-07-03T17:01:56.005Z" }, - { url = "https://files.pythonhosted.org/packages/79/2d/7bcd938c6afb0f40293283f5f09988b61fb0a4f1d180abe7c23a2f665f8e/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703", size = 2625565, upload-time = "2024-07-03T17:01:58.508Z" }, - { url = "https://files.pythonhosted.org/packages/ac/88/ca758e979457096008a4b16a064509028e3e092a1e85a5ed6c18ced8da88/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c", size = 2098784, upload-time = "2024-07-03T17:02:01.13Z" }, - { url = "https://files.pythonhosted.org/packages/eb/de/2fad6d63c3c42e472e985acb12ec45b7f56e42e6f4cd6dfbc5e87ee8678c/pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83", size = 1900198, upload-time = "2024-07-03T17:02:04.348Z" }, - { url = "https://files.pythonhosted.org/packages/fe/50/077c7f35b6488dc369a6d22993af3a37901e198630f38ac43391ca730f5b/pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203", size = 1968005, upload-time = "2024-07-03T17:02:06.737Z" }, - { url = "https://files.pythonhosted.org/packages/5d/1f/f378631574ead46d636b9a04a80ff878b9365d4b361b1905ef1667d4182a/pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0", size = 2118920, upload-time = "2024-07-03T17:02:09.976Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ea/e4943f17df7a3031d709481fe4363d4624ae875a6409aec34c28c9e6cf59/pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e", size = 1717397, upload-time = "2024-07-03T17:02:12.495Z" }, - { url = "https://files.pythonhosted.org/packages/13/63/b95781763e8d84207025071c0cec16d921c0163c7a9033ae4b9a0e020dc7/pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20", size = 1898013, upload-time = "2024-07-03T17:02:15.157Z" }, - { url = "https://files.pythonhosted.org/packages/73/73/0c7265903f66cce39ed7ca939684fba344210cefc91ccc999cfd5b113fd3/pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906", size = 1828190, upload-time = "2024-07-03T17:03:24.111Z" }, - { url = "https://files.pythonhosted.org/packages/27/55/60b8b0e58b49ee3ed36a18562dd7c6bc06a551c390e387af5872a238f2ec/pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94", size = 1715252, upload-time = "2024-07-03T17:03:27.308Z" }, - { url = "https://files.pythonhosted.org/packages/28/3d/d66314bad6bb777a36559195a007b31e916bd9e2c198f7bb8f4ccdceb4fa/pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f", size = 1782641, upload-time = "2024-07-03T17:03:29.777Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f5/f178f4354d0d6c1431a8f9ede71f3c4269ac4dc55d314fdb7555814276dc/pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482", size = 1928788, upload-time = "2024-07-03T17:03:32.365Z" }, - { url = "https://files.pythonhosted.org/packages/9c/51/1f5e27bb194df79e30b593b608c66e881ed481241e2b9ed5bdf86d165480/pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6", size = 1886116, upload-time = "2024-07-03T17:03:35.19Z" }, - { url = "https://files.pythonhosted.org/packages/ac/76/450d9258c58dc7c70b9e3aadf6bebe23ddd99e459c365e2adbde80e238da/pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc", size = 1960125, upload-time = "2024-07-03T17:03:38.093Z" }, - { url = "https://files.pythonhosted.org/packages/dd/9e/0309a7a4bea51771729515e413b3987be0789837de99087f7415e0db1f9b/pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99", size = 2100407, upload-time = "2024-07-03T17:03:40.882Z" }, - { url = "https://files.pythonhosted.org/packages/af/93/06d44e08277b3b818b75bd5f25e879d7693e4b7dd3505fde89916fcc9ca2/pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6", size = 1914966, upload-time = "2024-07-03T17:03:45.039Z" }, + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, ] [[package]] @@ -1035,48 +941,54 @@ wheels = [ [[package]] name = "pyppmd" -version = "1.1.0" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/39/c8/9039c7503577de08a3f4c81e7619583efdc16030da6d1a25268d3dca49c8/pyppmd-1.1.0.tar.gz", hash = "sha256:1d38ce2e4b7eb84b53bc8a52380b94f66ba6c39328b8800b30c2b5bf31693973", size = 1348949, upload-time = "2023-11-05T08:44:32.148Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d7/b3084ff1ac6451ef7dd93d4f7627eeb121a3bed4f8a573a81978a43ddb06/pyppmd-1.2.0.tar.gz", hash = "sha256:cc04af92f1d26831ec96963439dfb27c96467b5452b94436a6af696649a121fd", size = 1351286, upload-time = "2025-05-01T11:37:09.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/10/b19621035862e2ae12a1ba14c5b5c0a0befb27906bc00691642d7bdbdce6/pyppmd-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5cd428715413fe55abf79dc9fc54924ba7e518053e1fc0cbdf80d0d99cf1442", size = 75756, upload-time = "2023-11-05T08:42:12.833Z" }, - { url = "https://files.pythonhosted.org/packages/85/4a/a7c172cd431c4e1ddf9be349dc4bcfea81c2a236d2fe51bbfdcd697af55a/pyppmd-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e96cc43f44b7658be2ea764e7fa99c94cb89164dbb7cdf209178effc2168319", size = 47347, upload-time = "2023-11-05T08:42:15.75Z" }, - { url = "https://files.pythonhosted.org/packages/0d/32/f7357e0412e977ede4d63ba8bf55d014e5ea5b311818b2b0a1fee6d91baa/pyppmd-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd20142869094bceef5ab0b160f4fff790ad1f612313a1e3393a51fc3ba5d57e", size = 46640, upload-time = "2023-11-05T08:42:17.849Z" }, - { url = "https://files.pythonhosted.org/packages/b5/8e/1f416819f0aab17de47b15b72d0e9b05e2bf795c6e28d9f403ac01398b74/pyppmd-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4f9b51e45c11e805e74ea6f6355e98a6423b5bbd92f45aceee24761bdc3d3b8", size = 135666, upload-time = "2023-11-05T08:42:20.611Z" }, - { url = "https://files.pythonhosted.org/packages/73/ac/7d07d3ac6874f235554de392de08e6a369001db43cd6a619af4fbe02fb55/pyppmd-1.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459f85e928fb968d0e34fb6191fd8c4e710012d7d884fa2b317b2e11faac7c59", size = 132892, upload-time = "2023-11-05T08:42:23.006Z" }, - { url = "https://files.pythonhosted.org/packages/09/76/61db4268a439cfba8736b14130d928d199633fab2360a2c5043332a427d2/pyppmd-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f73cf2aaf60477eef17f5497d14b6099d8be9748390ad2b83d1c88214d050c05", size = 138901, upload-time = "2023-11-05T08:42:25.152Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9c/546729489ae07c0d7c2bfe37c69ae1cd3ce35a18ab000480ea4e8f12754f/pyppmd-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2ea3ae0e92c0b5345cd3a4e145e01bbd79c2d95355481ea5d833b5c0cb202a2d", size = 139725, upload-time = "2023-11-05T08:42:27.291Z" }, - { url = "https://files.pythonhosted.org/packages/f7/db/4e734e97541554a389e7adb2a2a5c86ad8ae35c4dafe817b12fdc317de1a/pyppmd-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:775172c740133c0162a01c1a5443d0e312246881cdd6834421b644d89a634b91", size = 131598, upload-time = "2023-11-05T08:42:29.477Z" }, - { url = "https://files.pythonhosted.org/packages/b1/8f/530e47290e07d2fdedfd345fc72af08226ccdd4cc913c2b895a8396c17b6/pyppmd-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:14421030f1d46f69829698bdd960698a3b3df0925e3c470e82cfcdd4446b7bc1", size = 142767, upload-time = "2023-11-05T08:42:32.479Z" }, - { url = "https://files.pythonhosted.org/packages/a5/f9/16e0adfef500b171a96ed3c95f4a4d999f99cc79de3e415146808b19c2fb/pyppmd-1.1.0-cp310-cp310-win32.whl", hash = "sha256:b691264f9962532aca3bba5be848b6370e596d0a2ca722c86df388be08d0568a", size = 41283, upload-time = "2023-11-05T08:42:34.762Z" }, - { url = "https://files.pythonhosted.org/packages/37/8d/c4846ab632e13ead87189f31bcc51fc825c75078d162a4a9dc8aed0a5b97/pyppmd-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:216b0d969a3f06e35fbfef979706d987d105fcb1e37b0b1324f01ee143719c4a", size = 46078, upload-time = "2023-11-05T08:42:36.809Z" }, - { url = "https://files.pythonhosted.org/packages/27/0e/9db5d7c6ca3159aa0f07c0f1d5c59079176e7c57740a61aca62a39661178/pyppmd-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1f8c51044ee4df1b004b10bf6b3c92f95ea86cfe1111210d303dca44a56e4282", size = 75781, upload-time = "2023-11-05T08:42:38.892Z" }, - { url = "https://files.pythonhosted.org/packages/f0/1b/4894b5c71feee76d3dfccf4383b59841f9bfd27aecf912b6542a2ab1e073/pyppmd-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac25b3a13d1ac9b8f0bde46952e10848adc79d932f2b548a6491ef8825ae0045", size = 47370, upload-time = "2023-11-05T08:42:40.913Z" }, - { url = "https://files.pythonhosted.org/packages/50/98/57b2c281e546f682279bd4a2577045d1f6d527c8fa2151a990b2a9bc48c2/pyppmd-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c8d3003eebe6aabe22ba744a38a146ed58a25633420d5da882b049342b7c8036", size = 46633, upload-time = "2023-11-05T08:42:42.742Z" }, - { url = "https://files.pythonhosted.org/packages/06/72/b7e37aa69b7a105bcc119bc171437fbcb104aef2568b68ec8ed21a3fcdd1/pyppmd-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c520656bc12100aa6388df27dd7ac738577f38bf43f4a4bea78e1861e579ea5", size = 138233, upload-time = "2023-11-05T08:42:45.135Z" }, - { url = "https://files.pythonhosted.org/packages/60/73/4f53a3c7730e1cba3f210b35ed6779e0fe302739196f43452664e079c0b5/pyppmd-1.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c2a3e807028159a705951f5cb5d005f94caed11d0984e59cc50506de543e22d", size = 135486, upload-time = "2023-11-05T08:42:47.47Z" }, - { url = "https://files.pythonhosted.org/packages/31/7c/956ebf1f07506bb59e6f13ef068d91f1bec828758d399b455b175b668f6c/pyppmd-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8a2447e69444703e2b273247bfcd4b540ec601780eff07da16344c62d2993d", size = 141183, upload-time = "2023-11-05T08:42:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/73/b4/4863499e012c555f4619dbebc5b83d79818e0161d9b6fb8b1e709fb1d6c7/pyppmd-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b9e0c8053e69cad6a92a0889b3324f567afc75475b4f54727de553ac4fc85780", size = 141752, upload-time = "2023-11-05T08:42:52.179Z" }, - { url = "https://files.pythonhosted.org/packages/b4/cc/44e175222b31f86d0192d1d0d2c46c4bf0e933c9a06a65ff39596ad05666/pyppmd-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5938d256e8d2a2853dc3af8bb58ae6b4a775c46fc891dbe1826a0b3ceb624031", size = 133921, upload-time = "2023-11-05T08:42:54.011Z" }, - { url = "https://files.pythonhosted.org/packages/f1/d9/2f2e222d43ab274909e8dcd16d25cd4cc0245a8d59f93f8d6397cd4dc49f/pyppmd-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1ce5822d8bea920856232ccfb3c26b56b28b6846ea1b0eb3d5cb9592a026649e", size = 145191, upload-time = "2023-11-05T08:42:55.683Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e7/1214571442624e2314ed1ed5ba0081358335fc760fb455c3d8df83b118c6/pyppmd-1.1.0-cp311-cp311-win32.whl", hash = "sha256:2a9e894750f2a52b03e3bc0d7cf004d96c3475a59b1af7e797d808d7d29c9ffe", size = 41286, upload-time = "2023-11-05T08:42:57.204Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7f/d3cc8443bd2b56bc54ea205dcf73d70ef8d4342096ff33fc8719956f45e9/pyppmd-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:969555c72e72fe2b4dd944127521a8f2211caddb5df452bbc2506b5adfac539e", size = 46087, upload-time = "2023-11-05T08:42:58.75Z" }, - { url = "https://files.pythonhosted.org/packages/bf/0b/4c8e3a92c4366a9aa2d801ab4bd7ba72bd1d214da890dd91ab4d73e52878/pyppmd-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d6ef8fd818884e914bc209f7961c9400a4da50d178bba25efcef89f09ec9169", size = 76116, upload-time = "2023-11-05T08:43:00.458Z" }, - { url = "https://files.pythonhosted.org/packages/e1/0b/45fdf5a28c810ed4d3c0cb05ae5346e2972cdbfe89f374b263e07c5b820d/pyppmd-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95f28e2ecf3a9656bd7e766aaa1162b6872b575627f18715f8b046e8617c124a", size = 47633, upload-time = "2023-11-05T08:43:02.488Z" }, - { url = "https://files.pythonhosted.org/packages/56/a4/4aa1d36d98f3786c8b12ac96ac8234d7dc3c2a9e8f5174a5698f424099ec/pyppmd-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:37f3557ea65ee417abcdf5f49d35df00bb9f6f252639cae57aeefcd0dd596133", size = 46704, upload-time = "2023-11-05T08:43:04.264Z" }, - { url = "https://files.pythonhosted.org/packages/d9/70/a49389a6666f670db5ecc7caa37030c9a9abfeea455c387172584551a271/pyppmd-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e84b25d088d7727d50218f57f92127cdb839acd6ec3de670b6680a4cf0b2d2a", size = 139145, upload-time = "2023-11-05T08:43:06.222Z" }, - { url = "https://files.pythonhosted.org/packages/30/4c/f08cdf618744a3cce0da106ecf6e427b24d27b0bb1484afc40b88ca23a39/pyppmd-1.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99ed42891986dac8c2ecf52bddfb777900233d867aa18849dbba6f3335600466", size = 136618, upload-time = "2023-11-05T08:43:08.008Z" }, - { url = "https://files.pythonhosted.org/packages/bb/e0/afc0fb971c893e9e72cc8d70df93c50b3f3ebb12b4bdb21f869b775faf7e/pyppmd-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6fe69b82634488ada75ba07efb90cd5866fa3d64a2c12932b6e8ae207a14e5f", size = 142757, upload-time = "2023-11-05T08:43:09.763Z" }, - { url = "https://files.pythonhosted.org/packages/26/b2/793e92c7a66de0b0b8d777c3c4df3ee5a5bec7fbaf0b69ab7374cefefa43/pyppmd-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:60981ffde1fe6ade750b690b35318c41a1160a8505597fda2c39a74409671217", size = 142749, upload-time = "2023-11-05T08:43:11.579Z" }, - { url = "https://files.pythonhosted.org/packages/5e/6e/a1bf750bc7ed025a06600c65917d02e3c6dea7dfa728746c7251d4910d37/pyppmd-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:46e8240315476f57aac23d71e6de003e122b65feba7c68f4cc46a089a82a7cd4", size = 135033, upload-time = "2023-11-05T08:43:13.332Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ee/4a12a4b1990f1fabb77f9ef94d2cd6c795690eec79ad135b8236dc59dbd2/pyppmd-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0308e2e76ecb4c878a18c2d7a7c61dbca89b4ef138f65d5f5ead139154dcdea", size = 146510, upload-time = "2023-11-05T08:43:15.52Z" }, - { url = "https://files.pythonhosted.org/packages/04/cd/a6571420345315f5340ac10897726303ae07260cb025dc4a60371d1e8b97/pyppmd-1.1.0-cp312-cp312-win32.whl", hash = "sha256:b4fa4c27dc1314d019d921f2aa19e17f99250557e7569eeb70e180558f46af74", size = 41332, upload-time = "2023-11-05T08:43:17.157Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/af77129d671d6adcc6c82e1b0f03f0ad0b70c44ac70ed4c72b5c8952553b/pyppmd-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c269d21e15f4175df27cf00296476097af76941f948734c642d7fb6e85b9b3b9", size = 46193, upload-time = "2023-11-05T08:43:18.79Z" }, - { url = "https://files.pythonhosted.org/packages/6a/e2/1d5fbd6dde1234b635000072c8d1d87c7ed3acf01a3c4aa8082504d58bc5/pyppmd-1.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ad5da9f7592158e6b6b51d7cd15e536d8b23afbb4d22cba4e5744c7e0a3548b1", size = 41505, upload-time = "2023-11-05T08:44:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/24/66/9215c5dda61b3aa3259902a586dacd198b4b0793ab99228734091b5e7fa7/pyppmd-1.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc6543e7d12ef0a1466d291d655e3d6bca59c7336dbb53b62ccdd407822fb52b", size = 44814, upload-time = "2023-11-05T08:44:05.087Z" }, - { url = "https://files.pythonhosted.org/packages/1a/87/cc2aa429688f238ae30f26b8334194a21e25643d3257c9e5b14cccdc578e/pyppmd-1.1.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5e4008a45910e3c8c227f6f240de67eb14454c015dc3d8060fc41e230f395d3", size = 43629, upload-time = "2023-11-05T08:44:07.134Z" }, - { url = "https://files.pythonhosted.org/packages/9f/96/cd3f64f6bdce091ffb6d2c1c23dc91e8b94e312a5d08cd648625555fb69e/pyppmd-1.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9301fa39d1fb0ed09a10b4c5d7f0074113e96a1ead16ba7310bedf95f7ef660c", size = 43911, upload-time = "2023-11-05T08:44:08.975Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ab/02ab90e2dddf2dd55e30e64fa0509627c6e0c86b26503a6df95ae55b1e45/pyppmd-1.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:59521a3c6028da0cb5780ba16880047b00163432a6b975da2f6123adfc1b0be8", size = 42427, upload-time = "2023-11-05T08:44:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/aa/aa/c552da09a126934d8934ca057804c7e33e67118c31fdd1852bed0be191b5/pyppmd-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4a25d8b2a71e0cc6f34475c36450e905586b13d0c88fb28471655c215f370908", size = 76751, upload-time = "2025-05-01T11:35:54.503Z" }, + { url = "https://files.pythonhosted.org/packages/27/76/ee45339169e06d8288aa2016a2c5165a51eb938a6a530b8961d16f7b3640/pyppmd-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc9dd8a6261152591a352d91e5e52c16b81fa760f64c361a7afb24a1f3b5e048", size = 47672, upload-time = "2025-05-01T11:35:56.503Z" }, + { url = "https://files.pythonhosted.org/packages/7c/27/6582c889adc5b71110e7b7fbb850080f0cc62e7867ca84d7b06536da30e3/pyppmd-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2cd2694f43720fa1304c1fa31b8a1e7d80162f045e91569fb93473277c2747b8", size = 47911, upload-time = "2025-05-01T11:35:57.668Z" }, + { url = "https://files.pythonhosted.org/packages/90/88/a31fc66dfa8e5b35ffeb49fc9ba9d07229f7a99dddd2092e281042a74551/pyppmd-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0354919ab0f4065d76c64ad0dc21f14116651a2124cf4915b96c4e76d9caf470", size = 135910, upload-time = "2025-05-01T11:35:59.127Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7b/ba5e6fa06ccb544468235a3f7eb9c9f7ad8bd103be5c2c4686e8adba5ea0/pyppmd-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:416c15576924ff9d2852fbe53d162c946e0466ce79d8a03a058e6f09a54934f0", size = 139010, upload-time = "2025-05-01T11:36:00.464Z" }, + { url = "https://files.pythonhosted.org/packages/74/63/22f37747ec2c6af72b2f5cb89128818cb05ab06c7059a62db40bef862e9a/pyppmd-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dcdd5bf53f562af2a9be76739be69c9de080dfa59a4c4a8bcc4a163f9c5cb53e", size = 139927, upload-time = "2025-05-01T11:36:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/63/e9/d6f9ce0f7d97e09f618d7407ddc775805934bcffae5255297129581995e6/pyppmd-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c67196af6cfcc68e72a8fffbc332d743327bb9323cb7f3709e27185e743c7272", size = 142915, upload-time = "2025-05-01T11:36:03.709Z" }, + { url = "https://files.pythonhosted.org/packages/49/99/381dac48a0dfb71bbcd02731481d1b6c94106309029dac72d9b5944163ee/pyppmd-1.2.0-cp310-cp310-win32.whl", hash = "sha256:d529c78382a2315db22c93e1c831231ee3fd2ad5a352f61496d72474558c6b00", size = 41773, upload-time = "2025-05-01T11:36:04.884Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b9/c6db6a63e94f4735e63a460d13c6b1b9356bac3588f0d92eb75692b491ae/pyppmd-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f19285ae4dd20bb917c4fd177f0911847feb3abada91cec5fd5d9d5f1b9f3e0", size = 46506, upload-time = "2025-05-01T11:36:06.113Z" }, + { url = "https://files.pythonhosted.org/packages/72/a1/eff9e908495dfc57d721327acc3d14793ab8efcb5dfbd38397be63348b86/pyppmd-1.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:30068ed6da301f6ba25219f96d828f3c3a80ca227647571d21c7704301e095e6", size = 44678, upload-time = "2025-05-01T11:36:07.712Z" }, + { url = "https://files.pythonhosted.org/packages/20/09/8f38b6e7224fdb3faf0c1a524bdf72f2135187098bb5f95a4203087562d5/pyppmd-1.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1a5f0b78d68620ffb51c46c34c9e0ec02c40bb68e903e6c3ce02870c528164af", size = 76750, upload-time = "2025-05-01T11:36:09.225Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d2/aac8d12427b5cf4f7f28312a47ccdab7ecead9d880b21280dff98aeff160/pyppmd-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5f1ee49b88fd2e58a144b1ae0da9c2fe0dabc1962531da9475badbed6fba61fc", size = 47674, upload-time = "2025-05-01T11:36:10.346Z" }, + { url = "https://files.pythonhosted.org/packages/02/9b/e603f52f3bac329d3088d85921571792eace2377800591fca5c4d6f38444/pyppmd-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c98697fea3f3baf5ffc759fd41c766d708ff3fba7379776031077527873ce4ac", size = 47911, upload-time = "2025-05-01T11:36:11.399Z" }, + { url = "https://files.pythonhosted.org/packages/97/66/ddaf72369f3f86648095bdebfd1d58cab1ac7ea70ffd991cf794d7b1725b/pyppmd-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a3087d7ee6fc35db0bfecabd1df4615f2a9d58a56af61f5fc18b9ce2b379cbf", size = 138493, upload-time = "2025-05-01T11:36:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/3d/9f/a1034fc7450bdd0f8c44be16c7eb02b0465759055edd7cbff5b3b2e27273/pyppmd-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69fe10feb24a92e673b68aca5d945564232d09e25a4e185899e0c657096ae695", size = 141328, upload-time = "2025-05-01T11:36:13.659Z" }, + { url = "https://files.pythonhosted.org/packages/41/a9/60e9a384efe6721a491d04406751b405a1debfffa7c6e44e54460c8117fc/pyppmd-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aa40c982d1df515cd4cb366d3e1ae95ce22f3c20e6b8b2d31aa492679f7ad78c", size = 141949, upload-time = "2025-05-01T11:36:14.842Z" }, + { url = "https://files.pythonhosted.org/packages/03/73/6c270d95c5fa20b37e4b952f1ae2742a87dca764e4c78e3d7d459a30eb8a/pyppmd-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a5c03dd85da64a237c601dd690d8eb95951b7c2eef91b89e110eb208010c6035", size = 145257, upload-time = "2025-05-01T11:36:16.093Z" }, + { url = "https://files.pythonhosted.org/packages/cd/0d/d7e9e2bd19ef2e35462af4bf072afb5e0b336f1925cba3bb2146fddf0a64/pyppmd-1.2.0-cp311-cp311-win32.whl", hash = "sha256:c577f3dadd514979255e9df6eb89a63409d0e91855bb8c0969ffcd67d5d4f124", size = 41776, upload-time = "2025-05-01T11:36:17.683Z" }, + { url = "https://files.pythonhosted.org/packages/33/bb/beb10ba2ef8311be10716ed8e07da0cfa7fd95fb05b6ec58bf57d586ae7b/pyppmd-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:f29dfb7aaf4b49ebc09d726fcdeabbce1cb21e9cf3a055244bb1384b8b51dd3b", size = 46511, upload-time = "2025-05-01T11:36:18.716Z" }, + { url = "https://files.pythonhosted.org/packages/2d/24/e9f0a85b143fe8f360d14a1b165d2afdd13e000f45c745a06d5124b561ba/pyppmd-1.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:bf26c2def22322135fbaaa3de3c0963062c1835bd43d595478e3a2a674466a1a", size = 44679, upload-time = "2025-05-01T11:36:20.263Z" }, + { url = "https://files.pythonhosted.org/packages/be/ae/0d539436af52af00f2ca529018c83fc4b1c436250390c3d6d988f7292e42/pyppmd-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d28cc9febcf37f2ff08b9e25d472de529e8973119c0a3279603b1915c809dd45", size = 77285, upload-time = "2025-05-01T11:36:21.755Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2a/9fa89827e121e0f4f9daf948c1b5c6bbeb8c8d9f60e17a2d4eac02336e7d/pyppmd-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0f07d5376e1f699d09fbb9139562e5b72a347100aecaa73b688fa08461b3c118", size = 48210, upload-time = "2025-05-01T11:36:23.338Z" }, + { url = "https://files.pythonhosted.org/packages/44/73/f6833332f9c9c94c584c4669d700da6b7ac6291f22c1d043c9ffc22b37e6/pyppmd-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:874f52eae03647b653aa34476f4e23c4c30458245c0eb7aa7fb290940abbd5b9", size = 47912, upload-time = "2025-05-01T11:36:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/c6/cb/08bb9ba89027135e7feed993b5a11beddedb51a00d17ddd51d14cf317414/pyppmd-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abafffb3d5b292924eafd8214ad80487400cf358c4e9dc2ac6c21d2c651c5ee2", size = 139273, upload-time = "2025-05-01T11:36:26.559Z" }, + { url = "https://files.pythonhosted.org/packages/a5/09/c779028af0ed66c14aa07825d4a8a57acc5bba2227db3ad075311e203221/pyppmd-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e955de43991346d4ccb28a74fb4c80cadecf72a6724705301fe1adb569689fe", size = 142718, upload-time = "2025-05-01T11:36:27.762Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c6/0ec94bec55829d415ee3ca5f17f3e37557629cdd111d6673a5d2bc9cbda7/pyppmd-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14ed0846c3bcee506555cd943db950d5787a6ffa1089e05deced010759ef1fe5", size = 142901, upload-time = "2025-05-01T11:36:28.892Z" }, + { url = "https://files.pythonhosted.org/packages/77/4c/34ec83e9337f7a04352739c8dfe57d0f956141c158b7cb06eca0bff19b9c/pyppmd-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3caef2fb93a63d696b21e5ff72cb2955687b5dfcbed1938936334f9f7737fcd3", size = 146480, upload-time = "2025-05-01T11:36:30.155Z" }, + { url = "https://files.pythonhosted.org/packages/a5/1a/76e29b5e3ab9d480c7ab8fa8ff300a4d0286a66d6224b58e057e51ef22e0/pyppmd-1.2.0-cp312-cp312-win32.whl", hash = "sha256:011c813389476e84387599ad4aa834100e888c6608a6e7d6f07ea7cbac8a8e65", size = 41824, upload-time = "2025-05-01T11:36:31.4Z" }, + { url = "https://files.pythonhosted.org/packages/e6/a8/bea53a474da009db35641023d2aaf6979a78164f5de7da1d87a64ea81700/pyppmd-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:42c7c9050b44b713676d255f0c212b8ff5c0463821053960c89292cf6b6221cc", size = 46607, upload-time = "2025-05-01T11:36:32.894Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1e/84109dfddfc2634ee882014ac572a9966373d704dcf3026c47437026fa92/pyppmd-1.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:5768bff11936047613bcb91ee466f21779efc24360bd7953bd338b32da88577a", size = 44747, upload-time = "2025-05-01T11:36:34.033Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/ffb458fde32135f7861f2de152d7bb9c778ce6466e43a4ac845e315d1897/pyppmd-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4aa8ffca1727872923d2673045975bca571eb810cf14a21d048648da5237369b", size = 77284, upload-time = "2025-05-01T11:36:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/fb8de2664cabc12621b6eed4bb9783b41336e72e0f76ebce42e3e9f58728/pyppmd-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6dc00f0ce9f79e1c1c87d9998220a714ab8216873b6c996776b88ab23efe05ac", size = 48212, upload-time = "2025-05-01T11:36:36.574Z" }, + { url = "https://files.pythonhosted.org/packages/da/aa/7f8198de419bff405aa77c444fbf9d300ce86cc4889e91101669439c616d/pyppmd-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d437881763ffd0d19079402f50e7f4aad5895e3cd5312d095edef0b32dac3aef", size = 47912, upload-time = "2025-05-01T11:36:37.695Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d2/6cddd47f7bf94986d75695859aa38d3d7b246d01bab17a9420c0cc4b54f2/pyppmd-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c763f2e3a011d5e96dfa0195f38accce9a14d489725a3d3641a74addbb5b72", size = 139310, upload-time = "2025-05-01T11:36:38.809Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ae/4b0a4fe34f91cce15aa086a3d374ee21f8261445fe935bc835d6d8ba75bb/pyppmd-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38e3835a1951d18dd273000c870a4eb2804c20c400aa3c72231449f300cedf19", size = 142719, upload-time = "2025-05-01T11:36:39.986Z" }, + { url = "https://files.pythonhosted.org/packages/6e/26/fb3fe6b04c0e63454bf1c1d70f5fc628bc2dc7bb3384002e8572733580a6/pyppmd-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c76b8881fc087e70338b1cccd452bd12566206587a0d0d8266ba2833be902194", size = 142799, upload-time = "2025-05-01T11:36:42.081Z" }, + { url = "https://files.pythonhosted.org/packages/a2/65/16a0d31f970435bbc706d1c278d6d00dbf8cc3a1b6426b66fd6e63468b31/pyppmd-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8b43e299310e27af5a4bc505bcc87d10cfc38ae28e5ed1f6a779d811705e5ad6", size = 146355, upload-time = "2025-05-01T11:36:43.607Z" }, + { url = "https://files.pythonhosted.org/packages/07/07/1613cbbef810e7f46a9ded1eb6c3e29ae33a15bcd545581b631a02d77b44/pyppmd-1.2.0-cp313-cp313-win32.whl", hash = "sha256:4b3249256f8a7ecdd36477f277b232a46ee2c8ca280b23faaeacb7f50cab949a", size = 41820, upload-time = "2025-05-01T11:36:45.231Z" }, + { url = "https://files.pythonhosted.org/packages/58/46/4554bc202b4ec0307de72aeb3b7ea6e8585f102d832b2d22ab0e8fc0c3ee/pyppmd-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:625896f5da7038fe7145907b68b0b58f7c13b88ad6bbfdc1c20c05654c17fa6c", size = 46612, upload-time = "2025-05-01T11:36:46.297Z" }, + { url = "https://files.pythonhosted.org/packages/29/ec/5eef76498779a2d31230f3a383a0fa5d7e0cf0e4296362dd70fc7b236b57/pyppmd-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:bec8abbf1edb0300c0a2e4f1bbad6a96154de3e507a2b054a0b1187f1c2e4982", size = 44747, upload-time = "2025-05-01T11:36:47.858Z" }, + { url = "https://files.pythonhosted.org/packages/da/e4/bfb0351c59e3f0f04ee1500b302353508e93d36396b2a2ce843e44eedf72/pyppmd-1.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86e252979fc5ae2492ebb46ed0eed0625a46a2cce519c4616b870eab58d77fb7", size = 44872, upload-time = "2025-05-01T11:37:02.162Z" }, + { url = "https://files.pythonhosted.org/packages/74/c2/31a013c1e19404ca66c71ff0b33b6bd086718eb1a41ac6b7078e954eb3ff/pyppmd-1.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9095d8b098ce8cb5c1e404843a16e5167fb5bdebb4d6aed259d43dd2d73cfca3", size = 43956, upload-time = "2025-05-01T11:37:03.827Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ab/2291aa748951883b2bf727a01e586cd00085251c51844ecf178b909f7b9b/pyppmd-1.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:064307c7fec7bdf3da63f5e28c0f1c5cb5c9bf888c1b268c6df3c131391ab345", size = 44874, upload-time = "2025-05-01T11:37:04.952Z" }, + { url = "https://files.pythonhosted.org/packages/96/98/2ceccb56b96e93256c4dd56d3b89f580702d7696b126dc1492cfdb4887a1/pyppmd-1.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c012c17a53b6d9744e0514b17b0c4169c5f21fb54b4db7a0119bc2d7b3fcc609", size = 43956, upload-time = "2025-05-01T11:37:06.077Z" }, ] [[package]] @@ -1167,58 +1079,158 @@ wheels = [ [[package]] name = "pyzstd" -version = "0.16.1" +version = "0.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/f5/ad944b3fd65ea8f1bbb05459da73489eb331261ed0a3999a18c10429b52e/pyzstd-0.16.1.tar.gz", hash = "sha256:ed50c08233878c155c73ab2622e115cd9e46c0f1c2e2ddd76f2e7ca24933f195", size = 789490, upload-time = "2024-08-04T10:16:05.676Z" } +resolution-markers = [ + "python_full_version < '3.13'", +] +sdist = { url = "https://files.pythonhosted.org/packages/62/14/878fee4072cecb1cc6e061c7d0d933e481389c27de939538c9cc3f18894a/pyzstd-0.16.2.tar.gz", hash = "sha256:179c1a2ea1565abf09c5f2fd72f9ce7c54b2764cf7369e05c0bfd8f1f67f63d2", size = 789505, upload-time = "2024-10-10T20:20:57.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/a9/efad061c5a982f859ba8bf5de565d73567f87ad8bba3364fe28e9a8672b6/pyzstd-0.16.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:637376c8f8cbd0afe1cab613f8c75fd502bd1016bf79d10760a2d5a00905fe62", size = 372191, upload-time = "2024-10-10T20:18:36.828Z" }, + { url = "https://files.pythonhosted.org/packages/b6/36/eb6dcfacb273ca13dfa20d296f27ffd0a6c53677965f868625edf764b71e/pyzstd-0.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e7a7118cbcfa90ca2ddbf9890c7cb582052a9a8cf2b7e2c1bbaf544bee0f16a", size = 295083, upload-time = "2024-10-10T20:18:38.954Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/a7862487402123f221439808ed50915e00cfc8e1df7365af366610176347/pyzstd-0.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a74cb1ba05876179525144511eed3bd5a509b0ab2b10632c1215a85db0834dfd", size = 390166, upload-time = "2024-10-10T20:18:40.29Z" }, + { url = "https://files.pythonhosted.org/packages/b8/52/1e1ab63026d67f18b9841285576d59bb799b838a5de4f852ad9e054674a1/pyzstd-0.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c084dde218ffbf112e507e72cbf626b8f58ce9eb23eec129809e31037984662", size = 472043, upload-time = "2024-10-10T20:18:42.231Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/14c8948b9d16d399ff80504bc404bb091b0eb5339f6fbdad0481da751c09/pyzstd-0.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4646459ebd3d7a59ddbe9312f020bcf7cdd1f059a2ea07051258f7af87a0b31", size = 415258, upload-time = "2024-10-10T20:18:43.948Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3e/e4c7f449af9d19975ff5d333a58330317cf8b05fe4754106c694a29e7c25/pyzstd-0.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14bfc2833cc16d7657fc93259edeeaa793286e5031b86ca5dc861ba49b435fce", size = 413680, upload-time = "2024-10-10T20:18:46.418Z" }, + { url = "https://files.pythonhosted.org/packages/10/09/8918853028cf593c141456b9a42d68420beec3f16a8cc4f1aa5d0b8b0c84/pyzstd-0.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f27d488f19e5bf27d1e8aa1ae72c6c0a910f1e1ffbdf3c763d02ab781295dd27", size = 412630, upload-time = "2024-10-10T20:18:47.729Z" }, + { url = "https://files.pythonhosted.org/packages/47/20/5a4c899530571e0e8ecdcb9dc7e3fc38491d4b342fbd7d8413805c88013b/pyzstd-0.16.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91e134ca968ff7dcfa8b7d433318f01d309b74ee87e0d2bcadc117c08e1c80db", size = 404980, upload-time = "2024-10-10T20:18:49.15Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1d/aeeeebb702d3500a01b5b1029ba1716aea3afa75e8aacb904806b3f1afe5/pyzstd-0.16.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6b5f64cd3963c58b8f886eb6139bb8d164b42a74f8a1bb95d49b4804f4592d61", size = 418000, upload-time = "2024-10-10T20:18:51.535Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0c/66ca36d24ad97af40a8fe8de9e3f316a5f4fd2fb3cab8634a2f7da5571c8/pyzstd-0.16.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0b4a8266871b9e0407f9fd8e8d077c3558cf124d174e6357b523d14f76971009", size = 485576, upload-time = "2024-10-10T20:18:52.847Z" }, + { url = "https://files.pythonhosted.org/packages/39/66/6c1de1347de94aa85f60e854cccae0948bda2eda2351e4d47c8bb0a7cf18/pyzstd-0.16.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1bb19f7acac30727354c25125922aa59f44d82e0e6a751df17d0d93ff6a73853", size = 564542, upload-time = "2024-10-10T20:18:54.172Z" }, + { url = "https://files.pythonhosted.org/packages/6d/46/75365a3ab279d58e69d410ce0a21527e689fa651837227e23dee294d096f/pyzstd-0.16.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3008325b7368e794d66d4d98f2ee1d867ef5afd09fd388646ae02b25343c420d", size = 430619, upload-time = "2024-10-10T20:18:56.55Z" }, + { url = "https://files.pythonhosted.org/packages/0d/62/17bf81d42acbd39bffdea559b6fbd7ec331cd74bc52f249e536fefe5480d/pyzstd-0.16.2-cp310-cp310-win32.whl", hash = "sha256:66f2d5c0bbf5bf32c577aa006197b3525b80b59804450e2c32fbcc2d16e850fd", size = 218224, upload-time = "2024-10-10T20:18:57.82Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b6/281245890df08a567186c6e262c43d68581291cca107c8d7304c37708e46/pyzstd-0.16.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fe5f5459ebe1161095baa7a86d04ab625b35148f6c425df0347ed6c90a2fd58", size = 245012, upload-time = "2024-10-10T20:18:59.148Z" }, + { url = "https://files.pythonhosted.org/packages/10/5a/19d7aec81853f6dc53eabad388227e3beecfaca4788af23b8807a0ea2112/pyzstd-0.16.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c1bdbe7f01c7f37d5cd07be70e32a84010d7dfd6677920c0de04cf7d245b60d", size = 372192, upload-time = "2024-10-10T20:19:00.64Z" }, + { url = "https://files.pythonhosted.org/packages/29/35/2eb025e6a0fff49b5de8bea20e82e4d7d5456e634bf3809123fbe5e5f194/pyzstd-0.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1882a3ceaaf9adc12212d587d150ec5e58cfa9a765463d803d739abbd3ac0f7a", size = 295084, upload-time = "2024-10-10T20:19:01.936Z" }, + { url = "https://files.pythonhosted.org/packages/04/1f/03785d7ff1ce73b9347533f798cb27afa57768e66012f97b18b7b7303158/pyzstd-0.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea46a8b9d60f6a6eba29facba54c0f0d70328586f7ef0da6f57edf7e43db0303", size = 390167, upload-time = "2024-10-10T20:19:03.141Z" }, + { url = "https://files.pythonhosted.org/packages/b7/59/e307622115a2df30075efbd28933dc0ad8f2007c5ba5a3eb49c956de3d56/pyzstd-0.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7865bc06589cdcecdede0deefe3da07809d5b7ad9044c224d7b2a0867256957", size = 472038, upload-time = "2024-10-10T20:19:04.978Z" }, + { url = "https://files.pythonhosted.org/packages/97/21/870fda5454240089e9c37625320580d392b03beaeae4889c67c0a21c4d34/pyzstd-0.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:52f938a65b409c02eb825e8c77fc5ea54508b8fc44b5ce226db03011691ae8cc", size = 415217, upload-time = "2024-10-10T20:19:06.206Z" }, + { url = "https://files.pythonhosted.org/packages/3c/35/b33faeeb9c96fddd08bf7871c9f5c4638c32ad79227155922fd4a63190c5/pyzstd-0.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e97620d3f53a0282947304189deef7ca7f7d0d6dfe15033469dc1c33e779d5e5", size = 413714, upload-time = "2024-10-10T20:19:07.544Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a3/b9058dd43eb52025a2ca78946dcb9ef9d8984acac172a698bcf12712217c/pyzstd-0.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c40e9983d017108670dc8df68ceef14c7c1cf2d19239213274783041d0e64c", size = 412568, upload-time = "2024-10-10T20:19:09.583Z" }, + { url = "https://files.pythonhosted.org/packages/12/31/fe7d462c912f2040775bfa2af4327f9fcebb16e8fa9c3bfa058bc1306722/pyzstd-0.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7cd4b3b2c6161066e4bde6af1cf78ed3acf5d731884dd13fdf31f1db10830080", size = 404988, upload-time = "2024-10-10T20:19:11.371Z" }, + { url = "https://files.pythonhosted.org/packages/48/4c/582aca0e5210436499bce1639a8d15da3f76f8d5827da1aa3eeb2c4e271c/pyzstd-0.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:454f31fd84175bb203c8c424f2255a343fa9bd103461a38d1bf50487c3b89508", size = 417961, upload-time = "2024-10-10T20:19:12.968Z" }, + { url = "https://files.pythonhosted.org/packages/39/e9/54f53641ff10b4ea18d3ba159b03bd07e6ae5a5b7ae01f1329b0c35b8ca2/pyzstd-0.16.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5ef754a93743f08fb0386ce3596780bfba829311b49c8f4107af1a4bcc16935d", size = 485587, upload-time = "2024-10-10T20:19:15Z" }, + { url = "https://files.pythonhosted.org/packages/ce/65/25243b3fea9e52a20bfece1b12e3d3ee3125f17b1735aab08cb9a7a760b4/pyzstd-0.16.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:be81081db9166e10846934f0e3576a263cbe18d81eca06e6a5c23533f8ce0dc6", size = 564543, upload-time = "2024-10-10T20:19:16.751Z" }, + { url = "https://files.pythonhosted.org/packages/3b/3c/324b8ddca55b4b073b413cea3e0587af3c8153ccf7d6d63ed294831f2095/pyzstd-0.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:738bcb2fa1e5f1868986f5030955e64de53157fa1141d01f3a4daf07a1aaf644", size = 430628, upload-time = "2024-10-10T20:19:18.121Z" }, + { url = "https://files.pythonhosted.org/packages/db/a1/aca18925e23bceb833fc742ebaf87aa9d1ba8b178f0332bd108fc8966482/pyzstd-0.16.2-cp311-cp311-win32.whl", hash = "sha256:0ea214c9b97046867d1657d55979021028d583704b30c481a9c165191b08d707", size = 218215, upload-time = "2024-10-10T20:19:19.367Z" }, + { url = "https://files.pythonhosted.org/packages/c0/7f/0f5d1d1891e6c6e14d846d2881a06ab7e5e97cabeb5e1e9e53debec4091a/pyzstd-0.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:c17c0fc02f0e75b0c7cd21f8eaf4c6ce4112333b447d93da1773a5f705b2c178", size = 245055, upload-time = "2024-10-10T20:19:21.656Z" }, + { url = "https://files.pythonhosted.org/packages/28/15/20046759d138733e7150afa6aa15f322022d7587968e2dbd5b36fbf8aa86/pyzstd-0.16.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4081fd841a9efe9ded7290ee7502dbf042c4158b90edfadea3b8a072c8ec4e1", size = 373230, upload-time = "2024-10-10T20:19:23.586Z" }, + { url = "https://files.pythonhosted.org/packages/51/8d/55b536edaecf19d2f8dbd8fbaefd184f2f9cc6b71d241caa6d86bed96813/pyzstd-0.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd3fa45d2aeb65367dd702806b2e779d13f1a3fa2d13d5ec777cfd09de6822de", size = 295699, upload-time = "2024-10-10T20:19:24.887Z" }, + { url = "https://files.pythonhosted.org/packages/11/14/086e7f690154c6f3d9bdb46da26a4cd3c9e0b284346ce10943711ca48c32/pyzstd-0.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8b5f0d2c07994a5180d8259d51df6227a57098774bb0618423d7eb4a7303467", size = 390556, upload-time = "2024-10-10T20:19:26.287Z" }, + { url = "https://files.pythonhosted.org/packages/90/d2/c6d854705d6fa0ad876209b4ba796ab31d85b710d1459029f2cb41085a8d/pyzstd-0.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60c9d25b15c7ae06ed5d516d096a0d8254f9bed4368b370a09cccf191eaab5cb", size = 472928, upload-time = "2024-10-10T20:19:27.739Z" }, + { url = "https://files.pythonhosted.org/packages/aa/38/f97dd871e446adc834349caa605dbaf5bac86763a255f62c809cc2459c85/pyzstd-0.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29acf31ce37254f6cad08deb24b9d9ba954f426fa08f8fae4ab4fdc51a03f4ae", size = 416057, upload-time = "2024-10-10T20:19:29.097Z" }, + { url = "https://files.pythonhosted.org/packages/53/be/0c5ad7bf29dc890f6a3303760b9802aeeafa4e3ffb598de625f501986bfe/pyzstd-0.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec77612a17697a9f7cf6634ffcee616eba9b997712fdd896e77fd19ab3a0618", size = 414613, upload-time = "2024-10-10T20:19:30.474Z" }, + { url = "https://files.pythonhosted.org/packages/1f/1a/d3a1edcd59e2f62a35ac6257d2b86a2c872ae9a8e925380620a8db0d9a9a/pyzstd-0.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:313ea4974be93be12c9a640ab40f0fc50a023178aae004a8901507b74f190173", size = 413236, upload-time = "2024-10-10T20:19:31.8Z" }, + { url = "https://files.pythonhosted.org/packages/f2/8d/912430c2310466c14a89a5a529b72eddef7e73fa733806dbe0b030cf3495/pyzstd-0.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e91acdefc8c2c6c3b8d5b1b5fe837dce4e591ecb7c0a2a50186f552e57d11203", size = 405536, upload-time = "2024-10-10T20:19:34.005Z" }, + { url = "https://files.pythonhosted.org/packages/9e/83/4edb419a13b9d1e1debc01e88084eba93a5f7c10ef198da11f6782857c73/pyzstd-0.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:929bd91a403539e72b5b5cb97f725ac4acafe692ccf52f075e20cd9bf6e5493d", size = 419145, upload-time = "2024-10-10T20:19:35.539Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/62a169eddc37aefac480ee3b3318c221f6731e1e342dafd9e05b7fdaa7c5/pyzstd-0.16.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:740837a379aa32d110911ebcbbc524f9a9b145355737527543a884bd8777ca4f", size = 487157, upload-time = "2024-10-10T20:19:36.881Z" }, + { url = "https://files.pythonhosted.org/packages/57/9d/5949f2a0144d1f99fab7914f854b582d2784c73139cc190e603e4d6b7b37/pyzstd-0.16.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:adfc0e80dd157e6d1e0b0112c8ecc4b58a7a23760bd9623d74122ef637cfbdb6", size = 565918, upload-time = "2024-10-10T20:19:38.624Z" }, + { url = "https://files.pythonhosted.org/packages/de/ce/647b9c7602ac477c9e62cf9399810f72bb5dba8f508e7cdf8be1d260e6f9/pyzstd-0.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:79b183beae1c080ad3dca39019e49b7785391947f9aab68893ad85d27828c6e7", size = 431373, upload-time = "2024-10-10T20:19:39.89Z" }, + { url = "https://files.pythonhosted.org/packages/8b/fb/4141e3d4549eea26e5a59ec723eade271980816cb2ed7613df855baa672f/pyzstd-0.16.2-cp312-cp312-win32.whl", hash = "sha256:b8d00631a3c466bc313847fab2a01f6b73b3165de0886fb03210e08567ae3a89", size = 218541, upload-time = "2024-10-10T20:19:41.215Z" }, + { url = "https://files.pythonhosted.org/packages/51/b9/e1373b179129c2095d70bd1df02a51d388f4c7e4ecb62acb4e5e9570269b/pyzstd-0.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:c0d43764e9a60607f35d8cb3e60df772a678935ab0e02e2804d4147377f4942c", size = 245320, upload-time = "2024-10-10T20:19:42.911Z" }, + { url = "https://files.pythonhosted.org/packages/66/10/cc7c764c7673f1af1728abdcf58e58f88ef5d44ab4500677a2b7b4c01e7d/pyzstd-0.16.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3ae9ae7ad730562810912d7ecaf1fff5eaf4c726f4b4dfe04784ed5f06d7b91f", size = 373223, upload-time = "2024-10-10T20:19:44.106Z" }, + { url = "https://files.pythonhosted.org/packages/3f/a7/bcaf7d635ee929dd4d08ae1c35101892db56a11542471eecfbf46b9dd988/pyzstd-0.16.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2ce8d3c213f76a564420f3d0137066ac007ce9fb4e156b989835caef12b367a7", size = 295701, upload-time = "2024-10-10T20:19:45.527Z" }, + { url = "https://files.pythonhosted.org/packages/93/49/a604113a2f3135b29371a894c0faad22d7ea3f7b58f38d77baad8a817483/pyzstd-0.16.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2c14dac23c865e2d78cebd9087e148674b7154f633afd4709b4cd1520b99a61", size = 392395, upload-time = "2024-10-10T20:19:48.319Z" }, + { url = "https://files.pythonhosted.org/packages/b0/38/886ecf3ebb13a4b6e3ee85f448f54eef37a5ae2b453bd9d5d9edc909e119/pyzstd-0.16.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4527969d66a943e36ef374eda847e918077de032d58b5df84d98ffd717b6fa77", size = 474523, upload-time = "2024-10-10T20:19:49.54Z" }, + { url = "https://files.pythonhosted.org/packages/14/98/121da6ac072c00090c218b4888ef00ead15979f09a657d9a5ff770d6bb17/pyzstd-0.16.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd8256149b88e657e99f31e6d4b114c8ff2935951f1d8bb8e1fe501b224999c0", size = 417974, upload-time = "2024-10-10T20:19:50.886Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ba/56652a67c0bcfaceb2945e5f07d5aa21af86e07cf33d1ae47bb3529a56c3/pyzstd-0.16.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bd1f1822d65c9054bf36d35307bf8ed4aa2d2d6827431761a813628ff671b1d", size = 414587, upload-time = "2024-10-10T20:19:53.896Z" }, + { url = "https://files.pythonhosted.org/packages/cc/30/cab6f45101f0113ced609ef65482aedd276e0f022d9f25a327d4284142f5/pyzstd-0.16.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6733f4d373ec9ad2c1976cf06f973a3324c1f9abe236d114d6bb91165a397d", size = 415071, upload-time = "2024-10-10T20:19:55.261Z" }, + { url = "https://files.pythonhosted.org/packages/6d/44/2187fc8a46662926943aeb16d639dd4f3d06267c7e8abb2c6f97700ab11c/pyzstd-0.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7bec165ab6524663f00b69bfefd13a46a69fed3015754abaf81b103ec73d92c6", size = 407835, upload-time = "2024-10-10T20:19:56.798Z" }, + { url = "https://files.pythonhosted.org/packages/de/d5/6edca97d5453cba820d2ad5630e6ec1fcfad66f69af5ad7d6c688ea301be/pyzstd-0.16.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e4460fa6949aac6528a1ad0de8871079600b12b3ef4db49316306786a3598321", size = 421755, upload-time = "2024-10-10T20:19:58.132Z" }, + { url = "https://files.pythonhosted.org/packages/54/c1/1a0339e014ed97f4e6fd9166b0409ceda8f32e28e8ecda70fd7bb0915566/pyzstd-0.16.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75df79ea0315c97d88337953a17daa44023dbf6389f8151903d371513f503e3c", size = 489174, upload-time = "2024-10-10T20:19:59.51Z" }, + { url = "https://files.pythonhosted.org/packages/07/01/c65f2c9f0b902b33efcb0bdf3cbd07fc828fda6ff6333189eb71cf7acc60/pyzstd-0.16.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:93e1d45f4a196afb6f18682c79bdd5399277ead105b67f30b35c04c207966071", size = 573025, upload-time = "2024-10-10T20:20:01.009Z" }, + { url = "https://files.pythonhosted.org/packages/a7/54/7ab9cc54171b7f8bb97cfd1c1aa7fcb706a4babeb629732529d8111bc4e6/pyzstd-0.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:075e18b871f38a503b5d23e40a661adfc750bd4bd0bb8b208c1e290f3ceb8fa2", size = 429582, upload-time = "2024-10-10T20:20:02.972Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a5/f9c950bb378dd1335bc4cc56444ec2ab40b1dab085c5798c5d16a9bf9d0b/pyzstd-0.16.2-cp313-cp313-win32.whl", hash = "sha256:9e4295eb299f8d87e3487852bca033d30332033272a801ca8130e934475e07a9", size = 218544, upload-time = "2024-10-10T20:20:04.28Z" }, + { url = "https://files.pythonhosted.org/packages/9a/df/a15b9a8a59cd9908ae2b70bce2cb4ac3e2d7da11414ee0d0ceb46e4d0439/pyzstd-0.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:18deedc70f858f4cf574e59f305d2a0678e54db2751a33dba9f481f91bc71c28", size = 245313, upload-time = "2024-10-10T20:20:05.656Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ad/c09fb722c12a82b826c97efc50a919e229bfbaf644f5a140adcd71941473/pyzstd-0.16.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b631117b97a42ff6dfd0ffc885a92fff462d7c34766b28383c57b996f863338", size = 364187, upload-time = "2024-10-10T20:20:32.303Z" }, + { url = "https://files.pythonhosted.org/packages/57/f9/93175fe72f85fb675fe04abca296fe583112a25d0ec7faa026288d9463c2/pyzstd-0.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:56493a3fbe1b651a02102dd0902b0aa2377a732ff3544fb6fb3f114ca18db52f", size = 279825, upload-time = "2024-10-10T20:20:34.538Z" }, + { url = "https://files.pythonhosted.org/packages/8a/de/0b40acf76d7ed1f7975877535e004de85ec2e869632754b5d4d389258b8a/pyzstd-0.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1eae9bdba4a1e5d3181331f403114ff5b8ce0f4b569f48eba2b9beb2deef1e4", size = 321313, upload-time = "2024-10-10T20:20:36.265Z" }, + { url = "https://files.pythonhosted.org/packages/41/5e/00102bacd1a7c957c88098f3ae2cdac17842ac0f94d2e685ff5b75a05730/pyzstd-0.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1be6972391c8aeecc7e61feb96ffc8e77a401bcba6ed994e7171330c45a1948", size = 344376, upload-time = "2024-10-10T20:20:38.972Z" }, + { url = "https://files.pythonhosted.org/packages/a3/95/27a7da3dbd4460cd9432bdc22d9d5f8ec77c86275d069020fa74ea280f7f/pyzstd-0.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:761439d687e3a5687c2ff5c6a1190e1601362a4a3e8c6c82ff89719d51d73e19", size = 328591, upload-time = "2024-10-10T20:20:40.556Z" }, + { url = "https://files.pythonhosted.org/packages/c2/03/8f4d5fd45f6bfad66d67cdf583492a9f52a21049f60e6b36a7e9f8aa7adc/pyzstd-0.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f5fbdb8cf31b60b2dc586fecb9b73e2f172c21a0b320ed275f7b8d8a866d9003", size = 240786, upload-time = "2024-10-10T20:20:41.924Z" }, +] + +[[package]] +name = "pyzstd" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/a2/54d860ccbd07e3c67e4d0321d1c29fc7963ac82cf801a078debfc4ef7c15/pyzstd-0.17.0.tar.gz", hash = "sha256:d84271f8baa66c419204c1dd115a4dec8b266f8a2921da21b81764fa208c1db6", size = 1212160, upload-time = "2025-05-10T14:14:49.764Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/f9/6428560d9be40f5d9c608508558688d5395c942da54087dfcd0308fc8d78/pyzstd-0.16.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0cff110d121598f9eb638ce15393fece65bb5fac9a9d38c60fc5cb1ac8631465", size = 372187, upload-time = "2024-08-04T10:14:02.458Z" }, - { url = "https://files.pythonhosted.org/packages/66/75/4d8b6db87c9a47272f096e00bcc670b2aa1475abf5043082be1614fbc9e3/pyzstd-0.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:acbf3d01f79be0bd284ab316e33d6a3fceab478a932ce93de7275d7d9547b9be", size = 295081, upload-time = "2024-08-04T10:14:04.382Z" }, - { url = "https://files.pythonhosted.org/packages/39/cc/42368724285140502076e219a79b59c53c1634e5da696a290961153a40a5/pyzstd-0.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1d26304c41cc07a87b1b85f4bf61a0f853368e0c00bb700dc7245971dedd53", size = 390262, upload-time = "2024-08-04T10:14:06.192Z" }, - { url = "https://files.pythonhosted.org/packages/81/74/6b283b97c57a23317d3144000d876009aacc8c14502f0c985b01406d7dc1/pyzstd-0.16.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7507175f8d3f48358e28001a19242d3d4df819b6cd4cbc4f0fbe6f9dee9427", size = 472140, upload-time = "2024-08-04T10:14:07.259Z" }, - { url = "https://files.pythonhosted.org/packages/b3/e6/9d5e87184dc522d4fe6ccf390526ca0000210edc9819ec46c10b322d51d6/pyzstd-0.16.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd62933e3a11f7dd6c892fa38c67e7ba45de17cae08f1355bf07b31e631a36f3", size = 415356, upload-time = "2024-08-04T10:14:09.016Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/33d336971c1aa28a41f8196517d613ee16101e30ee7609f643302a3010cd/pyzstd-0.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4725fb00bf06bd674f73f37cb168dd73ca67e68287207fece340e7425f0754d", size = 413778, upload-time = "2024-08-04T10:14:10.236Z" }, - { url = "https://files.pythonhosted.org/packages/0f/22/d0035bcf8b82f42ab88c401c653d050312b1c8ec212d8c5f8cc41127c405/pyzstd-0.16.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9865ffbff114ad4411c9794deb1cbe57a03902f82a2671c23929a2628fd70bbc", size = 412725, upload-time = "2024-08-04T10:14:11.717Z" }, - { url = "https://files.pythonhosted.org/packages/d4/dc/60280702bc2e87f7735dcc54e590ebb4384ffb1d3f63e0364cf271d92bc2/pyzstd-0.16.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:65fc3e12ad4d3ddc1f408e31ad2b70e110bbb7f835e4737f0f7b99ed1ff110cd", size = 405080, upload-time = "2024-08-04T10:14:13.192Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4a/7d17078d2ff1f4025ac897ef79f7f900f0b6727f21a46cbb94aea1a9e3e9/pyzstd-0.16.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:397ca9ea892fece84fbbc5847ce46d16ee03501de3bbc6fb1f9b69bb14fe47a3", size = 418098, upload-time = "2024-08-04T10:14:14.907Z" }, - { url = "https://files.pythonhosted.org/packages/bc/96/ecc300ba3d6d90930c41b8a0baf655b872f214a69ec2c0101c0e496a2b2b/pyzstd-0.16.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:83e770056823f8add3be33599219aa962c36f60eff24fa815579bc65bb053499", size = 485674, upload-time = "2024-08-04T10:14:16.297Z" }, - { url = "https://files.pythonhosted.org/packages/83/62/ec883de85d2cfbd0f41347007c2d870bf1bdcd9d1fc5084939932ef9dd53/pyzstd-0.16.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f949a5375ca8a546059193400b2e7c70f1a10de58bd87d35bdc31c6230e47ab0", size = 564640, upload-time = "2024-08-04T10:14:17.568Z" }, - { url = "https://files.pythonhosted.org/packages/36/68/b42b53200300510d35c7ceb5823fa235e462f135b6a9877e279684e670d4/pyzstd-0.16.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:55e6dd2667a58ca92924f7ced5ac2c53ed26e07c453cfbde50693bf58c4c7b5b", size = 430714, upload-time = "2024-08-04T10:14:19.17Z" }, - { url = "https://files.pythonhosted.org/packages/e1/98/67a1531f67b7a5b5dd116fa679cbcb6bd5c797bcb7ff2d4669501449d826/pyzstd-0.16.1-cp310-cp310-win32.whl", hash = "sha256:c088b57288a8e1818c032ed7e3e3e573b3fe8fad698d02740a1583f55458a73f", size = 218301, upload-time = "2024-08-04T10:14:20.342Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d6/00c9e958e05cf0a6dd044a4632908908dbf07c4a5e624aa279ba8987552d/pyzstd-0.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:089f3d04430b1044fccedbd4e88bd5429cd1220cf523b8841ead0127d8eedd9f", size = 244538, upload-time = "2024-08-04T10:14:21.976Z" }, - { url = "https://files.pythonhosted.org/packages/4d/1b/bbd046b7e108b203886f37cc3776bf054ff1b793f15791d488024068593c/pyzstd-0.16.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7bb570705a39e2a78619e6134a68be00ccd04398d782827180c0d1df79fc88c1", size = 372188, upload-time = "2024-08-04T10:14:23.112Z" }, - { url = "https://files.pythonhosted.org/packages/71/f7/acc59d542d0702aa867caf15078ed2f3de90a77d28bef9089f646bc1aee3/pyzstd-0.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5633a0e9ac780a5577fc5dee3d6d05b8edf2f3d646ffe2c71e065d62a1b538c", size = 295081, upload-time = "2024-08-04T10:14:24.681Z" }, - { url = "https://files.pythonhosted.org/packages/58/a1/5528d90f9fa474a67993f2ee359027ef45fd42bd8953d8266562b6c9afa1/pyzstd-0.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61450162fb86504d16c00558976a4864ae12537e362f7346a0a79594ec2eb491", size = 390261, upload-time = "2024-08-04T10:14:25.82Z" }, - { url = "https://files.pythonhosted.org/packages/3e/00/295133a4438c4e25eb733ca5dc1f1b73e1badfca59a365f5b681fee48d21/pyzstd-0.16.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd3d79a74f863ec277ee3297b43f30178aa1a014eba54c286ea48f21248e525e", size = 472132, upload-time = "2024-08-04T10:14:27.11Z" }, - { url = "https://files.pythonhosted.org/packages/fb/03/49b2e4cc593d9ad233903082a05b17353646be23934526c58e01013b557a/pyzstd-0.16.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ddb50c2767ebf411f2b28e698d61d1671c87e943dac81b2a6e89529052c8ad", size = 415314, upload-time = "2024-08-04T10:14:28.564Z" }, - { url = "https://files.pythonhosted.org/packages/ee/72/9eade0d51a157e7496ff965a5243173be1aef6981389208e58eb70edfb39/pyzstd-0.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf0dec2978f9bc622c4daa48dd286f3f7e6ab196b1e17c46437abb6d4a968201", size = 413807, upload-time = "2024-08-04T10:14:29.729Z" }, - { url = "https://files.pythonhosted.org/packages/6f/96/7f30454efb380f14540fbb220643a73baccde401f683918593addb456344/pyzstd-0.16.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64ae91c0c19160cc0b95d33a5802e708ab15f11213f8043906d484b6062a80b3", size = 412663, upload-time = "2024-08-04T10:14:31.371Z" }, - { url = "https://files.pythonhosted.org/packages/95/ee/62a8bb6348ccac3a2245b44e3a869ca9bd35cf0471a891799c53c595e84a/pyzstd-0.16.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9175bf699ec234189dd5549b4ededc676b66010e2eef5b3170501a17d765cf5", size = 405085, upload-time = "2024-08-04T10:14:32.542Z" }, - { url = "https://files.pythonhosted.org/packages/f2/17/495e6c567a832bc31b96d875ce7b20255e5c32e67910e8842475858300d4/pyzstd-0.16.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cdedcddd851139605b0dbc9b9ed5767052f67c02fa98c66b0a0bd4c1bce0ba49", size = 418062, upload-time = "2024-08-04T10:14:34.08Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2b/62d92e3a54f62b8f65ac6b3179c489bcb7594edf2ce677b3fb48d3aa72d1/pyzstd-0.16.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:efeac4bf8a12cc0a1284164e77cca85727f8a5ec20328cef2e5c72f8eabf7630", size = 485685, upload-time = "2024-08-04T10:14:35.589Z" }, - { url = "https://files.pythonhosted.org/packages/48/91/53450b12dde525853beecfff44d4fb6953be59cce88b3a338b89f5953f77/pyzstd-0.16.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b867f620b7402e0befa4b5e7eaa79693be099a52304f31bfc1006cdc915d21c7", size = 564644, upload-time = "2024-08-04T10:14:37.483Z" }, - { url = "https://files.pythonhosted.org/packages/44/7d/4742635d291c8626c5574567f0f5ff3d78ae2a5805f6605c34fe0d795fa2/pyzstd-0.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4d9f8aa524f99f593ebf38639e6d066984b0f9ed084d45ee8877761d1ee6aa48", size = 430722, upload-time = "2024-08-04T10:14:39.317Z" }, - { url = "https://files.pythonhosted.org/packages/79/21/3d72c0d2252ff379f3f608b9bc144e22b86dc6e3490b6e9dcc537bc582c4/pyzstd-0.16.1-cp311-cp311-win32.whl", hash = "sha256:a4f2f1bd58361e4994e0fed4223038554bdb61644b2449f50f8c2960a8aeffc4", size = 218307, upload-time = "2024-08-04T10:14:40.454Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c4/31b8c89ce49fde36cc7555e2fdc54f5a285e6cce7230e3e4400741933cde/pyzstd-0.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:81567ffe7f5ba6d6612399a82191448ba4f7780c96f2643bea36403a49462e0b", size = 244562, upload-time = "2024-08-04T10:14:42.135Z" }, - { url = "https://files.pythonhosted.org/packages/62/8b/c100bcb0108b8330801cac1b7c76d545408186de43d0a3afa4edbc6bd6aa/pyzstd-0.16.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bb26734a5cda4b5e58b33c5fe20aee697fb9ad8dd72999bc71d7df09783f44db", size = 373080, upload-time = "2024-08-04T10:14:43.242Z" }, - { url = "https://files.pythonhosted.org/packages/12/9c/f51e6136d731422cccdf071fc0e2a30f1ef50ccfdf3b24ce54a8ab76c704/pyzstd-0.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b73e9d8ae8eca8dd600d54408584b625503761ad6b0e481e47e270a19e968141", size = 295697, upload-time = "2024-08-04T10:14:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/ef/ce538901fbae149a2ba8cc7ffd779d53940a2945b072b377aaf4e6e7a9a9/pyzstd-0.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b8af1f24361728cb0abeb447204015b2af016bfaf61d55b7c7bc44edc50348b", size = 390652, upload-time = "2024-08-04T10:14:45.506Z" }, - { url = "https://files.pythonhosted.org/packages/ad/d2/f091c42db2b3d5e9374155a26ef36d832ef401ee58c9c049dc1e9d7b785f/pyzstd-0.16.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5faf5894b58f38491ecb458e6f4032ae0bbebea64dfeff86abc6c6176829ac3", size = 473024, upload-time = "2024-08-04T10:14:46.983Z" }, - { url = "https://files.pythonhosted.org/packages/ac/35/3424762cfbaf1ddc28ac6ea5fe9d9059930c71a366af0ae7bc3a9f81964c/pyzstd-0.16.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:748ea21376016b77f93eb6e5d3fdf158620a27d36d2a05cb319f3e7b8b1943a5", size = 416155, upload-time = "2024-08-04T10:14:48.224Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a3/c887dd01759325b0aca49501e2bc523db2e731e9375afe186d2363c75000/pyzstd-0.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb49c7854c6c56d9d41abdcd970b5fec2681a6a74f390b6f8f8fe9d1ca1f8530", size = 414707, upload-time = "2024-08-04T10:14:49.474Z" }, - { url = "https://files.pythonhosted.org/packages/71/03/5a39ec1751fe7c5e80853dee28d27e3acb930766be4b1c35f23199093a92/pyzstd-0.16.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ea4cbeb5fa722222e8607ed22eab7723dfe8f502cbdaaab0989fc47f2fe4e6", size = 413333, upload-time = "2024-08-04T10:14:50.69Z" }, - { url = "https://files.pythonhosted.org/packages/37/6c/59d6b85ef68ef6716c806b21cee97b1015055e6a13a3ae7c1e94be0afbd3/pyzstd-0.16.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c78ca31b0d83f77ab6ff041808304f51672f925683ffc3a1a866469f1678fc10", size = 405633, upload-time = "2024-08-04T10:14:51.841Z" }, - { url = "https://files.pythonhosted.org/packages/c0/2e/097801ff5a9d4867e5bfb10a4b9decf97a5b9aefaf6c828c16b323fcb5a1/pyzstd-0.16.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:deea37b1618f31fd2618be0aad42bb5bafcdddc24df9fc18c71071314239e3a2", size = 419242, upload-time = "2024-08-04T10:14:53.562Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ce/e93cf06b1ffe089bb791e818ac5b92adb9745b25dbde3979ec6dfc26d2a4/pyzstd-0.16.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:aadbab6d6b79bd37697c3de28d4c2cbac3545ae9622be2f86ae5e426c6e1b192", size = 487256, upload-time = "2024-08-04T10:14:54.626Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f4/04c1adfc7c2328fe55faa87d058391822165b0f8225a01f5672ae5d2d999/pyzstd-0.16.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3b23295a6aedc71e5318b7e490f2ed1ea3fda6b31f2b5957c8da49a5aac7aa81", size = 566017, upload-time = "2024-08-04T10:14:56.412Z" }, - { url = "https://files.pythonhosted.org/packages/55/76/49a0e65b1c3b63a36b4dd97b84636ca3c0c990fd967974adda89b5b6deba/pyzstd-0.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f0a685bea6ba4e965d0de77cda3e380efeb144bb4fa0eff362626b4cdec71814", size = 431464, upload-time = "2024-08-04T10:14:57.562Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dd/d0af14d24e4ebd327e3e4e0a3220877188fec7788c229ffb60772de27533/pyzstd-0.16.1-cp312-cp312-win32.whl", hash = "sha256:ad8686ae57a59432860907e4c62d4b08b98d2330a129928145d797eda118da7b", size = 218653, upload-time = "2024-08-04T10:14:58.721Z" }, - { url = "https://files.pythonhosted.org/packages/44/ce/5436fee8b24b5007727b4bd8e50a4cb3966af6d26c21ec13d32d2a958f8a/pyzstd-0.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:53ae4ac03c286896b2a6741c9069afd80e432526d267f900420d8083f8ab1f78", size = 244741, upload-time = "2024-08-04T10:14:59.824Z" }, - { url = "https://files.pythonhosted.org/packages/65/a0/ef3b895df1502578402575ac4faf363b308f89e07393d8abc509b67e6ce2/pyzstd-0.16.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cf08a0fa9af8d690a41b9b7db6b8ae174ba2ac42b5463993c2cd3d144a094644", size = 364184, upload-time = "2024-08-04T10:15:40.098Z" }, - { url = "https://files.pythonhosted.org/packages/60/01/be74ef3c611474dc74032825900c8a16f1a0f6be10d9f116a00ca172c246/pyzstd-0.16.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:65683cb63d631b159e02738376987c26106b37a1345105c52067441e6259cf87", size = 279821, upload-time = "2024-08-04T10:15:42.527Z" }, - { url = "https://files.pythonhosted.org/packages/68/d9/765594ec72da9299abd07cd41fe4ec342f8d342146344b49196ea28b4d30/pyzstd-0.16.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc09abfd5e281dba33a1cfdc653ece69fc239ad2c6cebd99506facbcb2669c91", size = 321407, upload-time = "2024-08-04T10:15:43.711Z" }, - { url = "https://files.pythonhosted.org/packages/48/60/5adb3b211c51840b1c0b35d293d01130d8a2e21f6ab551eef23b855e2c91/pyzstd-0.16.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46feda6257df4cde7dda55811851c2096dea7b38dcd601099acb95d7acdc795f", size = 344471, upload-time = "2024-08-04T10:15:45.12Z" }, - { url = "https://files.pythonhosted.org/packages/c6/7b/d44e19dd087ef041e1f40a4744027bb687f84254a81c47bda3bb5dda2a76/pyzstd-0.16.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca952ce3388b5f7ee78931733ec41c8939482b466882e41d79a9a8c1387dd398", size = 328684, upload-time = "2024-08-04T10:15:46.256Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d9/c4a0df6313b8e4f058ac1ab1a0de028db185689df565d15a8405c99e2019/pyzstd-0.16.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dc0e4d4c832adcd3c25a5d5b5bf0aa05bc25a279b8e8356eb2b95975b2a67fa0", size = 240290, upload-time = "2024-08-04T10:15:47.427Z" }, + { url = "https://files.pythonhosted.org/packages/ea/4f/fb1528fb8cc5c499d7d62953c6d0bce5e96260482abfba883f625c14d168/pyzstd-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ac857abb4c4daea71f134e74af7fe16bcfeec40911d13cf9128ddc600d46d92", size = 377826, upload-time = "2025-05-10T14:12:30.195Z" }, + { url = "https://files.pythonhosted.org/packages/f3/60/eedb75628f905263baf4c552dc8255912c43f70784c8b18ef9dd52b186f6/pyzstd-0.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d84e8d1cbecd3b661febf5ca8ce12c5e112cfeb8401ceedfb84ab44365298ac", size = 297580, upload-time = "2025-05-10T14:12:32.254Z" }, + { url = "https://files.pythonhosted.org/packages/82/32/b7e776da4724c740e6a186e639b57ff0cd0ac23fac14e5c55cbd4bfcbd00/pyzstd-0.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f829fa1e7daac2e45b46656bdee13923150f329e53554aeaef75cceec706dd8c", size = 443135, upload-time = "2025-05-10T14:12:34.084Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0b/3223f74d7b09122a695eebb861d7d7020f351b0610065db53d7c6981e592/pyzstd-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:994de7a13bb683c190a1b2a0fb99fe0c542126946f0345360582d7d5e8ce8cda", size = 390643, upload-time = "2025-05-10T14:12:36.052Z" }, + { url = "https://files.pythonhosted.org/packages/32/44/c98f10f62cf69d261ed796a2affe1c4ee5bedc05b9690a4c870bc2a74589/pyzstd-0.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3eb213a22823e2155aa252d9093c62ac12d7a9d698a4b37c5613f99cb9de327", size = 478067, upload-time = "2025-05-10T14:12:37.405Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ec/78634376cec5de9e5648c92ca13efa350cab42acb48c72904652ac8a6b3e/pyzstd-0.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c451cfa31e70860334cc7dffe46e5178de1756642d972bc3a570fc6768673868", size = 421189, upload-time = "2025-05-10T14:12:38.728Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d4/e7fd4b0bf3cb5d792e373c0002ac05b7b55ee8349dd80eb1c99c8d167973/pyzstd-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d66dc6f15249625e537ea4e5e64c195f50182556c3731f260b13c775b7888d6b", size = 412870, upload-time = "2025-05-10T14:12:40.038Z" }, + { url = "https://files.pythonhosted.org/packages/ea/65/1a5a8cb348349cef27326db169c61aa16f74cc8bc873b02ee1f8c0094b0e/pyzstd-0.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:308d4888083913fac2b7b6f4a88f67c0773d66db37e6060971c3f173cfa92d1e", size = 415555, upload-time = "2025-05-10T14:12:41.766Z" }, + { url = "https://files.pythonhosted.org/packages/8c/52/12c9402dce3dac85ae1e53bf5623deeb371221f1aa810c40f8b51f06ae40/pyzstd-0.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a3b636f37af9de52efb7dd2d2f15deaeabdeeacf8e69c29bf3e7e731931e6d66", size = 445346, upload-time = "2025-05-10T14:12:43.121Z" }, + { url = "https://files.pythonhosted.org/packages/fa/93/1d1bf5f73fc5b891d880ff96f6e266a1fe84c0be5beffe872afdd11a5e6a/pyzstd-0.17.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4c07391c67b496d851b18aa29ff552a552438187900965df57f64d5cf2100c40", size = 518741, upload-time = "2025-05-10T14:12:44.854Z" }, + { url = "https://files.pythonhosted.org/packages/fa/88/c9882b07c9010014161b39d28784f793219f89c86c4ba7748b6b71818f43/pyzstd-0.17.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e8bd12a13313ffa27347d7abe20840dcd2092852ab835a8e86008f38f11bd5ac", size = 562483, upload-time = "2025-05-10T14:12:46.508Z" }, + { url = "https://files.pythonhosted.org/packages/83/f7/8d34a9c424fed34353ebc9fcd93a42e9a289b13d651e9413ffd430d28874/pyzstd-0.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e27bfab45f9cdab0c336c747f493a00680a52a018a8bb7a1f787ddde4b29410", size = 432312, upload-time = "2025-05-10T14:12:48.248Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0d/550003e5034383fa47741cb9991a0ec21fc373860eb4e145c6a2a4d06960/pyzstd-0.17.0-cp310-cp310-win32.whl", hash = "sha256:7370c0978edfcb679419f43ec504c128463858a7ea78cf6d0538c39dfb36fce3", size = 220017, upload-time = "2025-05-10T14:12:49.772Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9a/09cb36576f9ce0699bf271dd6a6d60afa1c79b67dc0f156e1c1dc479ba64/pyzstd-0.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:564f7aa66cda4acd9b2a8461ff0c6a6e39a977be3e2e7317411a9f7860d7338d", size = 246139, upload-time = "2025-05-10T14:12:51.529Z" }, + { url = "https://files.pythonhosted.org/packages/03/d4/ba87ffe5128e6c7d97bf99a9966bd9a76206b28c5d6c244b9697addbf3fc/pyzstd-0.17.0-cp310-cp310-win_arm64.whl", hash = "sha256:fccff3a37fa4c513fe1ebf94cb9dc0369c714da22b5671f78ddcbc7ec8f581cc", size = 223057, upload-time = "2025-05-10T14:12:52.879Z" }, + { url = "https://files.pythonhosted.org/packages/29/4a/81ca9a6a759ae10a51cb72f002c149b602ec81b3a568ca6292b117f6da0d/pyzstd-0.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06d1e7afafe86b90f3d763f83d2f6b6a437a8d75119fe1ff52b955eb9df04eaa", size = 377827, upload-time = "2025-05-10T14:12:54.102Z" }, + { url = "https://files.pythonhosted.org/packages/a1/09/584c12c8a918c9311a55be0c667e57a8ee73797367299e2a9f3fc3bf7a39/pyzstd-0.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc827657f644e4510211b49f5dab6b04913216bc316206d98f9a75214361f16e", size = 297579, upload-time = "2025-05-10T14:12:55.748Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/dc74cd83f30b97f95d42b028362e32032e61a8f8e6cc2a8e47b70976d99a/pyzstd-0.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecffadaa2ee516ecea3e432ebf45348fa8c360017f03b88800dd312d62ecb063", size = 443132, upload-time = "2025-05-10T14:12:57.098Z" }, + { url = "https://files.pythonhosted.org/packages/a8/12/fe93441228a324fe75d10f5f13d5e5d5ed028068810dfdf9505d89d704a0/pyzstd-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:596de361948d3aad98a837c98fcee4598e51b608f7e0912e0e725f82e013f00f", size = 390644, upload-time = "2025-05-10T14:12:58.379Z" }, + { url = "https://files.pythonhosted.org/packages/9d/d1/aa7cdeb9bf8995d9df9936c71151be5f4e7b231561d553e73bbf340c2281/pyzstd-0.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd3a8d0389c103e93853bf794b9a35ac5d0d11ca3e7e9f87e3305a10f6dfa6b2", size = 478070, upload-time = "2025-05-10T14:12:59.706Z" }, + { url = "https://files.pythonhosted.org/packages/95/62/7e5c450790bfd3db954694d4d877446d0b6d192aae9c73df44511f17b75c/pyzstd-0.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1356f72c7b8bb99b942d582b61d1a93c5065e66b6df3914dac9f2823136c3228", size = 421240, upload-time = "2025-05-10T14:13:01.151Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b5/d20c60678c0dfe2430f38241d118308f12516ccdb44f9edce27852ee2187/pyzstd-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f514c339b013b0b0a2ed8ea6e44684524223bd043267d7644d7c3a70e74a0dd", size = 412908, upload-time = "2025-05-10T14:13:02.904Z" }, + { url = "https://files.pythonhosted.org/packages/d2/a0/3ae0f1af2982b6cdeacc2a1e1cd20869d086d836ea43e0f14caee8664101/pyzstd-0.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d4de16306821021c2d82a45454b612e2a8683d99bfb98cff51a883af9334bea0", size = 415572, upload-time = "2025-05-10T14:13:04.828Z" }, + { url = "https://files.pythonhosted.org/packages/7d/84/cb0a10c3796f4cd5f09c112cbd72405ffd019f7c0d1e2e5e99ccc803c60c/pyzstd-0.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:aeb9759c04b6a45c1b56be21efb0a738e49b0b75c4d096a38707497a7ff2be82", size = 445334, upload-time = "2025-05-10T14:13:06.5Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d6/8c5cf223067b69aa63f9ecf01846535d4ba82d98f8c9deadfc0092fa16ca/pyzstd-0.17.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a5b31ddeada0027e67464d99f09167cf08bab5f346c3c628b2d3c84e35e239a", size = 518748, upload-time = "2025-05-10T14:13:08.286Z" }, + { url = "https://files.pythonhosted.org/packages/bf/1c/dc7bab00a118d0ae931239b23e05bf703392005cf3bb16942b7b2286452a/pyzstd-0.17.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8338e4e91c52af839abcf32f1f65f3b21e2597ffe411609bdbdaf10274991bd0", size = 562487, upload-time = "2025-05-10T14:13:09.714Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a4/fca96c0af643e4de38bce0dc25dab60ea558c49444c30b9dbe8b7a1714be/pyzstd-0.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:628e93862feb372b4700085ec4d1d389f1283ac31900af29591ae01019910ff3", size = 432319, upload-time = "2025-05-10T14:13:11.296Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a3/7c924478f6c14b369fec8c5cd807b069439c6ecbf98c4783c5791036d3ad/pyzstd-0.17.0-cp311-cp311-win32.whl", hash = "sha256:c27773f9c95ebc891cfcf1ef282584d38cde0a96cb8d64127953ad752592d3d7", size = 220005, upload-time = "2025-05-10T14:13:13.188Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f6/d081b6b29cf00780c971b07f7889a19257dd884e64a842a5ebc406fd3992/pyzstd-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:c043a5766e00a2b7844705c8fa4563b7c195987120afee8f4cf594ecddf7e9ac", size = 246224, upload-time = "2025-05-10T14:13:14.478Z" }, + { url = "https://files.pythonhosted.org/packages/61/f3/f42c767cde8e3b94652baf85863c25476fd463f3bd61f73ed4a02c1db447/pyzstd-0.17.0-cp311-cp311-win_arm64.whl", hash = "sha256:efd371e41153ef55bf51f97e1ce4c1c0b05ceb59ed1d8972fc9aa1e9b20a790f", size = 223036, upload-time = "2025-05-10T14:13:15.752Z" }, + { url = "https://files.pythonhosted.org/packages/76/50/7fa47d0a13301b1ce20972aa0beb019c97f7ee8b0658d7ec66727b5967f9/pyzstd-0.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ac330fc4f64f97a411b6f3fc179d2fe3050b86b79140e75a9a6dd9d6d82087f", size = 379056, upload-time = "2025-05-10T14:13:17.091Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f2/67b03b1fa4e2a0b05e147cc30ac6d271d3d11017b47b30084cb4699451f4/pyzstd-0.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:725180c0c4eb2e643b7048ebfb45ddf43585b740535907f70ff6088f5eda5096", size = 298381, upload-time = "2025-05-10T14:13:18.812Z" }, + { url = "https://files.pythonhosted.org/packages/01/8b/807ff0a13cf3790fe5de85e18e10c22b96d92107d2ce88699cefd3f890cb/pyzstd-0.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c20fe0a60019685fa1f7137cb284f09e3f64680a503d9c0d50be4dd0a3dc5ec", size = 443770, upload-time = "2025-05-10T14:13:20.495Z" }, + { url = "https://files.pythonhosted.org/packages/f0/88/832d8d8147691ee37736a89ea39eaf94ceac5f24a6ce2be316ff5276a1f8/pyzstd-0.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d97f7aaadc3b6e2f8e51bfa6aa203ead9c579db36d66602382534afaf296d0db", size = 391167, upload-time = "2025-05-10T14:13:22.236Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a5/2e09bee398dfb0d94ca43f3655552a8770a6269881dc4710b8f29c7f71aa/pyzstd-0.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42dcb34c5759b59721997036ff2d94210515d3ef47a9de84814f1c51a1e07e8a", size = 478960, upload-time = "2025-05-10T14:13:23.584Z" }, + { url = "https://files.pythonhosted.org/packages/da/b5/1f3b778ad1ccc395161fab7a3bf0dfbd85232234b6657c93213ed1ceda7e/pyzstd-0.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6bf05e18be6f6c003c7129e2878cffd76fcbebda4e7ebd7774e34ae140426cbf", size = 421891, upload-time = "2025-05-10T14:13:25.417Z" }, + { url = "https://files.pythonhosted.org/packages/83/c4/6bfb4725f4f38e9fe9735697060364fb36ee67546e7e8d78135044889619/pyzstd-0.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f7c3a5144aa4fbccf37c30411f6b1db4c0f2cb6ad4df470b37929bffe6ca0", size = 413608, upload-time = "2025-05-10T14:13:26.75Z" }, + { url = "https://files.pythonhosted.org/packages/95/a2/c48b543e3a482e758b648ea025b94efb1abe1f4859c5185ff02c29596035/pyzstd-0.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9efd4007f8369fd0890701a4fc77952a0a8c4cb3bd30f362a78a1adfb3c53c12", size = 416429, upload-time = "2025-05-10T14:13:28.096Z" }, + { url = "https://files.pythonhosted.org/packages/5c/62/2d039ee4dbc8116ca1f2a2729b88a1368f076f5dadad463f165993f7afa8/pyzstd-0.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5f8add139b5fd23b95daa844ca13118197f85bd35ce7507e92fcdce66286cc34", size = 446671, upload-time = "2025-05-10T14:13:29.772Z" }, + { url = "https://files.pythonhosted.org/packages/be/ec/9ec9f0957cf5b842c751103a2b75ecb0a73cf3d99fac57e0436aab6748e0/pyzstd-0.17.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:259a60e8ce9460367dcb4b34d8b66e44ca3d8c9c30d53ed59ae7037622b3bfc7", size = 520290, upload-time = "2025-05-10T14:13:31.585Z" }, + { url = "https://files.pythonhosted.org/packages/cc/42/2e2f4bb641c2a9ab693c31feebcffa1d7c24e946d8dde424bba371e4fcce/pyzstd-0.17.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:86011a93cc3455c5d2e35988feacffbf2fa106812a48e17eb32c2a52d25a95b3", size = 563785, upload-time = "2025-05-10T14:13:32.971Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e4/25e198d382faa4d322f617d7a5ff82af4dc65749a10d90f1423af2d194f6/pyzstd-0.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:425c31bc3de80313054e600398e4f1bd229ee61327896d5d015e2cd0283c9012", size = 433390, upload-time = "2025-05-10T14:13:34.668Z" }, + { url = "https://files.pythonhosted.org/packages/ad/7c/1ab970f5404ace9d343a36a86f1bd0fcf2dc1adf1ef8886394cf0a58bd9e/pyzstd-0.17.0-cp312-cp312-win32.whl", hash = "sha256:7c4b88183bb36eb2cebbc0352e6e9fe8e2d594f15859ae1ef13b63ebc58be158", size = 220291, upload-time = "2025-05-10T14:13:36.005Z" }, + { url = "https://files.pythonhosted.org/packages/b2/52/d35bf3e4f0676a74359fccef015eabe3ceaba95da4ac2212f8be4dde16de/pyzstd-0.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c31947e0120468342d74e0fa936d43f7e1dad66a2262f939735715aa6c730e8", size = 246451, upload-time = "2025-05-10T14:13:37.712Z" }, + { url = "https://files.pythonhosted.org/packages/34/da/a44705fe44dd87e0f09861b062f93ebb114365640dbdd62cbe80da9b8306/pyzstd-0.17.0-cp312-cp312-win_arm64.whl", hash = "sha256:1d0346418abcef11507356a31bef5470520f6a5a786d4e2c69109408361b1020", size = 222967, upload-time = "2025-05-10T14:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/7e/51/171f5aad999e3f99e664e8ef572bbf97cbd684c46891a99fe8767eb9b7f6/pyzstd-0.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6cd1a1d37a7abe9c01d180dad699e3ac3889e4f48ac5dcca145cc46b04e9abd2", size = 379051, upload-time = "2025-05-10T14:13:40.36Z" }, + { url = "https://files.pythonhosted.org/packages/83/1e/bdae9d1331a7fb60cdd9d3c75794ea4c0271d5e8408fbbe877353b730f99/pyzstd-0.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a44fd596eda06b6265dc0358d5b309715a93f8e96e8a4b5292c2fe0e14575b3", size = 298384, upload-time = "2025-05-10T14:13:41.728Z" }, + { url = "https://files.pythonhosted.org/packages/80/3d/c0b61fc7994254b369aa5e96fcd02dbb3f8964482d51e098640802dd35e8/pyzstd-0.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a99b37453f92f0691b2454d0905bbf2f430522612f6f12bbc81133ad947eb97", size = 445950, upload-time = "2025-05-10T14:13:43.034Z" }, + { url = "https://files.pythonhosted.org/packages/78/62/318de78124d49fe3f7ae2b44726bdb85eef63c3f3338ec3673665326df25/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63d864e9f9e624a466070a121ace9d9cbf579eac4ed575dee3b203ab1b3cbeee", size = 392923, upload-time = "2025-05-10T14:13:44.443Z" }, + { url = "https://files.pythonhosted.org/packages/7a/24/21541ee45cae4fd7e3d15d67f67ad3e96e41e0ee0a95653006f8a0df2349/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e58bc02b055f96d1f83c791dd197d8c80253275a56cd84f917a006e9f528420d", size = 480524, upload-time = "2025-05-10T14:13:45.798Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fd/6659504588f4cb53ac5f347bd75206072c4969eacf3ae6925f46ddb6dadb/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e62df7c0ba74618481149c849bc3ed7d551b9147e1274b4b3170bbcc0bfcc0a", size = 423568, upload-time = "2025-05-10T14:13:47.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/50/1eefc03eb21745321893fbd52702245f85e9e1f7ad35411dff2606792100/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42ecdd7136294f1becb8e57441df00eaa6dfd7444a8b0c96a1dfba5c81b066e7", size = 415473, upload-time = "2025-05-10T14:13:48.994Z" }, + { url = "https://files.pythonhosted.org/packages/8a/27/f3da112795f9b9dc4db819f9f6e1b231a7adc03c609db1f2b33a4185be1d/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:be07a57af75f99fc39b8e2d35f8fb823ecd7ef099cd1f6203829a5094a991ae2", size = 418276, upload-time = "2025-05-10T14:13:50.316Z" }, + { url = "https://files.pythonhosted.org/packages/95/56/02b601d7198dc5138ceea6f2b978b3205b9fab05740957d1ef1c4ca59621/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0d41e6f7ec2a70dab4982157a099562de35a6735c890945b4cebb12fb7eb0be0", size = 449285, upload-time = "2025-05-10T14:13:51.759Z" }, + { url = "https://files.pythonhosted.org/packages/f4/79/8a4c352f9dd5728402318f324930250ad40df8fd27fea33818cf0c9ac171/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f482d906426756e7cc9a43f500fee907e1b3b4e9c04d42d58fb1918c6758759b", size = 522190, upload-time = "2025-05-10T14:13:53.075Z" }, + { url = "https://files.pythonhosted.org/packages/55/4a/51385325e7b816365292078449a8007bc3ab3e05b7b29ab91d9d519edb01/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:827327b35605265e1d05a2f6100244415e8f2728bb75c951736c9288415908d7", size = 566488, upload-time = "2025-05-10T14:13:54.484Z" }, + { url = "https://files.pythonhosted.org/packages/26/68/da37fb4e6a79a3cff7de4a3ee006fb5f981230c59de79f6c8c426392a265/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a55008f80e3390e4f37bd9353830f1675f271d13d6368d2f1dc413b7c6022b3", size = 432870, upload-time = "2025-05-10T14:13:55.86Z" }, + { url = "https://files.pythonhosted.org/packages/30/05/769d82f9708c4907512111a1de44bb77e5b08ad3862287c2e5fc5ead2df2/pyzstd-0.17.0-cp313-cp313-win32.whl", hash = "sha256:a4be186c0df86d4d95091c759a06582654f2b93690503b1c24d77f537d0cf5d0", size = 220290, upload-time = "2025-05-10T14:13:57.227Z" }, + { url = "https://files.pythonhosted.org/packages/62/92/f69eb8623f041c2656e27337ac08e69cd18a9eacb1557ab498d391f191bd/pyzstd-0.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:251a0b599bd224ec66f39165ddb2f959d0a523938e3bbfa82d8188dc03a271a2", size = 246450, upload-time = "2025-05-10T14:13:58.596Z" }, + { url = "https://files.pythonhosted.org/packages/ad/ef/5ae5445d5f675e9e8c868b2326597c5b396e41c5c9645daa45e8c1cd3d5c/pyzstd-0.17.0-cp313-cp313-win_arm64.whl", hash = "sha256:ce6d5fd908fd3ddec32d1c1a5a7a15b9d7737d0ef2ab20fe1e8261da61395017", size = 222966, upload-time = "2025-05-10T14:13:59.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/32/97505422bd403a4207587fc454eaa6497d353e6110fce234e1d2be780279/pyzstd-0.17.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c56f99c697130f39702e07ab9fa0bb4c929c7bfe47c0a488dea732bd8a8752a", size = 368393, upload-time = "2025-05-10T14:14:24.909Z" }, + { url = "https://files.pythonhosted.org/packages/1d/db/963dd8a5f9e29581097a4f3a9f0deaa8a2cd516b2ce945fcb489e3c19e2a/pyzstd-0.17.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:152bae1b2197bcd41fc143f93acd23d474f590162547484ca04ce5874c4847de", size = 283560, upload-time = "2025-05-10T14:14:26.171Z" }, + { url = "https://files.pythonhosted.org/packages/66/14/a8868202b896538f1f1ecbf13f226722426b6d44a11a8d6ce23ce57a4370/pyzstd-0.17.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2ddbbd7614922e52018ba3e7bb4cbe6f25b230096831d97916b8b89be8cd0cb", size = 356913, upload-time = "2025-05-10T14:14:27.519Z" }, + { url = "https://files.pythonhosted.org/packages/35/a6/7198ab6abd0604eb7d71a8a36b69b66441258d9216bc2fa5f181dcd47c7a/pyzstd-0.17.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f6f3f152888825f71fd2cf2499f093fac252a5c1fa15ab8747110b3dc095f6b", size = 329418, upload-time = "2025-05-10T14:14:28.897Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6b/9901ea929ea481428113a16530b26873615ae2ed184897ec92e15004cc07/pyzstd-0.17.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d00a2d2bddf51c7bf32c17dc47f0f49f47ebae07c2528b9ee8abf1f318ac193", size = 349449, upload-time = "2025-05-10T14:14:30.247Z" }, + { url = "https://files.pythonhosted.org/packages/11/30/fc8258499b9a556eaadc61f542aa930d2046d96125454add97b2bc8fb052/pyzstd-0.17.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d79e3eff07217707a92c1a6a9841c2466bfcca4d00fea0bea968f4034c27a256", size = 241666, upload-time = "2025-05-10T14:14:31.712Z" }, + { url = "https://files.pythonhosted.org/packages/b8/95/b1ae395968efdba92704c23f2f8e027d08e00d1407671e42f65ac914d211/pyzstd-0.17.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3ce6bac0c4c032c5200647992a8efcb9801c918633ebe11cceba946afea152d9", size = 368391, upload-time = "2025-05-10T14:14:33.064Z" }, + { url = "https://files.pythonhosted.org/packages/c7/72/856831cacef58492878b8307353e28a3ba4326a85c3c82e4803a95ad0d14/pyzstd-0.17.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:a00998144b35be7c485a383f739fe0843a784cd96c3f1f2f53f1a249545ce49a", size = 283561, upload-time = "2025-05-10T14:14:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a7/a86e55cd9f3e630a71c0bf78ac6da0c6b50dc428ca81aa7c5adbc66eb880/pyzstd-0.17.0-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8521d7bbd00e0e1c1fd222c1369a7600fba94d24ba380618f9f75ee0c375c277", size = 356912, upload-time = "2025-05-10T14:14:35.722Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b7/de2b42dd96dfdb1c0feb5f43d53db2d3a060607f878da7576f35dff68789/pyzstd-0.17.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da65158c877eac78dcc108861d607c02fb3703195c3a177f2687e0bcdfd519d0", size = 329417, upload-time = "2025-05-10T14:14:37.487Z" }, + { url = "https://files.pythonhosted.org/packages/52/65/d4e8196e068e6b430499fb2a5092380eb2cb7eecf459b9d4316cff7ecf6c/pyzstd-0.17.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:226ca0430e2357abae1ade802585231a2959b010ec9865600e416652121ba80b", size = 349448, upload-time = "2025-05-10T14:14:38.797Z" }, + { url = "https://files.pythonhosted.org/packages/9e/15/b5ed5ad8c8d2d80c5f5d51e6c61b2cc05f93aaf171164f67ccc7ade815cd/pyzstd-0.17.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e3a19e8521c145a0e2cd87ca464bf83604000c5454f7e0746092834fd7de84d1", size = 241668, upload-time = "2025-05-10T14:14:40.18Z" }, ] [[package]] @@ -1245,19 +1257,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, ] -[[package]] -name = "rich" -version = "13.7.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b3/01/c954e134dc440ab5f96952fe52b4fdc64225530320a910473c1fe270d9aa/rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432", size = 221248, upload-time = "2024-02-28T14:51:19.472Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", size = 240681, upload-time = "2024-02-28T14:51:14.353Z" }, -] - [[package]] name = "ruff" version = "0.11.13"