Issue #19719: Update various finder and loader ABCs such that their
old methods now provide implementations when PEP 451 APIs are present. This should help with backwards-compatibility with code which has not been updated to work with PEP 451.
This commit is contained in:
parent
61272b77b0
commit
8d942296bb
|
@ -275,9 +275,13 @@ ABC hierarchy::
|
||||||
will be the value of :attr:`__path__` from the parent
|
will be the value of :attr:`__path__` from the parent
|
||||||
package. If a loader cannot be found, ``None`` is returned.
|
package. If a loader cannot be found, ``None`` is returned.
|
||||||
|
|
||||||
|
If :meth:`find_spec` is defined, backwards-compatible functionality is
|
||||||
|
provided.
|
||||||
|
|
||||||
.. versionchanged:: 3.4
|
.. versionchanged:: 3.4
|
||||||
Returns ``None`` when called instead of raising
|
Returns ``None`` when called instead of raising
|
||||||
:exc:`NotImplementedError`.
|
:exc:`NotImplementedError`. Can use :meth:`find_spec` to provide
|
||||||
|
functionality.
|
||||||
|
|
||||||
.. deprecated:: 3.4
|
.. deprecated:: 3.4
|
||||||
Use :meth:`find_spec` instead.
|
Use :meth:`find_spec` instead.
|
||||||
|
@ -325,8 +329,12 @@ ABC hierarchy::
|
||||||
``portion`` is the empty list then no loader or location for a namespace
|
``portion`` is the empty list then no loader or location for a namespace
|
||||||
package were found (i.e. failure to find anything for the module).
|
package were found (i.e. failure to find anything for the module).
|
||||||
|
|
||||||
|
If :meth:`find_spec` is defined then backwards-compatible functionality is
|
||||||
|
provided.
|
||||||
|
|
||||||
.. versionchanged:: 3.4
|
.. versionchanged:: 3.4
|
||||||
Returns ``(None, [])`` instead of raising :exc:`NotImplementedError`.
|
Returns ``(None, [])`` instead of raising :exc:`NotImplementedError`.
|
||||||
|
Uses :meth:`find_spec` when available to provide functionality.
|
||||||
|
|
||||||
.. deprecated:: 3.4
|
.. deprecated:: 3.4
|
||||||
Use :meth:`find_spec` instead.
|
Use :meth:`find_spec` instead.
|
||||||
|
@ -413,9 +421,13 @@ ABC hierarchy::
|
||||||
:func:`importlib.util.module_for_loader` decorator can handle the
|
:func:`importlib.util.module_for_loader` decorator can handle the
|
||||||
details for :attr:`__package__`.
|
details for :attr:`__package__`.
|
||||||
|
|
||||||
|
When :meth:`exec_module` is available then backwards-compatible
|
||||||
|
functionality is provided.
|
||||||
|
|
||||||
.. versionchanged:: 3.4
|
.. versionchanged:: 3.4
|
||||||
Raise :exc:`ImportError` when called instead of
|
Raise :exc:`ImportError` when called instead of
|
||||||
:exc:`NotImplementedError`.
|
:exc:`NotImplementedError`. Functionality provided when
|
||||||
|
:meth:`exec_module` is available.
|
||||||
|
|
||||||
.. deprecated:: 3.4
|
.. deprecated:: 3.4
|
||||||
The recommended API for loading a module is :meth:`exec_module`
|
The recommended API for loading a module is :meth:`exec_module`
|
||||||
|
|
|
@ -49,10 +49,15 @@ class MetaPathFinder(Finder):
|
||||||
If no module is found, return None. The fullname is a str and
|
If no module is found, return None. The fullname is a str and
|
||||||
the path is a list of strings or None.
|
the path is a list of strings or None.
|
||||||
|
|
||||||
This method is deprecated in favor of finder.find_spec().
|
This method is deprecated in favor of finder.find_spec(). If find_spec()
|
||||||
|
exists then backwards-compatible functionality is provided for this
|
||||||
|
method.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return None
|
if not hasattr(self, 'find_spec'):
|
||||||
|
return None
|
||||||
|
found = self.find_spec(fullname, path)
|
||||||
|
return found.loader if found is not None else None
|
||||||
|
|
||||||
def invalidate_caches(self):
|
def invalidate_caches(self):
|
||||||
"""An optional method for clearing the finder's cache, if any.
|
"""An optional method for clearing the finder's cache, if any.
|
||||||
|
@ -81,10 +86,21 @@ class PathEntryFinder(Finder):
|
||||||
The portion will be discarded if another path entry finder
|
The portion will be discarded if another path entry finder
|
||||||
locates the module as a normal module or package.
|
locates the module as a normal module or package.
|
||||||
|
|
||||||
This method is deprecated in favor of finder.find_spec().
|
This method is deprecated in favor of finder.find_spec(). If find_spec()
|
||||||
|
is provided than backwards-compatible functionality is provided.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return None, []
|
if not hasattr(self, 'find_spec'):
|
||||||
|
return None, []
|
||||||
|
found = self.find_spec(fullname)
|
||||||
|
if found is not None:
|
||||||
|
if not found.submodule_search_locations:
|
||||||
|
portions = []
|
||||||
|
else:
|
||||||
|
portions = found.submodule_search_locations
|
||||||
|
return found.loader, portions
|
||||||
|
else:
|
||||||
|
return None, []
|
||||||
|
|
||||||
find_module = _bootstrap._find_module_shim
|
find_module = _bootstrap._find_module_shim
|
||||||
|
|
||||||
|
@ -124,10 +140,14 @@ class Loader(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
ImportError is raised on failure.
|
ImportError is raised on failure.
|
||||||
|
|
||||||
This method is deprecated in favor of loader.exec_module().
|
This method is deprecated in favor of loader.exec_module(). If
|
||||||
|
exec_module() exists then it is used to provide a backwards-compatible
|
||||||
|
functionality for this method.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
raise ImportError
|
if not hasattr(self, 'exec_module'):
|
||||||
|
raise ImportError
|
||||||
|
return _bootstrap._load_module_shim(self, fullname)
|
||||||
|
|
||||||
def module_repr(self, module):
|
def module_repr(self, module):
|
||||||
"""Return a module's repr.
|
"""Return a module's repr.
|
||||||
|
|
|
@ -14,6 +14,7 @@ from . import util
|
||||||
|
|
||||||
frozen_init, source_init = util.import_importlib('importlib')
|
frozen_init, source_init = util.import_importlib('importlib')
|
||||||
frozen_abc, source_abc = util.import_importlib('importlib.abc')
|
frozen_abc, source_abc = util.import_importlib('importlib.abc')
|
||||||
|
machinery = util.import_importlib('importlib.machinery')
|
||||||
frozen_util, source_util = util.import_importlib('importlib.util')
|
frozen_util, source_util = util.import_importlib('importlib.util')
|
||||||
|
|
||||||
##### Inheritance ##############################################################
|
##### Inheritance ##############################################################
|
||||||
|
@ -285,6 +286,137 @@ class ExecutionLoaderDefaultsTests:
|
||||||
tests = make_return_value_tests(ExecutionLoader, InspectLoaderDefaultsTests)
|
tests = make_return_value_tests(ExecutionLoader, InspectLoaderDefaultsTests)
|
||||||
Frozen_ELDefaultTests, Source_ELDefaultsTests = tests
|
Frozen_ELDefaultTests, Source_ELDefaultsTests = tests
|
||||||
|
|
||||||
|
##### MetaPathFinder concrete methods ##########################################
|
||||||
|
|
||||||
|
class MetaPathFinderFindModuleTests:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def finder(cls, spec):
|
||||||
|
class MetaPathSpecFinder(cls.abc.MetaPathFinder):
|
||||||
|
|
||||||
|
def find_spec(self, fullname, path, target=None):
|
||||||
|
self.called_for = fullname, path
|
||||||
|
return spec
|
||||||
|
|
||||||
|
return MetaPathSpecFinder()
|
||||||
|
|
||||||
|
def test_no_spec(self):
|
||||||
|
finder = self.finder(None)
|
||||||
|
path = ['a', 'b', 'c']
|
||||||
|
name = 'blah'
|
||||||
|
found = finder.find_module(name, path)
|
||||||
|
self.assertIsNone(found)
|
||||||
|
self.assertEqual(name, finder.called_for[0])
|
||||||
|
self.assertEqual(path, finder.called_for[1])
|
||||||
|
|
||||||
|
def test_spec(self):
|
||||||
|
loader = object()
|
||||||
|
spec = self.util.spec_from_loader('blah', loader)
|
||||||
|
finder = self.finder(spec)
|
||||||
|
found = finder.find_module('blah', None)
|
||||||
|
self.assertIs(found, spec.loader)
|
||||||
|
|
||||||
|
|
||||||
|
Frozen_MPFFindModuleTests, Source_MPFFindModuleTests = util.test_both(
|
||||||
|
MetaPathFinderFindModuleTests,
|
||||||
|
abc=(frozen_abc, source_abc),
|
||||||
|
util=(frozen_util, source_util))
|
||||||
|
|
||||||
|
##### PathEntryFinder concrete methods #########################################
|
||||||
|
|
||||||
|
class PathEntryFinderFindLoaderTests:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def finder(cls, spec):
|
||||||
|
class PathEntrySpecFinder(cls.abc.PathEntryFinder):
|
||||||
|
|
||||||
|
def find_spec(self, fullname, target=None):
|
||||||
|
self.called_for = fullname
|
||||||
|
return spec
|
||||||
|
|
||||||
|
return PathEntrySpecFinder()
|
||||||
|
|
||||||
|
def test_no_spec(self):
|
||||||
|
finder = self.finder(None)
|
||||||
|
name = 'blah'
|
||||||
|
found = finder.find_loader(name)
|
||||||
|
self.assertIsNone(found[0])
|
||||||
|
self.assertEqual([], found[1])
|
||||||
|
self.assertEqual(name, finder.called_for)
|
||||||
|
|
||||||
|
def test_spec_with_loader(self):
|
||||||
|
loader = object()
|
||||||
|
spec = self.util.spec_from_loader('blah', loader)
|
||||||
|
finder = self.finder(spec)
|
||||||
|
found = finder.find_loader('blah')
|
||||||
|
self.assertIs(found[0], spec.loader)
|
||||||
|
|
||||||
|
def test_spec_with_portions(self):
|
||||||
|
spec = self.machinery.ModuleSpec('blah', None)
|
||||||
|
paths = ['a', 'b', 'c']
|
||||||
|
spec.submodule_search_locations = paths
|
||||||
|
finder = self.finder(spec)
|
||||||
|
found = finder.find_loader('blah')
|
||||||
|
self.assertIsNone(found[0])
|
||||||
|
self.assertEqual(paths, found[1])
|
||||||
|
|
||||||
|
|
||||||
|
Frozen_PEFFindLoaderTests, Source_PEFFindLoaderTests = util.test_both(
|
||||||
|
PathEntryFinderFindLoaderTests,
|
||||||
|
abc=(frozen_abc, source_abc),
|
||||||
|
machinery=machinery,
|
||||||
|
util=(frozen_util, source_util))
|
||||||
|
|
||||||
|
|
||||||
|
##### Loader concrete methods ##################################################
|
||||||
|
class LoaderLoadModuleTests:
|
||||||
|
|
||||||
|
def loader(self):
|
||||||
|
class SpecLoader(self.abc.Loader):
|
||||||
|
found = None
|
||||||
|
def exec_module(self, module):
|
||||||
|
self.found = module
|
||||||
|
|
||||||
|
def is_package(self, fullname):
|
||||||
|
"""Force some non-default module state to be set."""
|
||||||
|
return True
|
||||||
|
|
||||||
|
return SpecLoader()
|
||||||
|
|
||||||
|
def test_fresh(self):
|
||||||
|
loader = self.loader()
|
||||||
|
name = 'blah'
|
||||||
|
with util.uncache(name):
|
||||||
|
loader.load_module(name)
|
||||||
|
module = loader.found
|
||||||
|
self.assertIs(sys.modules[name], module)
|
||||||
|
self.assertEqual(loader, module.__loader__)
|
||||||
|
self.assertEqual(loader, module.__spec__.loader)
|
||||||
|
self.assertEqual(name, module.__name__)
|
||||||
|
self.assertEqual(name, module.__spec__.name)
|
||||||
|
self.assertIsNotNone(module.__path__)
|
||||||
|
self.assertIsNotNone(module.__path__,
|
||||||
|
module.__spec__.submodule_search_locations)
|
||||||
|
|
||||||
|
def test_reload(self):
|
||||||
|
name = 'blah'
|
||||||
|
loader = self.loader()
|
||||||
|
module = types.ModuleType(name)
|
||||||
|
module.__spec__ = self.util.spec_from_loader(name, loader)
|
||||||
|
module.__loader__ = loader
|
||||||
|
with util.uncache(name):
|
||||||
|
sys.modules[name] = module
|
||||||
|
loader.load_module(name)
|
||||||
|
found = loader.found
|
||||||
|
self.assertIs(found, sys.modules[name])
|
||||||
|
self.assertIs(module, sys.modules[name])
|
||||||
|
|
||||||
|
|
||||||
|
Frozen_LoaderLoadModuleTests, Source_LoaderLoadModuleTests = util.test_both(
|
||||||
|
LoaderLoadModuleTests,
|
||||||
|
abc=(frozen_abc, source_abc),
|
||||||
|
util=(frozen_util, source_util))
|
||||||
|
|
||||||
|
|
||||||
##### InspectLoader concrete methods ###########################################
|
##### InspectLoader concrete methods ###########################################
|
||||||
class InspectLoaderSourceToCodeTests:
|
class InspectLoaderSourceToCodeTests:
|
||||||
|
|
|
@ -13,6 +13,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #19719: Make importlib.abc.MetaPathFinder.find_module(),
|
||||||
|
PathEntryFinder.find_loader(), and Loader.load_module() use PEP 451 APIs to
|
||||||
|
help with backwards-compatibility.
|
||||||
|
|
||||||
- Issue #20144: inspect.Signature now supports parsing simple symbolic
|
- Issue #20144: inspect.Signature now supports parsing simple symbolic
|
||||||
constants as parameter default values in __text_signature__.
|
constants as parameter default values in __text_signature__.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue