From 019ee49d50b6466f2f18035c812fa87d20c24a46 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 28 Apr 2025 00:19:59 +0200 Subject: [PATCH] gh-133005: Support `tarfile.open(mode="w|xz", preset=...)` (GH-133007) * gh-133005: Support `tarfile.open(mode="w|xz", preset=...)` Support passing the `preset` option to `tarfile.open` when the file is open with `mode="w|xz"`. This aligns the behavior with `"w:xz"` mode. * Also raise an error for `compresslevel` or `preset` with wrong mode Raise an error if `compresslevel` or `preset` argument is specified for stream mode with incorrect compression. This should reduce the risk of mistakes and align the stream modes with regular modes, that raise an implicit TypeError on unsupported arguments. * Apply suggestions from code review Co-authored-by: Brian Schubert --- Doc/library/tarfile.rst | 5 ++++- Lib/tarfile.py | 13 ++++++++++--- .../2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index c9d69cf50940..8e9775ddbc69 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -112,7 +112,7 @@ Some facts and figures: ``'w|bz2'``, :func:`tarfile.open` accepts the keyword argument *compresslevel* (default ``9``) to specify the compression level of the file. - For modes ``'w:xz'`` and ``'x:xz'``, :func:`tarfile.open` accepts the + For modes ``'w:xz'``, ``'x:xz'`` and ``'w|xz'``, :func:`tarfile.open` accepts the keyword argument *preset* to specify the compression level of the file. For special purposes, there is a second format for *mode*: @@ -167,6 +167,9 @@ Some facts and figures: .. versionchanged:: 3.12 The *compresslevel* keyword argument also works for streams. + .. versionchanged:: next + The *preset* keyword argument also works for streams. + .. class:: TarFile :noindex: diff --git a/Lib/tarfile.py b/Lib/tarfile.py index a0fab46b24e2..82c5f6704cbd 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -339,7 +339,7 @@ class _Stream: """ def __init__(self, name, mode, comptype, fileobj, bufsize, - compresslevel): + compresslevel, preset): """Construct a _Stream object. """ self._extfileobj = True @@ -398,7 +398,7 @@ class _Stream: self.cmp = lzma.LZMADecompressor() self.exception = lzma.LZMAError else: - self.cmp = lzma.LZMACompressor() + self.cmp = lzma.LZMACompressor(preset=preset) elif comptype != "tar": raise CompressionError("unknown compression type %r" % comptype) @@ -1885,10 +1885,17 @@ class TarFile(object): if filemode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") + if "compresslevel" in kwargs and comptype not in ("gz", "bz2"): + raise ValueError( + "compresslevel is only valid for w|gz and w|bz2 modes" + ) + if "preset" in kwargs and comptype not in ("xz",): + raise ValueError("preset is only valid for w|xz mode") compresslevel = kwargs.pop("compresslevel", 9) + preset = kwargs.pop("preset", None) stream = _Stream(name, filemode, comptype, fileobj, bufsize, - compresslevel) + compresslevel, preset) try: t = cls(name, filemode, stream, **kwargs) except: diff --git a/Misc/NEWS.d/next/Library/2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst b/Misc/NEWS.d/next/Library/2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst new file mode 100644 index 000000000000..cb3ad4897069 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst @@ -0,0 +1,2 @@ +Support passing ``preset`` option to :func:`tarfile.open` when using ``'w|xz'`` +mode. -- 2.47.3