gh-132983: Add the compression.zstd pacakge and tests (#133365)

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
Co-authored-by: Tomas R. <tomas.roun8@gmail.com>
Co-authored-by: Rogdham <contact@rogdham.net>
This commit is contained in:
Emma Smith 2025-05-05 17:38:08 -07:00 committed by GitHub
parent 793402e217
commit c273f59fb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 3358 additions and 100 deletions

View file

@ -399,7 +399,17 @@ class _Stream:
self.exception = lzma.LZMAError
else:
self.cmp = lzma.LZMACompressor(preset=preset)
elif comptype == "zst":
try:
from compression import zstd
except ImportError:
raise CompressionError("compression.zstd module is not available") from None
if mode == "r":
self.dbuf = b""
self.cmp = zstd.ZstdDecompressor()
self.exception = zstd.ZstdError
else:
self.cmp = zstd.ZstdCompressor()
elif comptype != "tar":
raise CompressionError("unknown compression type %r" % comptype)
@ -591,6 +601,8 @@ class _StreamProxy(object):
return "bz2"
elif self.buf.startswith((b"\x5d\x00\x00\x80", b"\xfd7zXZ")):
return "xz"
elif self.buf.startswith(b"\x28\xb5\x2f\xfd"):
return "zst"
else:
return "tar"
@ -1817,11 +1829,13 @@ class TarFile(object):
'r:gz' open for reading with gzip compression
'r:bz2' open for reading with bzip2 compression
'r:xz' open for reading with lzma compression
'r:zst' open for reading with zstd compression
'a' or 'a:' open for appending, creating the file if necessary
'w' or 'w:' open for writing without compression
'w:gz' open for writing with gzip compression
'w:bz2' open for writing with bzip2 compression
'w:xz' open for writing with lzma compression
'w:zst' open for writing with zstd compression
'x' or 'x:' create a tarfile exclusively without compression, raise
an exception if the file is already created
@ -1831,16 +1845,20 @@ class TarFile(object):
if the file is already created
'x:xz' create an lzma compressed tarfile, raise an exception
if the file is already created
'x:zst' create a zstd compressed tarfile, raise an exception
if the file is already created
'r|*' open a stream of tar blocks with transparent compression
'r|' open an uncompressed stream of tar blocks for reading
'r|gz' open a gzip compressed stream of tar blocks
'r|bz2' open a bzip2 compressed stream of tar blocks
'r|xz' open an lzma compressed stream of tar blocks
'r|zst' open a zstd compressed stream of tar blocks
'w|' open an uncompressed stream for writing
'w|gz' open a gzip compressed stream for writing
'w|bz2' open a bzip2 compressed stream for writing
'w|xz' open an lzma compressed stream for writing
'w|zst' open a zstd compressed stream for writing
"""
if not name and not fileobj:
@ -2006,12 +2024,48 @@ class TarFile(object):
t._extfileobj = False
return t
@classmethod
def zstopen(cls, name, mode="r", fileobj=None, level=None, options=None,
zstd_dict=None, **kwargs):
"""Open zstd compressed tar archive name for reading or writing.
Appending is not allowed.
"""
if mode not in ("r", "w", "x"):
raise ValueError("mode must be 'r', 'w' or 'x'")
try:
from compression.zstd import ZstdFile, ZstdError
except ImportError:
raise CompressionError("compression.zstd module is not available") from None
fileobj = ZstdFile(
fileobj or name,
mode,
level=level,
options=options,
zstd_dict=zstd_dict
)
try:
t = cls.taropen(name, mode, fileobj, **kwargs)
except (ZstdError, EOFError) as e:
fileobj.close()
if mode == 'r':
raise ReadError("not a zstd file") from e
raise
except Exception:
fileobj.close()
raise
t._extfileobj = False
return t
# All *open() methods are registered here.
OPEN_METH = {
"tar": "taropen", # uncompressed tar
"gz": "gzopen", # gzip compressed tar
"bz2": "bz2open", # bzip2 compressed tar
"xz": "xzopen" # lzma compressed tar
"xz": "xzopen", # lzma compressed tar
"zst": "zstopen" # zstd compressed tar
}
#--------------------------------------------------------------------------
@ -2963,6 +3017,9 @@ def main():
'.tbz': 'bz2',
'.tbz2': 'bz2',
'.tb2': 'bz2',
# zstd
'.zst': 'zst',
'.tzst': 'zst',
}
tar_mode = 'w:' + compressions[ext] if ext in compressions else 'w'
tar_files = args.create