[Python-checkins] cpython: Have importlib take advantage of ImportError's new 'name' and 'path'

brett.cannon python-checkins at python.org
Fri Apr 13 03:13:16 CEST 2012


http://hg.python.org/cpython/rev/c071af95772a
changeset:   76280:c071af95772a
parent:      76272:6825fd9b00ed
user:        Brett Cannon <brett at python.org>
date:        Thu Apr 12 21:09:01 2012 -0400
summary:
  Have importlib take advantage of ImportError's new 'name' and 'path'
attributes.

files:
  Lib/importlib/_bootstrap.py                   |  42 ++++++---
  Lib/importlib/abc.py                          |  18 ++-
  Lib/importlib/test/builtin/test_loader.py     |   9 +-
  Lib/importlib/test/extension/test_loader.py   |   6 +-
  Lib/importlib/test/frozen/test_loader.py      |   6 +-
  Lib/importlib/test/import_/test_caching.py    |   3 +-
  Lib/importlib/test/import_/test_packages.py   |   6 +-
  Lib/importlib/test/source/test_abc_loader.py  |  11 +-
  Lib/importlib/test/source/test_file_loader.py |  16 ++-
  9 files changed, 76 insertions(+), 41 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -227,7 +227,7 @@
     """
     def _check_name_wrapper(self, name, *args, **kwargs):
         if self._name != name:
-            raise ImportError("loader cannot handle %s" % name)
+            raise ImportError("loader cannot handle %s" % name, name=name)
         return method(self, name, *args, **kwargs)
     _wrap(_check_name_wrapper, method)
     return _check_name_wrapper
@@ -237,7 +237,8 @@
     """Decorator to verify the named module is built-in."""
     def _requires_builtin_wrapper(self, fullname):
         if fullname not in sys.builtin_module_names:
-            raise ImportError("{0} is not a built-in module".format(fullname))
+            raise ImportError("{0} is not a built-in module".format(fullname),
+                              name=fullname)
         return fxn(self, fullname)
     _wrap(_requires_builtin_wrapper, fxn)
     return _requires_builtin_wrapper
@@ -247,7 +248,8 @@
     """Decorator to verify the named module is frozen."""
     def _requires_frozen_wrapper(self, fullname):
         if not imp.is_frozen(fullname):
-            raise ImportError("{0} is not a frozen module".format(fullname))
+            raise ImportError("{0} is not a frozen module".format(fullname),
+                              name=fullname)
         return fxn(self, fullname)
     _wrap(_requires_frozen_wrapper, fxn)
     return _requires_frozen_wrapper
@@ -372,7 +374,7 @@
         filename = self.get_filename(fullname).rpartition(path_sep)[2]
         return filename.rsplit('.', 1)[0] == '__init__'
 
-    def _bytes_from_bytecode(self, fullname, data, source_stats):
+    def _bytes_from_bytecode(self, fullname, data, bytecode_path, source_stats):
         """Return the marshalled bytes from bytecode, verifying the magic
         number, timestamp and source size along the way.
 
@@ -383,7 +385,8 @@
         raw_timestamp = data[4:8]
         raw_size = data[8:12]
         if len(magic) != 4 or magic != imp.get_magic():
-            raise ImportError("bad magic number in {}".format(fullname))
+            raise ImportError("bad magic number in {}".format(fullname),
+                              name=fullname, path=bytecode_path)
         elif len(raw_timestamp) != 4:
             raise EOFError("bad timestamp in {}".format(fullname))
         elif len(raw_size) != 4:
@@ -396,7 +399,8 @@
             else:
                 if _r_long(raw_timestamp) != source_mtime:
                     raise ImportError(
-                        "bytecode is stale for {}".format(fullname))
+                        "bytecode is stale for {}".format(fullname),
+                        name=fullname, path=bytecode_path)
             try:
                 source_size = source_stats['size'] & 0xFFFFFFFF
             except KeyError:
@@ -404,7 +408,8 @@
             else:
                 if _r_long(raw_size) != source_size:
                     raise ImportError(
-                        "bytecode is stale for {}".format(fullname))
+                        "bytecode is stale for {}".format(fullname),
+                        name=fullname, path=bytecode_path)
         # Can't return the code object as errors from marshal loading need to
         # propagate even when source is available.
         return data[12:]
@@ -466,7 +471,8 @@
         try:
             source_bytes = self.get_data(path)
         except IOError:
-            raise ImportError("source not available through get_data()")
+            raise ImportError("source not available through get_data()",
+                              name=fullname)
         encoding = tokenize.detect_encoding(_io.BytesIO(source_bytes).readline)
         newline_decoder = _io.IncrementalNewlineDecoder(None, True)
         return newline_decoder.decode(source_bytes.decode(encoding[0]))
@@ -495,6 +501,7 @@
                 else:
                     try:
                         bytes_data = self._bytes_from_bytecode(fullname, data,
+                                                               bytecode_path,
                                                                st)
                     except (ImportError, EOFError):
                         pass
@@ -505,7 +512,8 @@
                             return found
                         else:
                             msg = "Non-code object in {}"
-                            raise ImportError(msg.format(bytecode_path))
+                            raise ImportError(msg.format(bytecode_path),
+                                              name=fullname, path=bytecode_path)
         source_bytes = self.get_data(source_path)
         code_object = compile(source_bytes, source_path, 'exec',
                                 dont_inherit=True)
@@ -604,12 +612,13 @@
     def get_code(self, fullname):
         path = self.get_filename(fullname)
         data = self.get_data(path)
-        bytes_data = self._bytes_from_bytecode(fullname, data, None)
+        bytes_data = self._bytes_from_bytecode(fullname, data, path, None)
         found = marshal.loads(bytes_data)
         if isinstance(found, code_type):
             return found
         else:
-            raise ImportError("Non-code object in {}".format(path))
+            raise ImportError("Non-code object in {}".format(path),
+                              name=fullname, path=path)
 
     def get_source(self, fullname):
         """Return None as there is no source code."""
@@ -678,7 +687,8 @@
             except ImportError:
                 continue
         else:
-            raise ImportError("no path hook found for {0}".format(path))
+            raise ImportError("no path hook found for {0}".format(path),
+                              path=path)
 
     @classmethod
     def _path_importer_cache(cls, path, default=None):
@@ -836,7 +846,7 @@
                            _SourceFinderDetails(),
                            _SourcelessFinderDetails())
     else:
-        raise ImportError("only directories are supported")
+        raise ImportError("only directories are supported", path=path)
 
 
 _DEFAULT_PATH_HOOK = _file_path_hook
@@ -936,10 +946,10 @@
             path = parent_module.__path__
         except AttributeError:
             msg = (_ERR_MSG + '; {} is not a package').format(name, parent)
-            raise ImportError(msg)
+            raise ImportError(msg, name=name)
     loader = _find_module(name, path)
     if loader is None:
-        raise ImportError(_ERR_MSG.format(name))
+        raise ImportError(_ERR_MSG.format(name), name=name)
     elif name not in sys.modules:
         # The parent import may have already imported this module.
         loader.load_module(name)
@@ -978,7 +988,7 @@
             if module is None:
                 message = ("import of {} halted; "
                             "None in sys.modules".format(name))
-                raise ImportError(message)
+                raise ImportError(message, name=name)
             return module
         except KeyError:
             pass  # Don't want to chain the exception
diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
--- a/Lib/importlib/abc.py
+++ b/Lib/importlib/abc.py
@@ -207,7 +207,7 @@
                         DeprecationWarning)
         path = self.source_path(fullname)
         if path is None:
-            raise ImportError
+            raise ImportError(name=fullname)
         else:
             return path
 
@@ -235,7 +235,7 @@
         if path is not None:
             return path
         raise ImportError("no source or bytecode path available for "
-                            "{0!r}".format(fullname))
+                            "{0!r}".format(fullname), name=fullname)
 
     def get_code(self, fullname):
         """Get a code object from source or bytecode."""
@@ -253,7 +253,8 @@
                 magic = data[:4]
                 if len(magic) < 4:
                     raise ImportError(
-                        "bad magic number in {}".format(fullname))
+                        "bad magic number in {}".format(fullname),
+                        name=fullname, path=bytecode_path)
                 raw_timestamp = data[4:8]
                 if len(raw_timestamp) < 4:
                     raise EOFError("bad timestamp in {}".format(fullname))
@@ -262,12 +263,14 @@
                 # Verify that the magic number is valid.
                 if imp.get_magic() != magic:
                     raise ImportError(
-                        "bad magic number in {}".format(fullname))
+                        "bad magic number in {}".format(fullname),
+                        name=fullname, path=bytecode_path)
                 # Verify that the bytecode is not stale (only matters when
                 # there is source to fall back on.
                 if source_timestamp:
                     if pyc_timestamp < source_timestamp:
-                        raise ImportError("bytecode is stale")
+                        raise ImportError("bytecode is stale", name=fullname,
+                                          path=bytecode_path)
             except (ImportError, EOFError):
                 # If source is available give it a shot.
                 if source_timestamp is not None:
@@ -279,12 +282,13 @@
                 return marshal.loads(bytecode)
         elif source_timestamp is None:
             raise ImportError("no source or bytecode available to create code "
-                                "object for {0!r}".format(fullname))
+                              "object for {0!r}".format(fullname),
+                              name=fullname)
         # Use the source.
         source_path = self.source_path(fullname)
         if source_path is None:
             message = "a source path must exist to load {0}".format(fullname)
-            raise ImportError(message)
+            raise ImportError(message, name=fullname)
         source = self.get_data(source_path)
         code_object = compile(source, source_path, 'exec', dont_inherit=True)
         # Generate bytecode and write it out.
diff --git a/Lib/importlib/test/builtin/test_loader.py b/Lib/importlib/test/builtin/test_loader.py
--- a/Lib/importlib/test/builtin/test_loader.py
+++ b/Lib/importlib/test/builtin/test_loader.py
@@ -54,15 +54,17 @@
     def test_unloadable(self):
         name = 'dssdsdfff'
         assert name not in sys.builtin_module_names
-        with self.assertRaises(ImportError):
+        with self.assertRaises(ImportError) as cm:
             self.load_module(name)
+        self.assertEqual(cm.exception.name, name)
 
     def test_already_imported(self):
         # Using the name of a module already imported but not a built-in should
         # still fail.
         assert hasattr(importlib, '__file__')  # Not a built-in.
-        with self.assertRaises(ImportError):
+        with self.assertRaises(ImportError) as cm:
             self.load_module('importlib')
+        self.assertEqual(cm.exception.name, 'importlib')
 
 
 class InspectLoaderTests(unittest.TestCase):
@@ -88,8 +90,9 @@
         # Modules not built-in should raise ImportError.
         for meth_name in ('get_code', 'get_source', 'is_package'):
             method = getattr(machinery.BuiltinImporter, meth_name)
-        with self.assertRaises(ImportError):
+        with self.assertRaises(ImportError) as cm:
             method(builtin_util.BAD_NAME)
+        self.assertRaises(builtin_util.BAD_NAME)
 
 
 
diff --git a/Lib/importlib/test/extension/test_loader.py b/Lib/importlib/test/extension/test_loader.py
--- a/Lib/importlib/test/extension/test_loader.py
+++ b/Lib/importlib/test/extension/test_loader.py
@@ -46,8 +46,10 @@
         pass
 
     def test_unloadable(self):
-        with self.assertRaises(ImportError):
-            self.load_module('asdfjkl;')
+        name = 'asdfjkl;'
+        with self.assertRaises(ImportError) as cm:
+            self.load_module(name)
+        self.assertEqual(cm.exception.name, name)
 
 
 def test_main():
diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/importlib/test/frozen/test_loader.py
--- a/Lib/importlib/test/frozen/test_loader.py
+++ b/Lib/importlib/test/frozen/test_loader.py
@@ -57,8 +57,9 @@
 
     def test_unloadable(self):
         assert machinery.FrozenImporter.find_module('_not_real') is None
-        with self.assertRaises(ImportError):
+        with self.assertRaises(ImportError) as cm:
             machinery.FrozenImporter.load_module('_not_real')
+        self.assertEqual(cm.exception.name, '_not_real')
 
 
 class InspectLoaderTests(unittest.TestCase):
@@ -92,8 +93,9 @@
         # Raise ImportError for modules that are not frozen.
         for meth_name in ('get_code', 'get_source', 'is_package'):
             method = getattr(machinery.FrozenImporter, meth_name)
-            with self.assertRaises(ImportError):
+            with self.assertRaises(ImportError) as cm:
                 method('importlib')
+            self.assertEqual(cm.exception.name, 'importlib')
 
 
 def test_main():
diff --git a/Lib/importlib/test/import_/test_caching.py b/Lib/importlib/test/import_/test_caching.py
--- a/Lib/importlib/test/import_/test_caching.py
+++ b/Lib/importlib/test/import_/test_caching.py
@@ -34,8 +34,9 @@
         name = 'using_None'
         with util.uncache(name):
             sys.modules[name] = None
-            with self.assertRaises(ImportError):
+            with self.assertRaises(ImportError) as cm:
                 import_util.import_(name)
+            self.assertEqual(cm.exception.name, name)
 
     def create_mock(self, *names, return_=None):
         mock = util.mock_modules(*names)
diff --git a/Lib/importlib/test/import_/test_packages.py b/Lib/importlib/test/import_/test_packages.py
--- a/Lib/importlib/test/import_/test_packages.py
+++ b/Lib/importlib/test/import_/test_packages.py
@@ -19,14 +19,16 @@
     def test_bad_parent(self):
         with util.mock_modules('pkg.module') as mock:
             with util.import_state(meta_path=[mock]):
-                with self.assertRaises(ImportError):
+                with self.assertRaises(ImportError) as cm:
                     import_util.import_('pkg.module')
+                self.assertEqual(cm.exception.name, 'pkg')
 
     def test_module_not_package(self):
         # Try to import a submodule from a non-package should raise ImportError.
         assert not hasattr(sys, '__path__')
-        with self.assertRaises(ImportError):
+        with self.assertRaises(ImportError) as cm:
             import_util.import_('sys.no_submodules_here')
+        self.assertEqual(cm.exception.name, 'sys.no_submodules_here')
 
     def test_module_not_package_but_side_effects(self):
         # If a module injects something into sys.modules as a side-effect, then
diff --git a/Lib/importlib/test/source/test_abc_loader.py b/Lib/importlib/test/source/test_abc_loader.py
--- a/Lib/importlib/test/source/test_abc_loader.py
+++ b/Lib/importlib/test/source/test_abc_loader.py
@@ -471,8 +471,9 @@
                 {'path': os.path.join('path', 'to', 'mod'),
                  'magic': bad_magic}}
         mock = PyPycLoaderMock({name: None}, bc)
-        with util.uncache(name), self.assertRaises(ImportError):
+        with util.uncache(name), self.assertRaises(ImportError) as cm:
             mock.load_module(name)
+        self.assertEqual(cm.exception.name, name)
 
     def test_no_bytecode(self):
         # Missing code object bytecode should lead to an EOFError.
@@ -516,8 +517,9 @@
         # If all *_path methods return None, raise ImportError.
         name = 'mod'
         mock = PyPycLoaderMock({name: None})
-        with util.uncache(name), self.assertRaises(ImportError):
+        with util.uncache(name), self.assertRaises(ImportError) as cm:
             mock.load_module(name)
+        self.assertEqual(cm.exception.name, name)
 
     def test_source_path_ImportError(self):
         # An ImportError from source_path should trigger an ImportError.
@@ -533,7 +535,7 @@
         mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')})
         bad_meth = types.MethodType(raise_ImportError, mock)
         mock.bytecode_path = bad_meth
-        with util.uncache(name), self.assertRaises(ImportError):
+        with util.uncache(name), self.assertRaises(ImportError) as cm:
             mock.load_module(name)
 
 
@@ -594,8 +596,9 @@
         def raise_IOError(path):
             raise IOError
         self.loader.get_data = raise_IOError
-        with self.assertRaises(ImportError):
+        with self.assertRaises(ImportError) as cm:
             self.loader.get_source(self.name)
+        self.assertEqual(cm.exception.name, self.name)
 
     def test_is_package(self):
         # Properly detect when loading a package.
diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py
--- a/Lib/importlib/test/source/test_file_loader.py
+++ b/Lib/importlib/test/source/test_file_loader.py
@@ -232,8 +232,10 @@
                                     lambda bc: bc[:12] + marshal.dumps(b'abcd'),
                                     del_source=del_source)
             file_path = mapping['_temp'] if not del_source else bytecode_path
-            with self.assertRaises(ImportError):
+            with self.assertRaises(ImportError) as cm:
                 self.import_(file_path, '_temp')
+            self.assertEqual(cm.exception.name, '_temp')
+            self.assertEqual(cm.exception.path, bytecode_path)
 
     def _test_bad_marshal(self, *, del_source=False):
         with source_util.create_modules('_temp') as mapping:
@@ -381,15 +383,19 @@
 
     def test_empty_file(self):
         def test(name, mapping, bytecode_path):
-            with self.assertRaises(ImportError):
+            with self.assertRaises(ImportError) as cm:
                 self.import_(bytecode_path, name)
+            self.assertEqual(cm.exception.name, name)
+            self.assertEqual(cm.exception.path, bytecode_path)
 
         self._test_empty_file(test, del_source=True)
 
     def test_partial_magic(self):
         def test(name, mapping, bytecode_path):
-            with self.assertRaises(ImportError):
+            with self.assertRaises(ImportError) as cm:
                 self.import_(bytecode_path, name)
+            self.assertEqual(cm.exception.name, name)
+            self.assertEqual(cm.exception.path, bytecode_path)
         self._test_partial_magic(test, del_source=True)
 
     def test_magic_only(self):
@@ -401,8 +407,10 @@
 
     def test_bad_magic(self):
         def test(name, mapping, bytecode_path):
-            with self.assertRaises(ImportError):
+            with self.assertRaises(ImportError) as cm:
                 self.import_(bytecode_path, name)
+            self.assertEqual(cm.exception.name, name)
+            self.assertEqual(cm.exception.path, bytecode_path)
 
         self._test_bad_magic(test, del_source=True)
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list