Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 02d8454

Browse files
committed
Issue #23014: Make importlib.abc.Loader.create_module() required when
importlib.abc.Loader.exec_module() is also defined. Before this change, create_module() was optional **and** could return None to trigger default semantics. This change now reduces the options for choosing default semantics to one and in the most backporting-friendly way (define create_module() to return None).
1 parent 863c69c commit 02d8454

11 files changed

Lines changed: 2440 additions & 2347 deletions

File tree

Doc/library/importlib.rst

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,16 @@ ABC hierarchy::
347347

348348
.. method:: create_module(spec)
349349

350-
An optional method that returns the module object to use when
351-
importing a module. create_module() may also return ``None``,
352-
indicating that the default module creation should take place
353-
instead.
350+
A method that returns the module object to use when
351+
importing a module. This method may return ``None``,
352+
indicating that default module creation semantics should take place.
354353

355354
.. versionadded:: 3.4
356355

356+
.. versionchanged:: 3.5
357+
Starting in Python 3.6, this method will not be optional when
358+
:meth:`exec_module` is defined.
359+
357360
.. method:: exec_module(module)
358361

359362
An abstract method that executes the module in its own namespace
@@ -417,7 +420,7 @@ ABC hierarchy::
417420

418421
.. deprecated:: 3.4
419422
The recommended API for loading a module is :meth:`exec_module`
420-
(and optionally :meth:`create_module`). Loaders should implement
423+
(and :meth:`create_module`). Loaders should implement
421424
it instead of load_module(). The import machinery takes care of
422425
all the other responsibilities of load_module() when exec_module()
423426
is implemented.
@@ -1136,9 +1139,9 @@ an :term:`importer`.
11361139

11371140
.. function:: module_from_spec(spec)
11381141

1139-
Create a new module based on **spec**.
1142+
Create a new module based on **spec** and ``spec.loader.create_module()``.
11401143

1141-
If the module object is from ``spec.loader.create_module()``, then any
1144+
If ``spec.loader.create_module()`` does not return ``None``, then any
11421145
pre-existing attributes will not be reset. Also, no :exc:`AttributeError`
11431146
will be raised if triggered while accessing **spec** or setting an attribute
11441147
on the module.
@@ -1234,9 +1237,10 @@ an :term:`importer`.
12341237
module has an attribute accessed.
12351238

12361239
This class **only** works with loaders that define
1237-
:meth:`importlib.abc.Loader.exec_module` as control over what module type
1238-
is used for the module is required. For the same reasons, the loader
1239-
**cannot** define :meth:`importlib.abc.Loader.create_module`. Finally,
1240+
:meth:`~importlib.abc.Loader.exec_module` as control over what module type
1241+
is used for the module is required. For those same reasons, the loader's
1242+
:meth:`~importlib.abc.Loader.create_module` method will be ignored (i.e., the
1243+
loader's method should only return ``None``). Finally,
12401244
modules which substitute the object placed into :attr:`sys.modules` will
12411245
not work as there is no way to properly replace the module references
12421246
throughout the interpreter safely; :exc:`ValueError` is raised if such a

Doc/reference/import.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ of what happens during the loading portion of import::
339339

340340
module = None
341341
if spec.loader is not None and hasattr(spec.loader, 'create_module'):
342+
# It is assumed 'exec_module' will also be defined on the loader.
342343
module = spec.loader.create_module(spec)
343344
if module is None:
344345
module = ModuleType(spec.name)
@@ -427,7 +428,7 @@ Module loaders may opt in to creating the module object during loading
427428
by implementing a :meth:`~importlib.abc.Loader.create_module` method.
428429
It takes one argument, the module spec, and returns the new module object
429430
to use during loading. ``create_module()`` does not need to set any attributes
430-
on the module object. If the loader does not define ``create_module()``, the
431+
on the module object. If the method returns ``None``, the
431432
import machinery will create the new module itself.
432433

433434
.. versionadded:: 3.4
@@ -462,6 +463,11 @@ import machinery will create the new module itself.
462463
module(s), and only if the loader itself has loaded the module(s)
463464
explicitly.
464465

466+
.. versionchanged:: 3.5
467+
A :exc:`DeprecationWarning` is raised when ``exec_module()`` is defined but
468+
``create_module()`` is not. Starting in Python 3.6 it will be an error to not
469+
define ``create_module()`` on a loader attached to a ModuleSpec.
470+
465471
Module spec
466472
-----------
467473

Doc/whatsnew/3.5.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,14 @@ Changes in the Python API
456456
`http.client` and `http.server` remain available for backwards compatibility.
457457
(Contributed by Demian Brecht in :issue:`21793`.)
458458

459+
* When an import loader defines :meth:`~importlib.machinery.Loader.exec_module`
460+
it is now expected to also define
461+
:meth:`~importlib.machinery.Loader.create_module` (raises a
462+
:exc:`DeprecationWarning` now, will be an error in Python 3.6). If the loader
463+
inherits from :class:`importlib.abc.Loader` then there is nothing to do, else
464+
simply define :meth:`~importlib.machinery.Loader.create_module` to return
465+
``None`` (:issue:`23014`).
466+
459467
Changes in the C API
460468
--------------------
461469

Lib/importlib/_bootstrap.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,10 @@ def module_from_spec(spec):
10551055
# If create_module() returns `None` then it means default
10561056
# module creation should be used.
10571057
module = spec.loader.create_module(spec)
1058+
elif hasattr(spec.loader, 'exec_module'):
1059+
_warnings.warn('starting in Python 3.6, loaders defining exec_module() '
1060+
'must also define create_module()',
1061+
DeprecationWarning, stacklevel=2)
10581062
if module is None:
10591063
module = _new_module(spec.name)
10601064
_init_module_attrs(spec, module)
@@ -1298,6 +1302,10 @@ def find_module(cls, fullname, path=None):
12981302
"""
12991303
return cls if _imp.is_frozen(fullname) else None
13001304

1305+
@classmethod
1306+
def create_module(cls, spec):
1307+
"""Use default semantics for module creation."""
1308+
13011309
@staticmethod
13021310
def exec_module(module):
13031311
name = module.__spec__.name
@@ -1411,6 +1419,9 @@ def is_package(self, fullname):
14111419
tail_name = fullname.rpartition('.')[2]
14121420
return filename_base == '__init__' and tail_name != '__init__'
14131421

1422+
def create_module(self, spec):
1423+
"""Use default semantics for module creation."""
1424+
14141425
def exec_module(self, module):
14151426
"""Execute the module."""
14161427
code = self.get_code(module.__name__)
@@ -1771,6 +1782,9 @@ def get_source(self, fullname):
17711782
def get_code(self, fullname):
17721783
return compile('', '<string>', 'exec', dont_inherit=True)
17731784

1785+
def create_module(self, spec):
1786+
"""Use default semantics for module creation."""
1787+
17741788
def exec_module(self, module):
17751789
pass
17761790

Lib/importlib/abc.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,6 @@ def create_module(self, spec):
122122
This method should raise ImportError if anything prevents it
123123
from creating a new module. It may return None to indicate
124124
that the spec should create the new module.
125-
126-
create_module() is optional.
127-
128125
"""
129126
# By default, defer to default semantics for the new module.
130127
return None

Lib/test/test_importlib/import_/test___loader__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ class SpecLoaderMock:
1111
def find_spec(self, fullname, path=None, target=None):
1212
return machinery.ModuleSpec(fullname, self)
1313

14+
def create_module(self, spec):
15+
return None
16+
1417
def exec_module(self, module):
1518
pass
1619

Lib/test/test_importlib/import_/test_api.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def find_spec(cls, fullname, path=None, target=None):
1616
spec = machinery.ModuleSpec(fullname, cls)
1717
return spec
1818

19+
@staticmethod
20+
def create_module(spec):
21+
return None
22+
1923
@staticmethod
2024
def exec_module(module):
2125
if module.__name__ == SUBMOD_NAME:

Lib/test/test_importlib/test_spec.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ def _get_filename(self, name):
3434
def _is_package(self, name):
3535
return self.package
3636

37+
def create_module(self, spec):
38+
return None
39+
3740

3841
class NewLoader(TestLoader):
3942

Lib/test/test_importlib/test_util.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,16 @@ def test_universal_newlines(self):
4141
class ModuleFromSpecTests:
4242

4343
def test_no_create_module(self):
44-
class Loader(self.abc.Loader):
45-
pass
44+
class Loader:
45+
def exec_module(self, module):
46+
pass
4647
spec = self.machinery.ModuleSpec('test', Loader())
47-
module = self.util.module_from_spec(spec)
48+
with warnings.catch_warnings(record=True) as w:
49+
warnings.simplefilter('always')
50+
module = self.util.module_from_spec(spec)
51+
self.assertEqual(1, len(w))
52+
self.assertTrue(issubclass(w[0].category, DeprecationWarning))
53+
self.assertIn('create_module', str(w[0].message))
4854
self.assertIsInstance(module, types.ModuleType)
4955
self.assertEqual(module.__name__, spec.name)
5056

Lib/test/test_pkgutil.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ def test_unreadable_dir_on_syspath(self):
104104
class PkgutilPEP302Tests(unittest.TestCase):
105105

106106
class MyTestLoader(object):
107+
def create_module(self, spec):
108+
return None
109+
107110
def exec_module(self, mod):
108111
# Count how many times the module is reloaded
109112
mod.__dict__['loads'] = mod.__dict__.get('loads', 0) + 1

0 commit comments

Comments
 (0)