summaryrefslogtreecommitdiffstats
path: root/Lib/importlib
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2016-06-25 17:58:17 (GMT)
committerBrett Cannon <brett@python.org>2016-06-25 17:58:17 (GMT)
commit696c35e86bffea1f2bc6179a29e46416899e3de6 (patch)
tree774b8cec3342b4ca9a2c6d9c193f59b17299f615 /Lib/importlib
parentda037616b10fc12a213e67711065f8123fb98cef (diff)
downloadcpython-696c35e86bffea1f2bc6179a29e46416899e3de6.zip
cpython-696c35e86bffea1f2bc6179a29e46416899e3de6.tar.gz
cpython-696c35e86bffea1f2bc6179a29e46416899e3de6.tar.bz2
Issue #26186: Remove the restriction that built-in and extension
modules can't be lazily loaded. Thanks to Python 3.6 allowing for types.ModuleType to have its __class__ mutated, the restriction can be lifted by calling create_module() on the wrapped loader.
Diffstat (limited to 'Lib/importlib')
-rw-r--r--Lib/importlib/util.py24
1 files changed, 11 insertions, 13 deletions
diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
index a9d0f1e..6bdf0d4 100644
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -204,11 +204,6 @@ def module_for_loader(fxn):
return module_for_loader_wrapper
-class _Module(types.ModuleType):
-
- """A subclass of the module type to allow __class__ manipulation."""
-
-
class _LazyModule(types.ModuleType):
"""A subclass of the module type which triggers loading upon attribute access."""
@@ -218,13 +213,14 @@ class _LazyModule(types.ModuleType):
# All module metadata must be garnered from __spec__ in order to avoid
# using mutated values.
# Stop triggering this method.
- self.__class__ = _Module
+ self.__class__ = types.ModuleType
# Get the original name to make sure no object substitution occurred
# in sys.modules.
original_name = self.__spec__.name
# Figure out exactly what attributes were mutated between the creation
# of the module and now.
- attrs_then = self.__spec__.loader_state
+ attrs_then = self.__spec__.loader_state['__dict__']
+ original_type = self.__spec__.loader_state['__class__']
attrs_now = self.__dict__
attrs_updated = {}
for key, value in attrs_now.items():
@@ -239,9 +235,9 @@ class _LazyModule(types.ModuleType):
# object was put into sys.modules.
if original_name in sys.modules:
if id(self) != id(sys.modules[original_name]):
- msg = ('module object for {!r} substituted in sys.modules '
- 'during a lazy load')
- raise ValueError(msg.format(original_name))
+ raise ValueError(f"module object for {original_name!r} "
+ "substituted in sys.modules during a lazy "
+ "load")
# Update after loading since that's what would happen in an eager
# loading situation.
self.__dict__.update(attrs_updated)
@@ -275,8 +271,7 @@ class LazyLoader(abc.Loader):
self.loader = loader
def create_module(self, spec):
- """Create a module which can have its __class__ manipulated."""
- return _Module(spec.name)
+ return self.loader.create_module(spec)
def exec_module(self, module):
"""Make the module load lazily."""
@@ -286,5 +281,8 @@ class LazyLoader(abc.Loader):
# on an object would have triggered the load,
# e.g. ``module.__spec__.loader = None`` would trigger a load from
# trying to access module.__spec__.
- module.__spec__.loader_state = module.__dict__.copy()
+ loader_state = {}
+ loader_state['__dict__'] = module.__dict__.copy()
+ loader_state['__class__'] = module.__class__
+ module.__spec__.loader_state = loader_state
module.__class__ = _LazyModule