mirror of https://github.com/python/cpython.git
Issue #19413: Restore pre-3.3 reload() semantics of re-finding modules.
This commit is contained in:
parent
dcdd05b0b4
commit
cdf601281f
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 @@ def code():
|
|||
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:
|
||||
|
|
|
@ -127,6 +127,8 @@ Library
|
|||
- Issue #8964: fix platform._sys_version to handle IronPython 2.6+.
|
||||
Patch by Martin Matusiak.
|
||||
|
||||
- Issue #19413: Restore pre-3.3 reload() semantics of re-finding modules.
|
||||
|
||||
- Issue #18958: Improve error message for json.load(s) while passing a string
|
||||
that starts with a UTF-8 BOM.
|
||||
|
||||
|
|
1011
Python/importlib.h
1011
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue