diff -r 7c131a031fc4 Doc/library/importlib.rst --- a/Doc/library/importlib.rst Fri Dec 12 12:00:02 2014 -0500 +++ b/Doc/library/importlib.rst Fri Dec 12 12:23:43 2014 -0500 @@ -347,13 +347,16 @@ .. method:: create_module(spec) - An optional method that returns the module object to use when - importing a module. create_module() may also return ``None``, - indicating that the default module creation should take place - instead. + A method that returns the module object to use when + importing a module. This method may return ``None``, + indicating that default module creation semantics should take place. .. versionadded:: 3.4 + .. versionchanged:: 3.5 + Starting in Python 3.6, this method wil not optional when + :meth:`exec_module` is defined. + .. method:: exec_module(module) An abstract method that executes the module in its own namespace @@ -417,7 +420,7 @@ .. deprecated:: 3.4 The recommended API for loading a module is :meth:`exec_module` - (and optionally :meth:`create_module`). Loaders should implement + (and :meth:`create_module`). Loaders should implement it instead of load_module(). The import machinery takes care of all the other responsibilities of load_module() when exec_module() is implemented. @@ -1136,9 +1139,9 @@ .. function:: module_from_spec(spec) - Create a new module based on **spec**. + Create a new module based on **spec** and ``spec.loader.create_module()``. - If the module object is from ``spec.loader.create_module()``, then any + If ``spec.loader.create_module()`` does not return None, then any pre-existing attributes will not be reset. Also, no :exc:`AttributeError` will be raised if triggered while accessing **spec** or setting an attribute on the module. @@ -1234,9 +1237,10 @@ module has an attribute accessed. This class **only** works with loaders that define - :meth:`importlib.abc.Loader.exec_module` as control over what module type - is used for the module is required. For the same reasons, the loader - **cannot** define :meth:`importlib.abc.Loader.create_module`. Finally, + :meth:`~importlib.abc.Loader.exec_module` as control over what module type + is used for the module is required. For those same reasons, the loader's + :meth:`~importlib.abc.Loader.create_module` method will be ignored (i.e., the + loader's method should only return ``None``). Finally, modules which substitute the object placed into :attr:`sys.modules` will not work as there is no way to properly replace the module references throughout the interpreter safely; :exc:`ValueError` is raised if such a diff -r 7c131a031fc4 Doc/reference/import.rst --- a/Doc/reference/import.rst Fri Dec 12 12:00:02 2014 -0500 +++ b/Doc/reference/import.rst Fri Dec 12 12:23:43 2014 -0500 @@ -339,6 +339,7 @@ module = None if spec.loader is not None and hasattr(spec.loader, 'create_module'): + # It is assumed 'exec_module' will also be defined on the loader. module = spec.loader.create_module(spec) if module is None: module = ModuleType(spec.name) @@ -427,7 +428,7 @@ by implementing a :meth:`~importlib.abc.Loader.create_module` method. It takes one argument, the module spec, and returns the new module object to use during loading. ``create_module()`` does not need to set any attributes -on the module object. If the loader does not define ``create_module()``, the +on the module object. If the method returns ``None``, the import machinery will create the new module itself. .. versionadded:: 3.4 @@ -462,6 +463,11 @@ module(s), and only if the loader itself has loaded the module(s) explicitly. +.. versionchanged:: 3.5 + A :class:`DeprecationWarning` is raised when ``exec_module()`` is defined but + ``create_module()`` is not. Starting in Python 3.6 it will be an error to not + define ``create_module()`` on a loader attached to a ModuleSpec. + Module spec ----------- diff -r 7c131a031fc4 Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/importlib/_bootstrap.py Fri Dec 12 12:23:43 2014 -0500 @@ -1055,6 +1055,10 @@ # If create_module() returns `None` then it means default # module creation should be used. module = spec.loader.create_module(spec) + elif hasattr(spec.loader, 'exec_module'): + _warnings.warn('starting in Python 3.6, loaders defining exec_module() ' + 'must also define create_module()', + DeprecationWarning) if module is None: module = _new_module(spec.name) _init_module_attrs(spec, module) @@ -1299,6 +1303,10 @@ return cls if _imp.is_frozen(fullname) else None @staticmethod + def create_module(spec): + """Use default semantics for module creation.""" + + @staticmethod def exec_module(module): name = module.__spec__.name if not _imp.is_frozen(name): @@ -1411,6 +1419,9 @@ tail_name = fullname.rpartition('.')[2] return filename_base == '__init__' and tail_name != '__init__' + def create_module(self, spec): + """Use default semantics for module creation.""" + def exec_module(self, module): """Execute the module.""" code = self.get_code(module.__name__) @@ -1771,6 +1782,9 @@ def get_code(self, fullname): return compile('', '', 'exec', dont_inherit=True) + def create_module(self, spec): + """Use default semantics for module creation.""" + def exec_module(self, module): pass diff -r 7c131a031fc4 Lib/importlib/abc.py --- a/Lib/importlib/abc.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/importlib/abc.py Fri Dec 12 12:23:43 2014 -0500 @@ -122,9 +122,6 @@ This method should raise ImportError if anything prevents it from creating a new module. It may return None to indicate that the spec should create the new module. - - create_module() is optional. - """ # By default, defer to default semantics for the new module. return None diff -r 7c131a031fc4 Lib/test/test_importlib/import_/test___loader__.py --- a/Lib/test/test_importlib/import_/test___loader__.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/test/test_importlib/import_/test___loader__.py Fri Dec 12 12:23:43 2014 -0500 @@ -11,6 +11,9 @@ def find_spec(self, fullname, path=None, target=None): return machinery.ModuleSpec(fullname, self) + def create_module(self, spec): + return None + def exec_module(self, module): pass diff -r 7c131a031fc4 Lib/test/test_importlib/import_/test_api.py --- a/Lib/test/test_importlib/import_/test_api.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/test/test_importlib/import_/test_api.py Fri Dec 12 12:23:43 2014 -0500 @@ -17,6 +17,10 @@ return spec @staticmethod + def create_module(spec): + return None + + @staticmethod def exec_module(module): if module.__name__ == SUBMOD_NAME: raise ImportError('I cannot be loaded!') diff -r 7c131a031fc4 Lib/test/test_importlib/test_spec.py --- a/Lib/test/test_importlib/test_spec.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/test/test_importlib/test_spec.py Fri Dec 12 12:23:43 2014 -0500 @@ -34,6 +34,9 @@ def _is_package(self, name): return self.package + def create_module(self, spec): + return None + class NewLoader(TestLoader): diff -r 7c131a031fc4 Lib/test/test_importlib/test_util.py --- a/Lib/test/test_importlib/test_util.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/test/test_importlib/test_util.py Fri Dec 12 12:23:43 2014 -0500 @@ -41,10 +41,16 @@ class ModuleFromSpecTests: def test_no_create_module(self): - class Loader(self.abc.Loader): - pass + class Loader: + def exec_module(self, module): + pass spec = self.machinery.ModuleSpec('test', Loader()) - module = self.util.module_from_spec(spec) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + module = self.util.module_from_spec(spec) + self.assertEqual(1, len(w)) + self.assertTrue(issubclass(w[0].category, DeprecationWarning)) + self.assertIn('create_module', str(w[0].message)) self.assertIsInstance(module, types.ModuleType) self.assertEqual(module.__name__, spec.name) diff -r 7c131a031fc4 Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py Fri Dec 12 12:00:02 2014 -0500 +++ b/Lib/test/test_pkgutil.py Fri Dec 12 12:23:43 2014 -0500 @@ -104,6 +104,9 @@ class PkgutilPEP302Tests(unittest.TestCase): class MyTestLoader(object): + def create_module(self, spec): + return None + def exec_module(self, mod): # Count how many times the module is reloaded mod.__dict__['loads'] = mod.__dict__.get('loads', 0) + 1