Issues #18088, 18089: Introduce

importlib.abc.Loader.init_module_attrs() and implement
importlib.abc.InspectLoader.load_module().

The importlib.abc.Loader.init_module_attrs() method sets the various
attributes on the module being loaded. It is done unconditionally to
support reloading. Typically people used
importlib.util.module_for_loader, but since that's a decorator there
was no way to override it's actions, so init_module_attrs() came into
existence to allow for overriding. This is also why module_for_loader
is now pending deprecation (having its other use replaced by
importlib.util.module_to_load).

All of this allowed for importlib.abc.InspectLoader.load_module() to
be implemented. At this point you can now implement a loader with
nothing more than get_code() (which only requires get_source();
package support requires is_package()). Thanks to init_module_attrs()
the implementation of load_module() is basically a context manager
containing 2 methods calls, a call to exec(), and a return statement.
This commit is contained in:
Brett Cannon 2013-05-31 18:56:47 -04:00
parent f1d7b11db9
commit 0dbb4c7f13
10 changed files with 3934 additions and 3637 deletions

View file

@ -5,6 +5,7 @@ import sys
from test import support
import types
import unittest
import warnings
class ModuleToLoadTests(unittest.TestCase):
@ -72,14 +73,27 @@ class ModuleForLoaderTests(unittest.TestCase):
"""Tests for importlib.util.module_for_loader."""
@staticmethod
def module_for_loader(func):
with warnings.catch_warnings():
warnings.simplefilter('ignore', PendingDeprecationWarning)
return util.module_for_loader(func)
def test_warning(self):
# Should raise a PendingDeprecationWarning when used.
with warnings.catch_warnings():
warnings.simplefilter('error', PendingDeprecationWarning)
with self.assertRaises(PendingDeprecationWarning):
func = util.module_for_loader(lambda x: x)
def return_module(self, name):
fxn = util.module_for_loader(lambda self, module: module)
fxn = self.module_for_loader(lambda self, module: module)
return fxn(self, name)
def raise_exception(self, name):
def to_wrap(self, module):
raise ImportError
fxn = util.module_for_loader(to_wrap)
fxn = self.module_for_loader(to_wrap)
try:
fxn(self, name)
except ImportError:
@ -100,7 +114,7 @@ class ModuleForLoaderTests(unittest.TestCase):
class FakeLoader:
def is_package(self, name):
return True
@util.module_for_loader
@self.module_for_loader
def load_module(self, module):
return module
name = 'a.b.c'
@ -134,7 +148,7 @@ class ModuleForLoaderTests(unittest.TestCase):
def test_decorator_attrs(self):
def fxn(self, module): pass
wrapped = util.module_for_loader(fxn)
wrapped = self.module_for_loader(fxn)
self.assertEqual(wrapped.__name__, fxn.__name__)
self.assertEqual(wrapped.__qualname__, fxn.__qualname__)
@ -160,7 +174,7 @@ class ModuleForLoaderTests(unittest.TestCase):
self._pkg = is_package
def is_package(self, name):
return self._pkg
@util.module_for_loader
@self.module_for_loader
def load_module(self, module):
return module