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):
|
if not module or not isinstance(module, types.ModuleType):
|
||||||
raise TypeError("reload() argument must be module")
|
raise TypeError("reload() argument must be module")
|
||||||
name = module.__name__
|
name = module.__name__
|
||||||
if name not in sys.modules:
|
if sys.modules.get(name) is not module:
|
||||||
msg = "module {} not in sys.modules"
|
msg = "module {} not in sys.modules"
|
||||||
raise ImportError(msg.format(name), name=name)
|
raise ImportError(msg.format(name), name=name)
|
||||||
if name in _RELOADING:
|
if name in _RELOADING:
|
||||||
@ -118,7 +118,11 @@ def reload(module):
|
|||||||
if parent_name and parent_name not in sys.modules:
|
if parent_name and parent_name not in sys.modules:
|
||||||
msg = "parent {!r} not in sys.modules"
|
msg = "parent {!r} not in sys.modules"
|
||||||
raise ImportError(msg.format(parent_name), name=parent_name)
|
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!
|
# The module may have replaced itself in sys.modules!
|
||||||
return sys.modules[module.__name__]
|
return sys.modules[module.__name__]
|
||||||
finally:
|
finally:
|
||||||
|
@ -1510,15 +1510,19 @@ def _find_module(name, path):
|
|||||||
"""Find a module's loader."""
|
"""Find a module's loader."""
|
||||||
if not sys.meta_path:
|
if not sys.meta_path:
|
||||||
_warnings.warn('sys.meta_path is empty', ImportWarning)
|
_warnings.warn('sys.meta_path is empty', ImportWarning)
|
||||||
|
is_reload = name in sys.modules
|
||||||
for finder in sys.meta_path:
|
for finder in sys.meta_path:
|
||||||
with _ImportLockContext():
|
with _ImportLockContext():
|
||||||
loader = finder.find_module(name, path)
|
loader = finder.find_module(name, path)
|
||||||
if loader is not None:
|
if loader is not None:
|
||||||
# The parent import may have already imported this module.
|
# 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
|
return loader
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
return sys.modules[name].__loader__
|
return sys.modules[name].__loader__
|
||||||
|
except AttributeError:
|
||||||
|
return loader
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
frozen_init, source_init = util.import_importlib('importlib')
|
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')
|
frozen_machinery, source_machinery = util.import_importlib('importlib.machinery')
|
||||||
|
|
||||||
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
from test import support
|
from test import support
|
||||||
import types
|
import types
|
||||||
@ -190,11 +192,129 @@ class ReloadTests:
|
|||||||
self.assertEqual(actual.spam, 3)
|
self.assertEqual(actual.spam, 3)
|
||||||
self.assertEqual(reloaded.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):
|
class Frozen_ReloadTests(ReloadTests, unittest.TestCase):
|
||||||
init = frozen_init
|
init = frozen_init
|
||||||
|
util = frozen_util
|
||||||
|
|
||||||
class Source_ReloadTests(ReloadTests, unittest.TestCase):
|
class Source_ReloadTests(ReloadTests, unittest.TestCase):
|
||||||
init = source_init
|
init = source_init
|
||||||
|
util = source_util
|
||||||
|
|
||||||
|
|
||||||
class InvalidateCacheTests:
|
class InvalidateCacheTests:
|
||||||
|
@ -127,6 +127,8 @@ Library
|
|||||||
- Issue #8964: fix platform._sys_version to handle IronPython 2.6+.
|
- Issue #8964: fix platform._sys_version to handle IronPython 2.6+.
|
||||||
Patch by Martin Matusiak.
|
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
|
- Issue #18958: Improve error message for json.load(s) while passing a string
|
||||||
that starts with a UTF-8 BOM.
|
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…
x
Reference in New Issue
Block a user