Issue #18115: Abstract out managing the cleanup of modules to use in
loaders where C code provides the loaded module.
This commit is contained in:
parent
6d26eba186
commit
01b0475b08
@ -475,8 +475,24 @@ def _verbose_message(message, *args, verbosity=1):
|
|||||||
print(message.format(*args), file=sys.stderr)
|
print(message.format(*args), file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
class _ManageReload:
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self._is_reload = self._name in sys.modules
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
if any(arg is not None for arg in args) and not self._is_reload:
|
||||||
|
try:
|
||||||
|
del sys.modules[self._name]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Written as a class only because contextlib is not available.
|
# Written as a class only because contextlib is not available.
|
||||||
class _ModuleManager:
|
class _ModuleManager(_ManageReload):
|
||||||
|
|
||||||
"""Context manager which returns the module to be loaded.
|
"""Context manager which returns the module to be loaded.
|
||||||
|
|
||||||
@ -490,12 +506,12 @@ class _ModuleManager:
|
|||||||
The reset_name argument specifies whether to unconditionally reset
|
The reset_name argument specifies whether to unconditionally reset
|
||||||
the __name__ attribute if the module is found to be a reload.
|
the __name__ attribute if the module is found to be a reload.
|
||||||
"""
|
"""
|
||||||
self._name = name
|
super().__init__(name)
|
||||||
self._reset_name = reset_name
|
self._reset_name = reset_name
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
super().__enter__()
|
||||||
self._module = sys.modules.get(self._name)
|
self._module = sys.modules.get(self._name)
|
||||||
self._is_reload = self._module is not None
|
|
||||||
if not self._is_reload:
|
if not self._is_reload:
|
||||||
# This must be done before open() is called as the 'io' module
|
# This must be done before open() is called as the 'io' module
|
||||||
# implicitly imports 'locale' and would otherwise trigger an
|
# implicitly imports 'locale' and would otherwise trigger an
|
||||||
@ -510,14 +526,12 @@ class _ModuleManager:
|
|||||||
self._module.__name__ = self._name
|
self._module.__name__ = self._name
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return self._module
|
return self._module
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
self._module.__initializing__ = False
|
self._module.__initializing__ = False
|
||||||
del self._module
|
del self._module
|
||||||
if any(arg is not None for arg in args) and not self._is_reload:
|
super().__exit__(*args)
|
||||||
del sys.modules[self._name]
|
|
||||||
|
|
||||||
|
|
||||||
def module_to_load(name, *, reset_name=True):
|
def module_to_load(name, *, reset_name=True):
|
||||||
@ -741,13 +755,8 @@ class BuiltinImporter:
|
|||||||
@_requires_builtin
|
@_requires_builtin
|
||||||
def load_module(cls, fullname):
|
def load_module(cls, fullname):
|
||||||
"""Load a built-in module."""
|
"""Load a built-in module."""
|
||||||
is_reload = fullname in sys.modules
|
with _ManageReload(fullname):
|
||||||
try:
|
|
||||||
return _call_with_frames_removed(_imp.init_builtin, fullname)
|
return _call_with_frames_removed(_imp.init_builtin, fullname)
|
||||||
except:
|
|
||||||
if not is_reload and fullname in sys.modules:
|
|
||||||
del sys.modules[fullname]
|
|
||||||
raise
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@_requires_builtin
|
@_requires_builtin
|
||||||
@ -792,16 +801,11 @@ class FrozenImporter:
|
|||||||
@_requires_frozen
|
@_requires_frozen
|
||||||
def load_module(cls, fullname):
|
def load_module(cls, fullname):
|
||||||
"""Load a frozen module."""
|
"""Load a frozen module."""
|
||||||
is_reload = fullname in sys.modules
|
with _ManageReload(fullname):
|
||||||
try:
|
|
||||||
m = _call_with_frames_removed(_imp.init_frozen, fullname)
|
m = _call_with_frames_removed(_imp.init_frozen, fullname)
|
||||||
# Let our own module_repr() method produce a suitable repr.
|
# Let our own module_repr() method produce a suitable repr.
|
||||||
del m.__file__
|
del m.__file__
|
||||||
return m
|
return m
|
||||||
except:
|
|
||||||
if not is_reload and fullname in sys.modules:
|
|
||||||
del sys.modules[fullname]
|
|
||||||
raise
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@_requires_frozen
|
@_requires_frozen
|
||||||
@ -1147,18 +1151,13 @@ class ExtensionFileLoader:
|
|||||||
@set_loader
|
@set_loader
|
||||||
def load_module(self, fullname):
|
def load_module(self, fullname):
|
||||||
"""Load an extension module."""
|
"""Load an extension module."""
|
||||||
is_reload = fullname in sys.modules
|
with _ManageReload(fullname):
|
||||||
try:
|
|
||||||
module = _call_with_frames_removed(_imp.load_dynamic,
|
module = _call_with_frames_removed(_imp.load_dynamic,
|
||||||
fullname, self.path)
|
fullname, self.path)
|
||||||
_verbose_message('extension module loaded from {!r}', self.path)
|
_verbose_message('extension module loaded from {!r}', self.path)
|
||||||
if self.is_package(fullname) and not hasattr(module, '__path__'):
|
if self.is_package(fullname) and not hasattr(module, '__path__'):
|
||||||
module.__path__ = [_path_split(self.path)[0]]
|
module.__path__ = [_path_split(self.path)[0]]
|
||||||
return module
|
return module
|
||||||
except:
|
|
||||||
if not is_reload and fullname in sys.modules:
|
|
||||||
del sys.modules[fullname]
|
|
||||||
raise
|
|
||||||
|
|
||||||
def is_package(self, fullname):
|
def is_package(self, fullname):
|
||||||
"""Return True if the extension module is a package."""
|
"""Return True if the extension module is a package."""
|
||||||
|
4911
Python/importlib.h
4911
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user