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

Skip to content

Commit 2a17bde

Browse files
committed
Issue #20383: Introduce importlib.util.module_from_spec().
Along the way, dismantle importlib._bootstrap._SpecMethods as it was no longer relevant and constructing the new function required partially dismantling the class anyway.
1 parent c8f0d6e commit 2a17bde

17 files changed

Lines changed: 4527 additions & 4727 deletions

File tree

Doc/library/importlib.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,21 @@ an :term:`importer`.
11291129

11301130
.. versionadded:: 3.4
11311131

1132+
.. function:: module_from_spec(spec)
1133+
1134+
Create a new module based on **spec**.
1135+
1136+
If the module object is from ``spec.loader.create_module()``, then any
1137+
pre-existing attributes will not be reset. Also, no :exc:`AttributeError`
1138+
will be raised if triggered while accessing **spec** or setting an attribute
1139+
on the module.
1140+
1141+
This function is preferred over using :class:`types.ModuleType` to create a
1142+
new module as **spec** is used to set as many import-controlled attributes on
1143+
the module as possible.
1144+
1145+
.. versionadded:: 3.5
1146+
11321147
.. decorator:: module_for_loader
11331148

11341149
A :term:`decorator` for :meth:`importlib.abc.Loader.load_module`

Doc/library/types.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ Standard names are defined for the following types:
115115
The type of :term:`modules <module>`. Constructor takes the name of the
116116
module to be created and optionally its :term:`docstring`.
117117

118+
.. note::
119+
Use :func:`importlib.util.module_from_spec` to create a new module if you
120+
wish to set the various import-controlled attributes.
121+
118122
.. attribute:: __doc__
119123

120124
The :term:`docstring` of the module. Defaults to ``None``.

Doc/whatsnew/3.5.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ importlib
153153
With a module object that you want to initialize you can then use
154154
``exec(code, module.__dict__)`` to execute the code in the module.
155155

156+
* :func:`importlib.util.module_from_spec` is now the preferred way to create a
157+
new module. Compared to :class:`types.ModuleType`, this new function will set
158+
the various import-controlled attributes based on the passed-in spec object.
159+
156160
inspect
157161
-------
158162

Lib/imp.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# Platform doesn't support dynamic loading.
1717
load_dynamic = None
1818

19-
from importlib._bootstrap import SourcelessFileLoader, _ERR_MSG, _SpecMethods
19+
from importlib._bootstrap import SourcelessFileLoader, _ERR_MSG, _exec, _load
2020

2121
from importlib import machinery
2222
from importlib import util
@@ -164,11 +164,10 @@ class _LoadSourceCompatibility(_HackedGetData, machinery.SourceFileLoader):
164164
def load_source(name, pathname, file=None):
165165
loader = _LoadSourceCompatibility(name, pathname, file)
166166
spec = util.spec_from_file_location(name, pathname, loader=loader)
167-
methods = _SpecMethods(spec)
168167
if name in sys.modules:
169-
module = methods.exec(sys.modules[name])
168+
module = _exec(spec, sys.modules[name])
170169
else:
171-
module = methods.load()
170+
module = _load(spec)
172171
# To allow reloading to potentially work, use a non-hacked loader which
173172
# won't rely on a now-closed file object.
174173
module.__loader__ = machinery.SourceFileLoader(name, pathname)
@@ -185,11 +184,10 @@ def load_compiled(name, pathname, file=None):
185184
"""**DEPRECATED**"""
186185
loader = _LoadCompiledCompatibility(name, pathname, file)
187186
spec = util.spec_from_file_location(name, pathname, loader=loader)
188-
methods = _SpecMethods(spec)
189187
if name in sys.modules:
190-
module = methods.exec(sys.modules[name])
188+
module = _exec(spec, sys.modules[name])
191189
else:
192-
module = methods.load()
190+
module = _load(spec)
193191
# To allow reloading to potentially work, use a non-hacked loader which
194192
# won't rely on a now-closed file object.
195193
module.__loader__ = SourcelessFileLoader(name, pathname)
@@ -210,11 +208,10 @@ def load_package(name, path):
210208
raise ValueError('{!r} is not a package'.format(path))
211209
spec = util.spec_from_file_location(name, path,
212210
submodule_search_locations=[])
213-
methods = _SpecMethods(spec)
214211
if name in sys.modules:
215-
return methods.exec(sys.modules[name])
212+
return _exec(spec, sys.modules[name])
216213
else:
217-
return methods.load()
214+
return _load(spec)
218215

219216

220217
def load_module(name, file, filename, details):

Lib/importlib/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ def reload(module):
145145
pkgpath = None
146146
target = module
147147
spec = module.__spec__ = _bootstrap._find_spec(name, pkgpath, target)
148-
methods = _bootstrap._SpecMethods(spec)
149-
methods.exec(module)
148+
_bootstrap._exec(spec, module)
150149
# The module may have replaced itself in sys.modules!
151150
return sys.modules[name]
152151
finally:

0 commit comments

Comments
 (0)