diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2013-11-01 04:22:15 (GMT) |
---|---|---|
committer | Eric Snow <ericsnowcurrently@gmail.com> | 2013-11-01 04:22:15 (GMT) |
commit | cdf601281f5909b4b7c6e1f10f3a80d3c216cdc3 (patch) | |
tree | 2bea84bd69350b853084377ab70bd17254bd4010 /Lib | |
parent | dcdd05b0b4c23da0eb39d3b29d40f8865b6b73ee (diff) | |
download | cpython-cdf601281f5909b4b7c6e1f10f3a80d3c216cdc3.zip cpython-cdf601281f5909b4b7c6e1f10f3a80d3c216cdc3.tar.gz cpython-cdf601281f5909b4b7c6e1f10f3a80d3c216cdc3.tar.bz2 |
Issue #19413: Restore pre-3.3 reload() semantics of re-finding modules.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/importlib/__init__.py | 8 | ||||
-rw-r--r-- | Lib/importlib/_bootstrap.py | 8 | ||||
-rw-r--r-- | Lib/test/test_importlib/test_api.py | 120 |
3 files changed, 132 insertions, 4 deletions
diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index 69ca9ce..e56e9c3 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -107,7 +107,7 @@ def reload(module): if not module or not isinstance(module, types.ModuleType): raise TypeError("reload() argument must be module") name = module.__name__ - if name not in sys.modules: + if sys.modules.get(name) is not module: msg = "module {} not in sys.modules" raise ImportError(msg.format(name), name=name) if name in _RELOADING: @@ -118,7 +118,11 @@ def reload(module): if parent_name and parent_name not in sys.modules: msg = "parent {!r} not in sys.modules" raise ImportError(msg.format(parent_name), name=parent_name) - module.__loader__.load_module(name) + loader = _bootstrap._find_module(name, None) + if loader is None: + raise ImportError(_bootstrap._ERR_MSG.format(name), name=name) + module.__loader__ = loader + loader.load_module(name) # The module may have replaced itself in sys.modules! return sys.modules[module.__name__] finally: diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index ec10532..a06a02f 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1510,15 +1510,19 @@ def _find_module(name, path): """Find a module's loader.""" if not sys.meta_path: _warnings.warn('sys.meta_path is empty', ImportWarning) + is_reload = name in sys.modules for finder in sys.meta_path: with _ImportLockContext(): loader = finder.find_module(name, path) if loader is not None: # The parent import may have already imported this module. - if name not in sys.modules: + if is_reload or name not in sys.modules: return loader else: - return sys.modules[name].__loader__ + try: + return sys.modules[name].__loader__ + except AttributeError: + return loader else: return None diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 5843a5c..1fa905c 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -1,8 +1,10 @@ from . import util frozen_init, source_init = util.import_importlib('importlib') +frozen_util, source_util = util.import_importlib('importlib.util') frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') +import os.path import sys from test import support import types @@ -190,11 +192,129 @@ class ReloadTests: self.assertEqual(actual.spam, 3) self.assertEqual(reloaded.spam, 3) + def test_reload_missing_loader(self): + with support.CleanImport('types'): + import types + loader = types.__loader__ + del types.__loader__ + reloaded = self.init.reload(types) + + self.assertIs(reloaded, types) + self.assertIs(sys.modules['types'], types) + self.assertEqual(reloaded.__loader__.path, loader.path) + + def test_reload_loader_replaced(self): + with support.CleanImport('types'): + import types + types.__loader__ = None + self.init.invalidate_caches() + reloaded = self.init.reload(types) + + self.assertIsNot(reloaded.__loader__, None) + self.assertIs(reloaded, types) + self.assertIs(sys.modules['types'], types) + + def test_reload_location_changed(self): + name = 'spam' + with support.temp_cwd(None) as cwd: + with util.uncache('spam'): + with support.DirsOnSysPath(cwd): + self.init.invalidate_caches() + path = os.path.join(cwd, name + '.py') + cached = self.util.cache_from_source(path) + expected = {'__name__': name, + '__package__': '', + '__file__': path, + '__cached__': cached, + '__doc__': None, + '__builtins__': __builtins__, + } + support.create_empty_file(path) + module = self.init.import_module(name) + ns = vars(module) + del ns['__initializing__'] + loader = ns.pop('__loader__') + self.assertEqual(loader.path, path) + self.assertEqual(ns, expected) + + self.init.invalidate_caches() + init_path = os.path.join(cwd, name, '__init__.py') + cached = self.util.cache_from_source(init_path) + expected = {'__name__': name, + '__package__': name, + '__file__': init_path, + '__cached__': cached, + '__path__': [os.path.dirname(init_path)], + '__doc__': None, + '__builtins__': __builtins__, + } + os.mkdir(name) + os.rename(path, init_path) + reloaded = self.init.reload(module) + ns = vars(reloaded) + del ns['__initializing__'] + loader = ns.pop('__loader__') + self.assertIs(reloaded, module) + self.assertEqual(loader.path, init_path) + self.assertEqual(ns, expected) + + def test_reload_namespace_changed(self): + self.maxDiff = None + name = 'spam' + with support.temp_cwd(None) as cwd: + with util.uncache('spam'): + with support.DirsOnSysPath(cwd): + self.init.invalidate_caches() + bad_path = os.path.join(cwd, name, '__init.py') + cached = self.util.cache_from_source(bad_path) + expected = {'__name__': name, + '__package__': name, + '__doc__': None, + } + os.mkdir(name) + with open(bad_path, 'w') as init_file: + init_file.write('eggs = None') + module = self.init.import_module(name) + ns = vars(module) + del ns['__initializing__'] + loader = ns.pop('__loader__') + path = ns.pop('__path__') + self.assertEqual(list(path), + [os.path.dirname(bad_path)] * 2) + with self.assertRaises(AttributeError): + # a NamespaceLoader + loader.path + self.assertEqual(ns, expected) + + self.init.invalidate_caches() + init_path = os.path.join(cwd, name, '__init__.py') + cached = self.util.cache_from_source(init_path) + expected = {'__name__': name, + '__package__': name, + '__file__': init_path, + '__cached__': cached, + '__path__': [os.path.dirname(init_path)], + '__doc__': None, + '__builtins__': __builtins__, + 'eggs': None, + } + os.rename(bad_path, init_path) + reloaded = self.init.reload(module) + ns = vars(reloaded) + del ns['__initializing__'] + loader = ns.pop('__loader__') + self.assertIs(reloaded, module) + self.assertEqual(loader.path, init_path) + self.assertEqual(ns, expected) + + class Frozen_ReloadTests(ReloadTests, unittest.TestCase): init = frozen_init + util = frozen_util class Source_ReloadTests(ReloadTests, unittest.TestCase): init = source_init + util = source_util class InvalidateCacheTests: |