summaryrefslogtreecommitdiffstats
path: root/Lib/importlib
diff options
context:
space:
mode:
authorMeador Inge <meadori@gmail.com>2011-12-15 04:27:28 (GMT)
committerMeador Inge <meadori@gmail.com>2011-12-15 04:27:28 (GMT)
commitd7afeeeb8dc8b4e2e59951a15b68f362282d447e (patch)
tree6e05ec5b94407e928228641563b41a47184137ee /Lib/importlib
parentabbcd0872fc970bb83d8ff5f0f09ca988c172360 (diff)
parent416f12ddb3b7d780bb75563414b88b32c0cf7e67 (diff)
downloadcpython-d7afeeeb8dc8b4e2e59951a15b68f362282d447e.zip
cpython-d7afeeeb8dc8b4e2e59951a15b68f362282d447e.tar.gz
cpython-d7afeeeb8dc8b4e2e59951a15b68f362282d447e.tar.bz2
Issue #13591: import_module potentially imports a module twice.
Diffstat (limited to 'Lib/importlib')
-rw-r--r--Lib/importlib/_bootstrap.py4
-rw-r--r--Lib/importlib/test/test_api.py17
-rw-r--r--Lib/importlib/test/util.py7
3 files changed, 26 insertions, 2 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 359b9e7..25533fc 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -837,7 +837,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))
diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py
index 0ffa3c4..a151626 100644
--- a/Lib/importlib/test/test_api.py
+++ b/Lib/importlib/test/test_api.py
@@ -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)
diff --git a/Lib/importlib/test/util.py b/Lib/importlib/test/util.py
index 0c0c84c..93b7cd2 100644
--- a/Lib/importlib/test/util.py
+++ b/Lib/importlib/test/util.py
@@ -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):