From 9aea31deddf7458be3546f72185740f3cd06687f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 27 Apr 2021 10:39:01 -0700 Subject: bpo-8978: improve tarfile.open error message when lzma / bz2 are missing (GH-24850) Automerge-Triggered-By: GH:pablogsal --- Lib/tarfile.py | 7 +++++-- Lib/test/test_tarfile.py | 12 ++++++++++++ Lib/test/testtar.tar.xz | Bin 0 -> 172 bytes .../next/Library/2021-03-13-14-02-07.bpo-8978.CRxG-O.rst | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 Lib/test/testtar.tar.xz create mode 100644 Misc/NEWS.d/next/Library/2021-03-13-14-02-07.bpo-8978.CRxG-O.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 395c0f1..18d415a 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1604,17 +1604,20 @@ class TarFile(object): # Find out which *open() is appropriate for opening the file. def not_compressed(comptype): return cls.OPEN_METH[comptype] == 'taropen' + error_msgs = [] for comptype in sorted(cls.OPEN_METH, key=not_compressed): func = getattr(cls, cls.OPEN_METH[comptype]) if fileobj is not None: saved_pos = fileobj.tell() try: return func(name, "r", fileobj, **kwargs) - except (ReadError, CompressionError): + except (ReadError, CompressionError) as e: + error_msgs.append(f'- method {comptype}: {e!r}') if fileobj is not None: fileobj.seek(saved_pos) continue - raise ReadError("file could not be opened successfully") + error_msgs_summary = '\n'.join(error_msgs) + raise ReadError(f"file could not be opened successfully:\n{error_msgs_summary}") elif ":" in mode: filemode, comptype = mode.split(":", 1) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 77ad830..817e6f1 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -2283,6 +2283,18 @@ class MiscTest(unittest.TestCase): 'SubsequentHeaderError', 'ExFileObject', 'main'} support.check__all__(self, tarfile, not_exported=not_exported) + def test_useful_error_message_when_modules_missing(self): + fname = os.path.join(os.path.dirname(__file__), 'testtar.tar.xz') + with self.assertRaises(tarfile.ReadError) as excinfo: + error = tarfile.CompressionError('lzma module is not available'), + with unittest.mock.patch.object(tarfile.TarFile, 'xzopen', side_effect=error): + tarfile.open(fname) + + self.assertIn( + "\n- method xz: CompressionError('lzma module is not available')\n", + str(excinfo.exception), + ) + class CommandLineTest(unittest.TestCase): diff --git a/Lib/test/testtar.tar.xz b/Lib/test/testtar.tar.xz new file mode 100644 index 0000000..512fa14 Binary files /dev/null and b/Lib/test/testtar.tar.xz differ diff --git a/Misc/NEWS.d/next/Library/2021-03-13-14-02-07.bpo-8978.CRxG-O.rst b/Misc/NEWS.d/next/Library/2021-03-13-14-02-07.bpo-8978.CRxG-O.rst new file mode 100644 index 0000000..2da8874 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-03-13-14-02-07.bpo-8978.CRxG-O.rst @@ -0,0 +1,2 @@ +Improve error message for :func:`tarfile.open` when :mod:`lzma` / :mod:`bz2` +are unavailable. Patch by Anthony Sottile. -- cgit v0.12