Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/library/tarfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ Some facts and figures:
a Zstandard dictionary used to improve compression of smaller amounts of
data.

For modes ``'r:zst'`` and ``'r|zst'``, :func:`tarfile.open` accepts the keyword
arguments *options* and *zstd_dict* as well.

For special purposes, there is a second format for *mode*:
``'filemode|[compression]'``. :func:`tarfile.open` will return a :class:`TarFile`
object that processes its data as a stream of blocks. No random seeking will
Expand Down
31 changes: 21 additions & 10 deletions Lib/tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,7 @@ class _Stream:
_Stream is intended to be used only internally.
"""

def __init__(self, name, mode, comptype, fileobj, bufsize,
compresslevel, preset):
def __init__(self, name, mode, comptype, fileobj, bufsize, **kwargs):
"""Construct a _Stream object.
"""
self._extfileobj = True
Expand Down Expand Up @@ -373,7 +372,7 @@ def __init__(self, name, mode, comptype, fileobj, bufsize,
self.exception = zlib.error
self._init_read_gz()
else:
self._init_write_gz(compresslevel)
self._init_write_gz(kwargs.get("compresslevel"))

elif comptype == "bz2":
try:
Expand All @@ -385,7 +384,7 @@ def __init__(self, name, mode, comptype, fileobj, bufsize,
self.cmp = bz2.BZ2Decompressor()
self.exception = OSError
else:
self.cmp = bz2.BZ2Compressor(compresslevel)
self.cmp = bz2.BZ2Compressor(kwargs.get("compresslevel"))

elif comptype == "xz":
try:
Expand All @@ -397,18 +396,21 @@ def __init__(self, name, mode, comptype, fileobj, bufsize,
self.cmp = lzma.LZMADecompressor()
self.exception = lzma.LZMAError
else:
self.cmp = lzma.LZMACompressor(preset=preset)
self.cmp = lzma.LZMACompressor(preset=kwargs.get("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.cmp = zstd.ZstdDecompressor(kwargs.get("zstd_dict"),
kwargs.get("options"))
self.exception = zstd.ZstdError
else:
self.cmp = zstd.ZstdCompressor()
self.cmp = zstd.ZstdCompressor(kwargs.get("level"),
kwargs.get("options"),
kwargs.get("zstd_dict"))
elif comptype != "tar":
raise CompressionError("unknown compression type %r" % comptype)

Expand Down Expand Up @@ -1929,10 +1931,19 @@ def not_compressed(comptype):
if "preset" in kwargs and comptype not in ("xz",):
raise ValueError("preset is only valid for w|xz mode")

compresslevel = kwargs.pop("compresslevel", 6)
preset = kwargs.pop("preset", None)
if comptype not in ("zst",):
for arg in ("level", "options", "zstd_dict"):
if arg in kwargs:
raise ValueError(
f"{arg} is only valid for zstd compression"
)

stream = _Stream(name, filemode, comptype, fileobj, bufsize,
compresslevel, preset)
compresslevel=kwargs.pop("compresslevel", 6),
preset=kwargs.pop("preset", None),
level=kwargs.pop("level", None),
options=kwargs.pop("options", None),
zstd_dict=kwargs.pop("zstd_dict", None))
try:
t = cls(name, filemode, stream, **kwargs)
except:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make ``tarfile.open`` correctly forward keyword arguments for zstd in stream mode.
Loading