mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-33331: Clean modules in the reversed order in PyImport_Cleanup(). (GH-6565)
Modules imported last are now cleared first at interpreter shutdown. A newly imported module is moved to the end of sys.modules, behind modules on which it depends.
This commit is contained in:
parent
542497aa9f
commit
c93c58b5d5
4 changed files with 1818 additions and 1850 deletions
|
@ -302,33 +302,6 @@ def _module_repr(module):
|
||||||
return '<module {!r} from {!r}>'.format(name, filename)
|
return '<module {!r} from {!r}>'.format(name, filename)
|
||||||
|
|
||||||
|
|
||||||
class _installed_safely:
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
self._module = module
|
|
||||||
self._spec = module.__spec__
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
# This must be done before putting the module in sys.modules
|
|
||||||
# (otherwise an optimization shortcut in import.c becomes
|
|
||||||
# wrong)
|
|
||||||
self._spec._initializing = True
|
|
||||||
sys.modules[self._spec.name] = self._module
|
|
||||||
|
|
||||||
def __exit__(self, *args):
|
|
||||||
try:
|
|
||||||
spec = self._spec
|
|
||||||
if any(arg is not None for arg in args):
|
|
||||||
try:
|
|
||||||
del sys.modules[spec.name]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
_verbose_message('import {!r} # {!r}', spec.name, spec.loader)
|
|
||||||
finally:
|
|
||||||
self._spec._initializing = False
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleSpec:
|
class ModuleSpec:
|
||||||
"""The specification for a module, used for loading.
|
"""The specification for a module, used for loading.
|
||||||
|
|
||||||
|
@ -614,12 +587,13 @@ def _exec(spec, module):
|
||||||
if sys.modules.get(name) is not module:
|
if sys.modules.get(name) is not module:
|
||||||
msg = 'module {!r} not in sys.modules'.format(name)
|
msg = 'module {!r} not in sys.modules'.format(name)
|
||||||
raise ImportError(msg, name=name)
|
raise ImportError(msg, name=name)
|
||||||
|
try:
|
||||||
if spec.loader is None:
|
if spec.loader is None:
|
||||||
if spec.submodule_search_locations is None:
|
if spec.submodule_search_locations is None:
|
||||||
raise ImportError('missing loader', name=spec.name)
|
raise ImportError('missing loader', name=spec.name)
|
||||||
# namespace package
|
# Namespace package.
|
||||||
_init_module_attrs(spec, module, override=True)
|
_init_module_attrs(spec, module, override=True)
|
||||||
return module
|
else:
|
||||||
_init_module_attrs(spec, module, override=True)
|
_init_module_attrs(spec, module, override=True)
|
||||||
if not hasattr(spec.loader, 'exec_module'):
|
if not hasattr(spec.loader, 'exec_module'):
|
||||||
# (issue19713) Once BuiltinImporter and ExtensionFileLoader
|
# (issue19713) Once BuiltinImporter and ExtensionFileLoader
|
||||||
|
@ -628,16 +602,29 @@ def _exec(spec, module):
|
||||||
spec.loader.load_module(name)
|
spec.loader.load_module(name)
|
||||||
else:
|
else:
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
return sys.modules[name]
|
finally:
|
||||||
|
# Update the order of insertion into sys.modules for module
|
||||||
|
# clean-up at shutdown.
|
||||||
|
module = sys.modules.pop(spec.name)
|
||||||
|
sys.modules[spec.name] = module
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
def _load_backward_compatible(spec):
|
def _load_backward_compatible(spec):
|
||||||
# (issue19713) Once BuiltinImporter and ExtensionFileLoader
|
# (issue19713) Once BuiltinImporter and ExtensionFileLoader
|
||||||
# have exec_module() implemented, we can add a deprecation
|
# have exec_module() implemented, we can add a deprecation
|
||||||
# warning here.
|
# warning here.
|
||||||
|
try:
|
||||||
spec.loader.load_module(spec.name)
|
spec.loader.load_module(spec.name)
|
||||||
|
except:
|
||||||
|
if spec.name in sys.modules:
|
||||||
|
module = sys.modules.pop(spec.name)
|
||||||
|
sys.modules[spec.name] = module
|
||||||
|
raise
|
||||||
# The module must be in sys.modules at this point!
|
# The module must be in sys.modules at this point!
|
||||||
module = sys.modules[spec.name]
|
# Move it to the end of sys.modules.
|
||||||
|
module = sys.modules.pop(spec.name)
|
||||||
|
sys.modules[spec.name] = module
|
||||||
if getattr(module, '__loader__', None) is None:
|
if getattr(module, '__loader__', None) is None:
|
||||||
try:
|
try:
|
||||||
module.__loader__ = spec.loader
|
module.__loader__ = spec.loader
|
||||||
|
@ -663,23 +650,42 @@ def _load_backward_compatible(spec):
|
||||||
def _load_unlocked(spec):
|
def _load_unlocked(spec):
|
||||||
# A helper for direct use by the import system.
|
# A helper for direct use by the import system.
|
||||||
if spec.loader is not None:
|
if spec.loader is not None:
|
||||||
# not a namespace package
|
# Not a namespace package.
|
||||||
if not hasattr(spec.loader, 'exec_module'):
|
if not hasattr(spec.loader, 'exec_module'):
|
||||||
return _load_backward_compatible(spec)
|
return _load_backward_compatible(spec)
|
||||||
|
|
||||||
module = module_from_spec(spec)
|
module = module_from_spec(spec)
|
||||||
with _installed_safely(module):
|
|
||||||
|
# This must be done before putting the module in sys.modules
|
||||||
|
# (otherwise an optimization shortcut in import.c becomes
|
||||||
|
# wrong).
|
||||||
|
spec._initializing = True
|
||||||
|
try:
|
||||||
|
sys.modules[spec.name] = module
|
||||||
|
try:
|
||||||
if spec.loader is None:
|
if spec.loader is None:
|
||||||
if spec.submodule_search_locations is None:
|
if spec.submodule_search_locations is None:
|
||||||
raise ImportError('missing loader', name=spec.name)
|
raise ImportError('missing loader', name=spec.name)
|
||||||
# A namespace package so do nothing.
|
# A namespace package so do nothing.
|
||||||
else:
|
else:
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
del sys.modules[spec.name]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
raise
|
||||||
|
# Move the module to the end of sys.modules.
|
||||||
# We don't ensure that the import-related module attributes get
|
# We don't ensure that the import-related module attributes get
|
||||||
# set in the sys.modules replacement case. Such modules are on
|
# set in the sys.modules replacement case. Such modules are on
|
||||||
# their own.
|
# their own.
|
||||||
return sys.modules[spec.name]
|
module = sys.modules.pop(spec.name)
|
||||||
|
sys.modules[spec.name] = module
|
||||||
|
_verbose_message('import {!r} # {!r}', spec.name, spec.loader)
|
||||||
|
finally:
|
||||||
|
spec._initializing = False
|
||||||
|
|
||||||
|
return module
|
||||||
|
|
||||||
# A method used during testing of _load_unlocked() and by
|
# A method used during testing of _load_unlocked() and by
|
||||||
# _load_module_shim().
|
# _load_module_shim().
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Modules imported last are now cleared first at interpreter shutdown.
|
|
@ -543,9 +543,10 @@ PyImport_Cleanup(void)
|
||||||
module last. Likewise, we don't delete sys until the very
|
module last. Likewise, we don't delete sys until the very
|
||||||
end because it is implicitly referenced (e.g. by print). */
|
end because it is implicitly referenced (e.g. by print). */
|
||||||
if (weaklist != NULL) {
|
if (weaklist != NULL) {
|
||||||
Py_ssize_t i, n;
|
Py_ssize_t i;
|
||||||
n = PyList_GET_SIZE(weaklist);
|
/* Since dict is ordered in CPython 3.6+, modules are saved in
|
||||||
for (i = 0; i < n; i++) {
|
importing order. First clear modules imported later. */
|
||||||
|
for (i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) {
|
||||||
PyObject *tup = PyList_GET_ITEM(weaklist, i);
|
PyObject *tup = PyList_GET_ITEM(weaklist, i);
|
||||||
PyObject *name = PyTuple_GET_ITEM(tup, 0);
|
PyObject *name = PyTuple_GET_ITEM(tup, 0);
|
||||||
PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1));
|
PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1));
|
||||||
|
|
3542
Python/importlib.h
generated
3542
Python/importlib.h
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue