mirror of https://github.com/python/cpython
Issue #13591: import_module potentially imports a module twice.
This commit is contained in:
commit
d7afeeeb8d
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -2548,6 +2548,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
|
||||
|
|
Loading…
Reference in New Issue