8000 bpo-42135: Deprecate implementations of find_module() and find_loader() by brettcannon · Pull Request #25169 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
< 10000 /details>
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions Doc/library/importlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.


Expand Down Expand Up @@ -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.
Expand Down
33 changes: 33 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,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
Expand Down
4 changes: 2 additions & 2 deletions Lib/importlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
6 changes: 6 additions & 0 deletions Lib/importlib/_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,9 @@ def find_module(cls, fullname, path=None):
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

Expand Down Expand Up @@ -834,6 +837,9 @@ def find_module(cls, fullname, path=None):
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
Expand Down
14 changes: 13 additions & 1 deletion Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -801,9 +804,12 @@ def find_spec(cls, fullname, path=None, target=None):
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
Expand Down Expand Up @@ -1404,6 +1410,9 @@ def find_module(cls, fullname, path=None):
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
Expand Down Expand Up @@ -1459,6 +1468,9 @@ def find_loader(self, fullname):
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, []
Expand Down
20 changes: 16 additions & 4 deletions Lib/importlib/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""

Expand All @@ -68,8 +80,8 @@ def find_module(self, fullname, path):

"""
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'):
Expand All @@ -86,7 +98,7 @@ def invalidate_caches(self):
machinery.PathFinder, machinery.WindowsRegistryFinder)


class PathEntryFinder(Finder):
class PathEntryFinder(metaclass=abc.ABCMeta):

"""Abstract base class for path entry finders used by PathFinder."""

Expand Down
16 changes: 12 additions & 4 deletions Lib/test/test_importlib/builtin/test_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import sys
import unittest
import warnings


@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module')
Expand Down Expand Up @@ -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'))

Expand All @@ -70,14 +73,19 @@ def test_module(self):

6377 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)


Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_importlib/extension/test_case_sensitivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@
@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,
Expand Down
11 changes: 5 additions & 6 deletions Lib/test/test_importlib/extension/test_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -32,7 +31,7 @@ def test_module(self):
test_package_over_module = None

def test_failure(self):
self.assertIsNone(self.find_module('asdfjkl;'))
self.assertIsNone(self.find_spec('asdfjkl;'))


(Frozen_FinderTests,
Expand Down
5 changes: 4 additions & 1 deletion Lib/test/test_importlib/frozen/test_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
machinery = util.import_importlib('importlib.machinery')

import unittest
import warnings


class FindSpecTests(abc.FinderTests):
Expand Down Expand Up @@ -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__'
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_importlib/frozen/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_module_repr_indirect(self):
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')
Expand Down
8 changes: 6 additions & 2 deletions Lib/test/test_importlib/import_/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ def test_empty_path_hooks(self):
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)
Expand Down Expand Up @@ -216,7 +217,9 @@ def test_invalidate_caches_clear_out_None(self):

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)

Expand Down Expand Up @@ -278,6 +281,7 @@ def find_module(fullname):
path_hooks=[Finder]):
with warnings.catch_warnings():
warnings.simplefilter("ignore", ImportWarning)
warnings.simplefilter("ignore", DeprecationWarning)
self.machinery.PathFinder.find_module('importlib')


Expand Down
Loading
0