diff --git a/pyproject.toml b/pyproject.toml index fdee18f6e..46e2b0537 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ dependencies = [ "userpath~=1.7", "uv>=0.5.23", "virtualenv>=20.26.6", - "zstandard<1", + "backports.zstd>=1.0.0 ; python_version<'3.14'", ] dynamic = ["version"] diff --git a/src/hatch/python/resolve.py b/src/hatch/python/resolve.py index cf17a29b7..9d7459d5a 100644 --- a/src/hatch/python/resolve.py +++ b/src/hatch/python/resolve.py @@ -5,7 +5,7 @@ import sys from abc import ABC, abstractmethod from functools import cached_property -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Literal from hatch.config.constants import PythonEnvVars from hatch.errors import PythonDistributionResolutionError, PythonDistributionUnknownError @@ -55,43 +55,36 @@ def archive_name(self) -> str: return self.source.rsplit("/", 1)[-1] def unpack(self, archive: Path, directory: Path) -> None: + # zip if self.source.endswith(".zip"): import zipfile with zipfile.ZipFile(archive, "r") as zf: zf.extractall(directory) - elif self.source.endswith((".tar.gz", ".tgz")): - import tarfile + return - with tarfile.open(archive, "r:gz") as tf: - if sys.version_info[:2] >= (3, 12): - tf.extractall(directory, filter="data") - else: - tf.extractall(directory) # noqa: S202 - elif self.source.endswith((".tar.bz2", ".bz2")): + # tar + if sys.version_info >= (3, 14): import tarfile + else: + # for zstd support (introduced in Python 3.14) + # and filter kwarg (introduced in Python 3.12) + from backports.zstd import tarfile - with tarfile.open(archive, "r:bz2") as tf: - if sys.version_info[:2] >= (3, 12): - tf.extractall(directory, filter="data") - else: - tf.extractall(directory) # noqa: S202 + mode: Literal["r:gz", "r:bz2", "r:zst"] + if self.source.endswith((".tar.gz", ".tgz")): + mode = "r:gz" + elif self.source.endswith((".tar.bz2", ".bz2")): + mode = "r:bz2" elif self.source.endswith((".tar.zst", ".tar.zstd")): - import tarfile - - import zstandard - - with open(archive, "rb") as ifh: - dctx = zstandard.ZstdDecompressor() - with dctx.stream_reader(ifh) as reader, tarfile.open(mode="r|", fileobj=reader) as tf: - if sys.version_info[:2] >= (3, 12): - tf.extractall(directory, filter="data") - else: - tf.extractall(directory) # noqa: S202 + mode = "r:zst" else: message = f"Unknown archive type: {archive}" raise ValueError(message) + with tarfile.open(archive, mode) as tf: + tf.extractall(directory, filter="data") + @property @abstractmethod def version(self) -> Version: