bpo-42135: Deprecate implementations of find_module() and find_loader() (GH-25169)

This commit is contained in:
Brett Cannon 2021-04-06 08:56:57 -07:00 committed by GitHub
parent efccff9ac8
commit 57c6cb5100
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 3821 additions and 3653 deletions

View File

@ -257,6 +257,10 @@ ABC hierarchy::
Returns ``None`` when called instead of raising
:exc:`NotImplementedError`.
.. deprecated:: 3.10
Implement :meth:`MetaPathFinder.find_spec` or
:meth:`PathEntryFinder.find_spec` instead.
.. class:: MetaPathFinder
@ -265,6 +269,9 @@ ABC hierarchy::
.. versionadded:: 3.3
.. versionchanged:: 3.10
No longer a subclass of :class:`Finder`.
.. method:: find_spec(fullname, path, target=None)
An abstract method for finding a :term:`spec <module spec>` for
@ -313,11 +320,13 @@ ABC hierarchy::
An abstract base class representing a :term:`path entry finder`. Though
it bears some similarities to :class:`MetaPathFinder`, ``PathEntryFinder``
is meant for use only within the path-based import subsystem provided
by :class:`PathFinder`. This ABC is a subclass of :class:`Finder` for
compatibility reasons only.
by :class:`importlib.machinery.PathFinder`.
.. versionadded:: 3.3
.. versionchanged:: 3.10
No longer a subclass of :class:`Finder`.
.. method:: find_spec(fullname, target=None)
An abstract method for finding a :term:`spec <module spec>` for
@ -363,7 +372,8 @@ ABC hierarchy::
.. method:: invalidate_caches()
An optional method which, when called, should invalidate any internal
cache used by the finder. Used by :meth:`PathFinder.invalidate_caches`
cache used by the finder. Used by
:meth:`importlib.machinery.PathFinder.invalidate_caches`
when invalidating the caches of all cached finders.
@ -1193,6 +1203,9 @@ find and load modules.
Attempt to find the loader to handle *fullname* within :attr:`path`.
.. deprecated:: 3.10
Use :meth:`find_spec` instead.
.. method:: invalidate_caches()
Clear out the internal cache.

View File

@ -1062,6 +1062,39 @@ Deprecated
:func:`importlib.util.spec_from_loader` to help in porting.
(Contributed by Brett Cannon in :issue:`43672`.)
* The various implementations of
:meth:`importlib.abc.MetaPathFinder.find_module` (
:meth:`importlib.machinery.BuiltinImporter.find_module`,
:meth:`importlib.machinery.FrozenImporter.find_module`,
:meth:`importlib.machinery.WindowsRegistryFinder.find_module`,
:meth:`importlib.machinery.PathFinder.find_module`,
:meth:`importlib.abc.MetaPathFinder.find_module`),
:meth:`importlib.abc.PathEntryFinder.find_module` (
:meth:`importlib.machinery.FileFinder.find_module`,
), and
:meth:`importlib.abc.PathEntryFinder.find_loader` (
:meth:`importlib.machinery.FileFinder.find_loader`
) now raise :exc:`DeprecationWarning` and are slated for removal in
Python 3.12 (previously they were documented as deprecated in Python 3.4).
(Contributed by Brett Cannon in :issue:`42135`.)
* :class:`importlib.abc.Finder` is deprecated (including its sole method,
:meth:`~importlib.abc.Finder.find_module`). Both
:class:`importlib.abc.MetaPathFinder` and :class:`importlib.abc.PathEntryFinder`
no longer inherit from the class. Users should inherit from one of these two
classes as appropriate instead.
(Contributed by Brett Cannon in :issue:`42135`.)
* The deprecations of :mod:`imp`, :func:`importlib.find_loader`,
:func:`importlib.util.set_package_wrapper`,
:func:`importlib.util.set_loader_wrapper`,
:func:`importlib.util.module_for_loader`,
:class:`pkgutil.ImpImporter`, and
:class:`pkgutil.ImpLoader` have all been updated to list Python 3.12 as the
slated version of removal (they began raising :exc:`DeprecationWarning` in
previous versions of Python).
(Contributed by Brett Cannon in :issue:`43720`.)
* The import system now uses the ``__spec__`` attribute on modules before
falling back on :meth:`~importlib.abc.Loader.module_repr` for a module's
``__repr__()`` method. Removal of the use of ``module_repr()`` is scheduled

View File

@ -78,8 +78,8 @@ def find_loader(name, path=None):
This function is deprecated in favor of importlib.util.find_spec().
"""
warnings.warn('Deprecated since Python 3.4. '
'Use importlib.util.find_spec() instead.',
warnings.warn('Deprecated since Python 3.4 and slated for removal in '
'Python 3.10; use importlib.util.find_spec() instead',
DeprecationWarning, stacklevel=2)
try:
loader = sys.modules[name].__loader__

View File

@ -761,6 +761,9 @@ class BuiltinImporter:
This method is deprecated. Use find_spec() instead.
"""
_warnings.warn("BuiltinImporter.find_module() is deprecated and "
"slated for removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
spec = cls.find_spec(fullname, path)
return spec.loader if spec is not None else None
@ -834,6 +837,9 @@ class FrozenImporter:
This method is deprecated. Use find_spec() instead.
"""
_warnings.warn("FrozenImporter.find_module() is deprecated and "
"slated for removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
return cls if _imp.is_frozen(fullname) else None
@staticmethod

View File

@ -533,6 +533,9 @@ def _find_module_shim(self, fullname):
This method is deprecated in favor of finder.find_spec().
"""
_warnings.warn("find_module() is deprecated and "
"slated for removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
# Call find_loader(). If it returns a string (indicating this
# is a namespace package portion), generate a warning and
# return None.
@ -801,9 +804,12 @@ class WindowsRegistryFinder:
def find_module(cls, fullname, path=None):
"""Find module named in the registry.
This method is deprecated. Use exec_module() instead.
This method is deprecated. Use find_spec() instead.
"""
_warnings.warn("WindowsRegistryFinder.find_module() is deprecated and "
"slated for removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
spec = cls.find_spec(fullname, path)
if spec is not None:
return spec.loader
@ -1404,6 +1410,9 @@ class PathFinder:
This method is deprecated. Use find_spec() instead.
"""
_warnings.warn("PathFinder.find_module() is deprecated and "
"slated for removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
spec = cls.find_spec(fullname, path)
if spec is None:
return None
@ -1459,6 +1468,9 @@ class FileFinder:
This method is deprecated. Use find_spec() instead.
"""
_warnings.warn("FileFinder.find_loader() is deprecated and "
"slated for removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
spec = self.find_spec(fullname)
if spec is None:
return None, []

View File

@ -41,15 +41,27 @@ class Finder(metaclass=abc.ABCMeta):
Deprecated since Python 3.3
"""
def __init__(self):
warnings.warn("the Finder ABC is deprecated and "
"slated for removal in Python 3.12; use MetaPathFinder "
"or PathEntryFinder instead",
DeprecationWarning)
@abc.abstractmethod
def find_module(self, fullname, path=None):
"""An abstract method that should find a module.
The fullname is a str and the optional path is a str or None.
Returns a Loader object or None.
"""
warnings.warn("importlib.abc.Finder along with its find_module() "
"method are deprecated and "
"slated for removal in Python 3.12; use "
"MetaPathFinder.find_spec() or "
"PathEntryFinder.find_spec() instead",
DeprecationWarning)
class MetaPathFinder(Finder):
class MetaPathFinder(metaclass=abc.ABCMeta):
"""Abstract base class for import finders on sys.meta_path."""
@ -68,8 +80,8 @@ class MetaPathFinder(Finder):
"""
warnings.warn("MetaPathFinder.find_module() is deprecated since Python "
"3.4 in favor of MetaPathFinder.find_spec() "
"(available since 3.4)",
"3.4 in favor of MetaPathFinder.find_spec() and is "
"slated for removal in Python 3.12",
DeprecationWarning,
stacklevel=2)
if not hasattr(self, 'find_spec'):
@ -86,7 +98,7 @@ _register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
machinery.PathFinder, machinery.WindowsRegistryFinder)
class PathEntryFinder(Finder):
class PathEntryFinder(metaclass=abc.ABCMeta):
"""Abstract base class for path entry finders used by PathFinder."""

View File

@ -5,6 +5,7 @@ machinery = util.import_importlib('importlib.machinery')
import sys
import unittest
import warnings
@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module')
@ -58,7 +59,9 @@ class FinderTests(abc.FinderTests):
def test_module(self):
# Common case.
with util.uncache(util.BUILTINS.good_name):
found = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
found = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name)
self.assertTrue(found)
self.assertTrue(hasattr(found, 'load_module'))
@ -70,14 +73,19 @@ class FinderTests(abc.FinderTests):
def test_failure(self):
assert 'importlib' not in sys.builtin_module_names
loader = self.machinery.BuiltinImporter.find_module('importlib')
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
loader = self.machinery.BuiltinImporter.find_module('importlib')
self.assertIsNone(loader)
def test_ignore_path(self):
# The value for 'path' should always trigger a failed import.
with util.uncache(util.BUILTINS.good_name):
loader = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name,
['pkg'])
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
loader = self.machinery.BuiltinImporter.find_module(
util.BUILTINS.good_name,
['pkg'])
self.assertIsNone(loader)

View File

@ -12,30 +12,30 @@ machinery = util.import_importlib('importlib.machinery')
@util.case_insensitive_tests
class ExtensionModuleCaseSensitivityTest(util.CASEOKTestBase):
def find_module(self):
def find_spec(self):
good_name = util.EXTENSIONS.name
bad_name = good_name.upper()
assert good_name != bad_name
finder = self.machinery.FileFinder(util.EXTENSIONS.path,
(self.machinery.ExtensionFileLoader,
self.machinery.EXTENSION_SUFFIXES))
return finder.find_module(bad_name)
return finder.find_spec(bad_name)
@unittest.skipIf(sys.flags.ignore_environment, 'ignore_environment flag was set')
def test_case_sensitive(self):
with os_helper.EnvironmentVarGuard() as env:
env.unset('PYTHONCASEOK')
self.caseok_env_changed(should_exist=False)
loader = self.find_module()
self.assertIsNone(loader)
spec = self.find_spec()
self.assertIsNone(spec)
@unittest.skipIf(sys.flags.ignore_environment, 'ignore_environment flag was set')
def test_case_insensitivity(self):
with os_helper.EnvironmentVarGuard() as env:
env.set('PYTHONCASEOK', '1')
self.caseok_env_changed(should_exist=True)
loader = self.find_module()
self.assertTrue(hasattr(loader, 'load_module'))
spec = self.find_spec()
self.assertTrue(spec)
(Frozen_ExtensionCaseSensitivity,

View File

@ -11,16 +11,15 @@ class FinderTests(abc.FinderTests):
"""Test the finder for extension modules."""
def find_module(self, fullname):
def find_spec(self, fullname):
importer = self.machinery.FileFinder(util.EXTENSIONS.path,
(self.machinery.ExtensionFileLoader,
self.machinery.EXTENSION_SUFFIXES))
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
return importer.find_module(fullname)
return importer.find_spec(fullname)
def test_module(self):
self.assertTrue(self.find_module(util.EXTENSIONS.name))
self.assertTrue(self.find_spec(util.EXTENSIONS.name))
# No extension module as an __init__ available for testing.
test_package = test_package_in_package = None
@ -32,7 +31,7 @@ class FinderTests(abc.FinderTests):
test_package_over_module = None
def test_failure(self):
self.assertIsNone(self.find_module('asdfjkl;'))
self.assertIsNone(self.find_spec('asdfjkl;'))
(Frozen_FinderTests,

View File

@ -4,6 +4,7 @@ from .. import util
machinery = util.import_importlib('importlib.machinery')
import unittest
import warnings
class FindSpecTests(abc.FinderTests):
@ -49,7 +50,9 @@ class FinderTests(abc.FinderTests):
def find(self, name, path=None):
finder = self.machinery.FrozenImporter
return finder.find_module(name, path)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
return finder.find_module(name, path)
def test_module(self):
name = '__hello__'

View File

@ -78,7 +78,7 @@ class ExecModuleTests(abc.LoaderTests):
test_state_after_failure = None
def test_unloadable(self):
assert self.machinery.FrozenImporter.find_module('_not_real') is None
assert self.machinery.FrozenImporter.find_spec('_not_real') is None
with self.assertRaises(ImportError) as cm:
self.exec_module('_not_real')
self.assertEqual(cm.exception.name, '_not_real')

View File

@ -75,7 +75,8 @@ class FinderTests:
with util.import_state(path_importer_cache={}, path_hooks=[],
path=[path_entry]):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
warnings.simplefilter('always', ImportWarning)
warnings.simplefilter('ignore', DeprecationWarning)
self.assertIsNone(self.find('os'))
self.assertIsNone(sys.path_importer_cache[path_entry])
self.assertEqual(len(w), 1)
@ -216,7 +217,9 @@ class FinderTests:
class FindModuleTests(FinderTests):
def find(self, *args, **kwargs):
return self.machinery.PathFinder.find_module(*args, **kwargs)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
return self.machinery.PathFinder.find_module(*args, **kwargs)
def check_found(self, found, importer):
self.assertIs(found, importer)
@ -278,6 +281,7 @@ class PathEntryFinderTests:
path_hooks=[Finder]):
with warnings.catch_warnings():
warnings.simplefilter("ignore", ImportWarning)
warnings.simplefilter("ignore", DeprecationWarning)
self.machinery.PathFinder.find_module('importlib')

View File

@ -9,6 +9,7 @@ machinery = util.import_importlib('importlib.machinery')
import os
from test.support import os_helper
import unittest
import warnings
@util.case_insensitive_tests
@ -64,7 +65,9 @@ class CaseSensitivityTest(util.CASEOKTestBase):
class CaseSensitivityTestPEP302(CaseSensitivityTest):
def find(self, finder):
return finder.find_module(self.name)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
return finder.find_module(self.name)
(Frozen_CaseSensitivityTestPEP302,

View File

@ -55,7 +55,7 @@ class InheritanceTests:
class MetaPathFinder(InheritanceTests):
superclass_names = ['Finder']
superclass_names = []
subclass_names = ['BuiltinImporter', 'FrozenImporter', 'PathFinder',
'WindowsRegistryFinder']
@ -66,7 +66,7 @@ class MetaPathFinder(InheritanceTests):
class PathEntryFinder(InheritanceTests):
superclass_names = ['Finder']
superclass_names = []
subclass_names = ['FileFinder']

View File

@ -440,9 +440,9 @@ class StartupTests:
with self.subTest(name=name):
self.assertTrue(hasattr(module, '__loader__'),
'{!r} lacks a __loader__ attribute'.format(name))
if self.machinery.BuiltinImporter.find_module(name):
if self.machinery.BuiltinImporter.find_spec(name):
self.assertIsNot(module.__loader__, None)
elif self.machinery.FrozenImporter.find_module(name):
elif self.machinery.FrozenImporter.find_spec(name):
self.assertIsNot(module.__loader__, None)
def test_everyone_has___spec__(self):
@ -450,9 +450,9 @@ class StartupTests:
if isinstance(module, types.ModuleType):
with self.subTest(name=name):
self.assertTrue(hasattr(module, '__spec__'))
if self.machinery.BuiltinImporter.find_module(name):
if self.machinery.BuiltinImporter.find_spec(name):
self.assertIsNot(module.__spec__, None)
elif self.machinery.FrozenImporter.find_module(name):
elif self.machinery.FrozenImporter.find_spec(name):
self.assertIsNot(module.__spec__, None)

View File

@ -119,6 +119,9 @@ class zipimporter(_bootstrap_external._LoaderBasics):
Deprecated since Python 3.10. Use find_spec() instead.
"""
_warnings.warn("zipimporter.find_loader() is deprecated and slated for "
"removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
mi = _get_module_info(self, fullname)
if mi is not None:
# This is a module or package.
@ -152,6 +155,9 @@ class zipimporter(_bootstrap_external._LoaderBasics):
Deprecated since Python 3.10. Use find_spec() instead.
"""
_warnings.warn("zipimporter.find_module() is deprecated and slated for "
"removal in Python 3.12; use find_spec() instead",
DeprecationWarning)
return self.find_loader(fullname, path)[0]
def find_spec(self, fullname, target=None):

View File

@ -0,0 +1,2 @@
Deprecate find_module() and find_loader() implementations in importlib and
zipimport.

1486
Python/importlib.h generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff