gh-97850: Deprecate find_loader and get_loader in pkgutil (GH-98520)

Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
Co-authored-by: Brett Cannon <brett@python.org>
Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net>
This commit is contained in:
Nikita Sobolev 2023-05-04 02:11:54 +03:00 committed by GitHub
parent 9f9e001ab2
commit d6e83fbf30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 18 deletions

View file

@ -64,6 +64,10 @@ support.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Updated to be based on :pep:`451` Updated to be based on :pep:`451`
.. deprecated-removed:: 3.12 3.14
Use :func:`importlib.util.find_spec` instead.
.. function:: get_importer(path_item) .. function:: get_importer(path_item)
Retrieve a :term:`finder` for the given *path_item*. Retrieve a :term:`finder` for the given *path_item*.
@ -96,6 +100,9 @@ support.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Updated to be based on :pep:`451` Updated to be based on :pep:`451`
.. deprecated-removed:: 3.12 3.14
Use :func:`importlib.util.find_spec` instead.
.. function:: iter_importers(fullname='') .. function:: iter_importers(fullname='')

View file

@ -813,6 +813,11 @@ Pending Removal in Python 3.14
* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, * The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12,
and will be removed in 3.14. and will be removed in 3.14.
* :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader`
now raise :exc:`DeprecationWarning`;
use :func:`importlib.util.find_spec` instead.
(Contributed by Nikita Sobolev in :gh:`97850`.)
Pending Removal in Future Versions Pending Removal in Future Versions
---------------------------------- ----------------------------------

View file

@ -270,6 +270,10 @@ def get_loader(module_or_name):
If the named module is not already imported, its containing package If the named module is not already imported, its containing package
(if any) is imported, in order to establish the package __path__. (if any) is imported, in order to establish the package __path__.
""" """
warnings._deprecated("pkgutil.get_loader",
f"{warnings._DEPRECATED_MSG}; "
"use importlib.util.find_spec() instead",
remove=(3, 14))
if module_or_name in sys.modules: if module_or_name in sys.modules:
module_or_name = sys.modules[module_or_name] module_or_name = sys.modules[module_or_name]
if module_or_name is None: if module_or_name is None:
@ -294,6 +298,10 @@ def find_loader(fullname):
importlib.util.find_spec that converts most failures to ImportError importlib.util.find_spec that converts most failures to ImportError
and only returns the loader rather than the full spec and only returns the loader rather than the full spec
""" """
warnings._deprecated("pkgutil.find_loader",
f"{warnings._DEPRECATED_MSG}; "
"use importlib.util.find_spec() instead",
remove=(3, 14))
if fullname.startswith('.'): if fullname.startswith('.'):
msg = "Relative module name {!r} not supported".format(fullname) msg = "Relative module name {!r} not supported".format(fullname)
raise ImportError(msg) raise ImportError(msg)

View file

@ -1,6 +1,6 @@
from pathlib import Path from pathlib import Path
from test.support.import_helper import unload, CleanImport from test.support.import_helper import unload, CleanImport
from test.support.warnings_helper import check_warnings from test.support.warnings_helper import check_warnings, ignore_warnings
import unittest import unittest
import sys import sys
import importlib import importlib
@ -535,25 +535,18 @@ class ImportlibMigrationTests(unittest.TestCase):
# PEP 302 emulation in this module is in the process of being # PEP 302 emulation in this module is in the process of being
# deprecated in favour of importlib proper # deprecated in favour of importlib proper
def test_get_loader_avoids_emulation(self):
with check_warnings() as w:
self.assertIsNotNone(pkgutil.get_loader("sys"))
self.assertIsNotNone(pkgutil.get_loader("os"))
self.assertIsNotNone(pkgutil.get_loader("test.support"))
self.assertEqual(len(w.warnings), 0)
@unittest.skipIf(__name__ == '__main__', 'not compatible with __main__') @unittest.skipIf(__name__ == '__main__', 'not compatible with __main__')
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_missing_loader_attribute(self): def test_get_loader_handles_missing_loader_attribute(self):
global __loader__ global __loader__
this_loader = __loader__ this_loader = __loader__
del __loader__ del __loader__
try: try:
with check_warnings() as w: self.assertIsNotNone(pkgutil.get_loader(__name__))
self.assertIsNotNone(pkgutil.get_loader(__name__))
self.assertEqual(len(w.warnings), 0)
finally: finally:
__loader__ = this_loader __loader__ = this_loader
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_missing_spec_attribute(self): def test_get_loader_handles_missing_spec_attribute(self):
name = 'spam' name = 'spam'
mod = type(sys)(name) mod = type(sys)(name)
@ -563,6 +556,7 @@ class ImportlibMigrationTests(unittest.TestCase):
loader = pkgutil.get_loader(name) loader = pkgutil.get_loader(name)
self.assertIsNone(loader) self.assertIsNone(loader)
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_spec_attribute_none(self): def test_get_loader_handles_spec_attribute_none(self):
name = 'spam' name = 'spam'
mod = type(sys)(name) mod = type(sys)(name)
@ -572,6 +566,7 @@ class ImportlibMigrationTests(unittest.TestCase):
loader = pkgutil.get_loader(name) loader = pkgutil.get_loader(name)
self.assertIsNone(loader) self.assertIsNone(loader)
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_None_in_sys_modules(self): def test_get_loader_None_in_sys_modules(self):
name = 'totally bogus' name = 'totally bogus'
sys.modules[name] = None sys.modules[name] = None
@ -581,18 +576,26 @@ class ImportlibMigrationTests(unittest.TestCase):
del sys.modules[name] del sys.modules[name]
self.assertIsNone(loader) self.assertIsNone(loader)
def test_get_loader_is_deprecated(self):
with check_warnings(
(r".*\bpkgutil.get_loader\b.*", DeprecationWarning),
):
res = pkgutil.get_loader("sys")
self.assertIsNotNone(res)
def test_find_loader_is_deprecated(self):
with check_warnings(
(r".*\bpkgutil.find_loader\b.*", DeprecationWarning),
):
res = pkgutil.find_loader("sys")
self.assertIsNotNone(res)
@ignore_warnings(category=DeprecationWarning)
def test_find_loader_missing_module(self): def test_find_loader_missing_module(self):
name = 'totally bogus' name = 'totally bogus'
loader = pkgutil.find_loader(name) loader = pkgutil.find_loader(name)
self.assertIsNone(loader) self.assertIsNone(loader)
def test_find_loader_avoids_emulation(self):
with check_warnings() as w:
self.assertIsNotNone(pkgutil.find_loader("sys"))
self.assertIsNotNone(pkgutil.find_loader("os"))
self.assertIsNotNone(pkgutil.find_loader("test.support"))
self.assertEqual(len(w.warnings), 0)
def test_get_importer_avoids_emulation(self): def test_get_importer_avoids_emulation(self):
# We use an illegal path so *none* of the path hooks should fire # We use an illegal path so *none* of the path hooks should fire
with check_warnings() as w: with check_warnings() as w:

View file

@ -0,0 +1,2 @@
Deprecate :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader`
in favor of :func:`importlib.util.find_spec`.