[Python-checkins] cpython (3.2): Issue #13591: import_module potentially imports a module twice.

meador.inge python-checkins at python.org
Thu Dec 15 05:28:04 CET 2011


http://hg.python.org/cpython/rev/d2504d30f259
changeset:   73973:d2504d30f259
branch:      3.2
parent:      73971:f1fe411bfd6b
user:        Meador Inge <meadori at gmail.com>
date:        Wed Dec 14 22:23:46 2011 -0600
summary:
  Issue #13591: import_module potentially imports a module twice.

files:
  Lib/importlib/_bootstrap.py    |   4 +++-
  Lib/importlib/test/test_api.py |  17 +++++++++++++++++
  Lib/importlib/test/util.py     |   7 ++++++-
  Misc/NEWS                      |   3 +++
  4 files changed, 29 insertions(+), 2 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -816,7 +816,9 @@
         for finder in meta_path:
             loader = finder.find_module(name, path)
             if loader is not None:
-                loader.load_module(name)
+                # The parent import may have already imported this module.
+                if name not in sys.modules:
+                    loader.load_module(name)
                 break
         else:
             raise ImportError(_ERR_MSG.format(name))
diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py
--- a/Lib/importlib/test/test_api.py
+++ b/Lib/importlib/test/test_api.py
@@ -67,6 +67,23 @@
             importlib.import_module('.support')
 
 
+    def test_loaded_once(self):
+        # Issue #13591: Modules should only be loaded once when
+        # initializing the parent package attempts to import the
+        # module currently being imported.
+        b_load_count = 0
+        def load_a():
+            importlib.import_module('a.b')
+        def load_b():
+            nonlocal b_load_count
+            b_load_count += 1
+        code = {'a': load_a, 'a.b': load_b}
+        modules = ['a.__init__', 'a.b']
+        with util.mock_modules(*modules, module_code=code) as mock:
+            with util.import_state(meta_path=[mock]):
+                importlib.import_module('a.b')
+        self.assertEqual(b_load_count, 1)
+
 def test_main():
     from test.support import run_unittest
     run_unittest(ImportModuleTests)
diff --git a/Lib/importlib/test/util.py b/Lib/importlib/test/util.py
--- a/Lib/importlib/test/util.py
+++ b/Lib/importlib/test/util.py
@@ -84,8 +84,9 @@
 
     """A mock importer/loader."""
 
-    def __init__(self, *names):
+    def __init__(self, *names, module_code={}):
         self.modules = {}
+        self.module_code = {}
         for name in names:
             if not name.endswith('.__init__'):
                 import_name = name
@@ -105,6 +106,8 @@
             if import_name != name:
                 module.__path__ = ['<mock __path__>']
             self.modules[import_name] = module
+            if import_name in module_code:
+                self.module_code[import_name] = module_code[import_name]
 
     def __getitem__(self, name):
         return self.modules[name]
@@ -120,6 +123,8 @@
             raise ImportError
         else:
             sys.modules[fullname] = self.modules[fullname]
+            if fullname in self.module_code:
+                self.module_code[fullname]()
             return self.modules[fullname]
 
     def __enter__(self):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1868,6 +1868,9 @@
 Library
 -------
 
+- Issue #13591: A bug in importlib has been fixed that caused import_module
+  to load a module twice.
+
 - logging: added "handler of last resort". See http://bit.ly/last-resort-handler
 
 - test.support: Added TestHandler and Matcher classes for better support of

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


More information about the Python-checkins mailing list