mirror of
https://github.com/python/cpython.git
synced 2025-09-20 07:31:10 +00:00
Issue #13591: import_module potentially imports a module twice.
This commit is contained in:
parent
061c0289af
commit
416f12ddb3
4 changed files with 29 additions and 2 deletions
|
@ -816,7 +816,9 @@ def _gcd_import(name, package=None, level=0):
|
||||||
for finder in meta_path:
|
for finder in meta_path:
|
||||||
loader = finder.find_module(name, path)
|
loader = finder.find_module(name, path)
|
||||||
if loader is not None:
|
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
|
break
|
||||||
else:
|
else:
|
||||||
raise ImportError(_ERR_MSG.format(name))
|
raise ImportError(_ERR_MSG.format(name))
|
||||||
|
|
|
@ -67,6 +67,23 @@ class ImportModuleTests(unittest.TestCase):
|
||||||
importlib.import_module('.support')
|
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():
|
def test_main():
|
||||||
from test.support import run_unittest
|
from test.support import run_unittest
|
||||||
run_unittest(ImportModuleTests)
|
run_unittest(ImportModuleTests)
|
||||||
|
|
|
@ -84,8 +84,9 @@ class mock_modules:
|
||||||
|
|
||||||
"""A mock importer/loader."""
|
"""A mock importer/loader."""
|
||||||
|
|
||||||
def __init__(self, *names):
|
def __init__(self, *names, module_code={}):
|
||||||
self.modules = {}
|
self.modules = {}
|
||||||
|
self.module_code = {}
|
||||||
for name in names:
|
for name in names:
|
||||||
if not name.endswith('.__init__'):
|
if not name.endswith('.__init__'):
|
||||||
import_name = name
|
import_name = name
|
||||||
|
@ -105,6 +106,8 @@ class mock_modules:
|
||||||
if import_name != name:
|
if import_name != name:
|
||||||
module.__path__ = ['<mock __path__>']
|
module.__path__ = ['<mock __path__>']
|
||||||
self.modules[import_name] = module
|
self.modules[import_name] = module
|
||||||
|
if import_name in module_code:
|
||||||
|
self.module_code[import_name] = module_code[import_name]
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
return self.modules[name]
|
return self.modules[name]
|
||||||
|
@ -120,6 +123,8 @@ class mock_modules:
|
||||||
raise ImportError
|
raise ImportError
|
||||||
else:
|
else:
|
||||||
sys.modules[fullname] = self.modules[fullname]
|
sys.modules[fullname] = self.modules[fullname]
|
||||||
|
if fullname in self.module_code:
|
||||||
|
self.module_code[fullname]()
|
||||||
return self.modules[fullname]
|
return self.modules[fullname]
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
|
|
@ -1868,6 +1868,9 @@ Core and Builtins
|
||||||
Library
|
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
|
- logging: added "handler of last resort". See http://bit.ly/last-resort-handler
|
||||||
|
|
||||||
- test.support: Added TestHandler and Matcher classes for better support of
|
- test.support: Added TestHandler and Matcher classes for better support of
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue