From ebf37b6e9df58d5e1560459841b7d5d0f04657a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 26 Apr 2025 14:44:25 +0200 Subject: [PATCH 1/3] 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. --- Doc/library/tarfile.rst | 5 ++++- Lib/tarfile.py | 7 ++++--- .../Library/2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst | 2 ++ 3 files changed, 10 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 c9d69cf5094095..f9cb5495e60cd2 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:: 3.14 + The *preset* keyword argument also works for streams. + .. class:: TarFile :noindex: diff --git a/Lib/tarfile.py b/Lib/tarfile.py index a0fab46b24e249..42ae201c6f6129 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 @@ def __init__(self, name, mode, comptype, fileobj, bufsize, 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) @@ -1887,8 +1887,9 @@ def not_compressed(comptype): raise ValueError("mode must be 'r' or 'w'") 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 00000000000000..53a687f0db7f6b --- /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 ``tarfile.open()`` when using ``w|xz`` +mode. From 414b94eceadc0e957408d8bc5a17c707d1807fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 26 Apr 2025 14:49:52 +0200 Subject: [PATCH 2/3] 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. --- Lib/tarfile.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 42ae201c6f6129..82c5f6704cbd24 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1885,6 +1885,12 @@ def not_compressed(comptype): 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) From 406dc4c06ab871cb8cd96e4ad0346fbac10767aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 26 Apr 2025 16:00:20 +0200 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Brian Schubert --- Doc/library/tarfile.rst | 2 +- .../next/Library/2025-04-26-14-44-21.gh-issue-133005.y4SRfk.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index f9cb5495e60cd2..8e9775ddbc6915 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -167,7 +167,7 @@ Some facts and figures: .. versionchanged:: 3.12 The *compresslevel* keyword argument also works for streams. - .. versionchanged:: 3.14 + .. versionchanged:: next The *preset* keyword argument also works for streams. 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 index 53a687f0db7f6b..cb3ad489706967 100644 --- 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 @@ -1,2 +1,2 @@ -Support passing ``preset`` option to ``tarfile.open()`` when using ``w|xz`` +Support passing ``preset`` option to :func:`tarfile.open` when using ``'w|xz'`` mode.