(original) (raw)
changeset: 73973:d2504d30f259 branch: 3.2 parent: 73971:f1fe411bfd6b user: Meador Inge meadori@gmail.com date: Wed Dec 14 22:23:46 2011 -0600 files: Lib/importlib/_bootstrap.py Lib/importlib/test/test_api.py Lib/importlib/test/util.py Misc/NEWS description: Issue #13591: import_module potentially imports a module twice. diff -r f1fe411bfd6b -r d2504d30f259 Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py Wed Dec 14 15:06:50 2011 -0800 +++ b/Lib/importlib/_bootstrap.py Wed Dec 14 22:23:46 2011 -0600 @@ -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 -r f1fe411bfd6b -r d2504d30f259 Lib/importlib/test/test_api.py --- a/Lib/importlib/test/test_api.py Wed Dec 14 15:06:50 2011 -0800 +++ b/Lib/importlib/test/test_api.py Wed Dec 14 22:23:46 2011 -0600 @@ -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 -r f1fe411bfd6b -r d2504d30f259 Lib/importlib/test/util.py --- a/Lib/importlib/test/util.py Wed Dec 14 15:06:50 2011 -0800 +++ b/Lib/importlib/test/util.py Wed Dec 14 22:23:46 2011 -0600 @@ -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__ = [''] 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 -r f1fe411bfd6b -r d2504d30f259 Misc/NEWS --- a/Misc/NEWS Wed Dec 14 15:06:50 2011 -0800 +++ b/Misc/NEWS Wed Dec 14 22:23:46 2011 -0600 @@ -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/meadori@gmail.com