summaryrefslogtreecommitdiff
path: root/Lib
diff options
context:
space:
mode:
authorIrit Katriel <iritkatriel@yahoo.com>2020-12-19 00:09:54 +0000
committerGitHub <noreply@github.com>2020-12-18 16:09:54 -0800
commitfb34096140bbb74c81500dd8bbc3c69c1d24d9ab (patch)
tree0b3dd85011b4d6f36068f0e69f38666178a10b48 /Lib
parente8d22642105d57007ab1242848a8cbadc7f179df (diff)
downloadcpython-git-fb34096140bbb74c81500dd8bbc3c69c1d24d9ab.tar.gz
bpo-24792: Fix zipimporter masking the cause of import errors (GH-22204)
zipimport's _unmarshal_code swallows import errors and then _get_module_code doesn't know the cause of the error, and returns the generic, and sometimes incorrect, 'could not find...'. Automerge-Triggered-By: GH:brettcannon
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_zipimport.py8
-rw-r--r--Lib/zipimport.py38
2 files changed, 24 insertions, 22 deletions
diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py
index 6dea2b1628..d59ef1ed6f 100644
--- a/Lib/test/test_zipimport.py
+++ b/Lib/test/test_zipimport.py
@@ -242,10 +242,10 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
files = {TESTMOD + pyc_ext: (NOW, badmagic_pyc)}
try:
self.doTest(".py", files, TESTMOD)
- except ImportError:
- pass
- else:
- self.fail("expected ImportError; import from bad pyc")
+ self.fail("This should not be reached")
+ except zipimport.ZipImportError as exc:
+ self.assertIsInstance(exc.__cause__, ImportError)
+ self.assertIn("magic number", exc.__cause__.msg)
def testBadMTime(self):
badtime_pyc = bytearray(test_pyc)
diff --git a/Lib/zipimport.py b/Lib/zipimport.py
index 02e4fd38d0..ce3e00e24f 100644
--- a/Lib/zipimport.py
+++ b/Lib/zipimport.py
@@ -185,7 +185,7 @@ class zipimporter(_bootstrap_external._LoaderBasics):
"""get_code(fullname) -> code object.
Return the code object for the specified module. Raise ZipImportError
- if the module couldn't be found.
+ if the module couldn't be imported.
"""
code, ispackage, modpath = _get_module_code(self, fullname)
return code
@@ -215,7 +215,8 @@ class zipimporter(_bootstrap_external._LoaderBasics):
def get_filename(self, fullname):
"""get_filename(fullname) -> filename string.
- Return the filename for the specified module.
+ Return the filename for the specified module or raise ZipImportError
+ if it couldn't be imported.
"""
# Deciding the filename requires working out where the code
# would come from if the module was actually loaded
@@ -267,7 +268,7 @@ class zipimporter(_bootstrap_external._LoaderBasics):
Load the module specified by 'fullname'. 'fullname' must be the
fully qualified (dotted) module name. It returns the imported
- module, or raises ZipImportError if it wasn't found.
+ module, or raises ZipImportError if it could not be imported.
Deprecated since Python 3.10. Use exec_module() instead.
"""
@@ -613,20 +614,15 @@ def _eq_mtime(t1, t2):
# Given the contents of a .py[co] file, unmarshal the data
-# and return the code object. Return None if it the magic word doesn't
-# match, or if the recorded .py[co] metadata does not match the source,
-# (we do this instead of raising an exception as we fall back
-# to .py if available and we don't want to mask other errors).
+# and return the code object. Raises ImportError it the magic word doesn't
+# match, or if the recorded .py[co] metadata does not match the source.
def _unmarshal_code(self, pathname, fullpath, fullname, data):
exc_details = {
'name': fullname,
'path': fullpath,
}
- try:
- flags = _bootstrap_external._classify_pyc(data, fullname, exc_details)
- except ImportError:
- return None
+ flags = _bootstrap_external._classify_pyc(data, fullname, exc_details)
hash_based = flags & 0b1 != 0
if hash_based:
@@ -640,11 +636,8 @@ def _unmarshal_code(self, pathname, fullpath, fullname, data):
source_bytes,
)
- try:
- _bootstrap_external._validate_hash_pyc(
- data, source_hash, fullname, exc_details)
- except ImportError:
- return None
+ _bootstrap_external._validate_hash_pyc(
+ data, source_hash, fullname, exc_details)
else:
source_mtime, source_size = \
_get_mtime_and_size_of_source(self, fullpath)
@@ -730,6 +723,7 @@ def _get_pyc_source(self, path):
# 'fullname'.
def _get_module_code(self, fullname):
path = _get_module_path(self, fullname)
+ import_error = None
for suffix, isbytecode, ispackage in _zip_searchorder:
fullpath = path + suffix
_bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2)
@@ -740,8 +734,12 @@ def _get_module_code(self, fullname):
else:
modpath = toc_entry[0]
data = _get_data(self.archive, toc_entry)
+ code = None
if isbytecode:
- code = _unmarshal_code(self, modpath, fullpath, fullname, data)
+ try:
+ code = _unmarshal_code(self, modpath, fullpath, fullname, data)
+ except ImportError as exc:
+ import_error = exc
else:
code = _compile_source(modpath, data)
if code is None:
@@ -751,4 +749,8 @@ def _get_module_code(self, fullname):
modpath = toc_entry[0]
return code, ispackage, modpath
else:
- raise ZipImportError(f"can't find module {fullname!r}", name=fullname)
+ if import_error:
+ msg = f"module load failed: {import_error}"
+ raise ZipImportError(msg, name=fullname) from import_error
+ else:
+ raise ZipImportError(f"can't find module {fullname!r}", name=fullname)