]> granicus.if.org Git - python/commitdiff
Issue #13591: import_module potentially imports a module twice.
authorMeador Inge <meadori@gmail.com>
Thu, 15 Dec 2011 04:23:46 +0000 (22:23 -0600)
committerMeador Inge <meadori@gmail.com>
Thu, 15 Dec 2011 04:23:46 +0000 (22:23 -0600)
Lib/importlib/_bootstrap.py
Lib/importlib/test/test_api.py
Lib/importlib/test/util.py
Misc/NEWS

index 425b8bf8c79ffd54cf3ddae2d7dbae89df49857a..90eb1a770f9da403416ea97bf094b41296282641 100644 (file)
@@ -816,7 +816,9 @@ def _gcd_import(name, package=None, level=0):
         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))
index 0ffa3c4d8072c494ed44c47386909da23291fa01..a151626de7d2fdbac56e76b193f14b21d77f89b6 100644 (file)
@@ -67,6 +67,23 @@ class ImportModuleTests(unittest.TestCase):
             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)
index 0c0c84c310bd3ed6d67c48bed5922ebcce3e44d3..93b7cd2861b96de11adf6c3298edbd8a9f1f8edc 100644 (file)
@@ -84,8 +84,9 @@ class mock_modules:
 
     """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 @@ class mock_modules:
             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 @@ class mock_modules:
             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):
index c996499c53e2243f363e2a46d46cfe3866ea0ea9..15c07f5e3f1a8bb62c3ca737928be249836616e9 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1868,6 +1868,9 @@ Core and Builtins
 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