Skip to content
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

gh-97850: Deprecate find_loader and get_loader in pkgutil #98520

Merged
merged 14 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ Deprecated
:exc:`ImportWarning`).
(Contributed by Brett Cannon in :gh:`65961`.)

* :func:`pkgutil.find_module` and :func:`pkgutil.get_module`
sobolevn marked this conversation as resolved.
Show resolved Hide resolved
now raise :exc:`DeprecationWarning`;
use :func:`importlib.util.find_spec` instead.
sobolevn marked this conversation as resolved.
Show resolved Hide resolved
(Contributed by Nikita Sobolev in :gh:`97850`.)


Pending Removal in Python 3.13
------------------------------
Expand Down
8 changes: 8 additions & 0 deletions Lib/pkgutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,10 @@ def get_loader(module_or_name):
If the named module is not already imported, its containing package
(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",
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
remove=(3, 14))
if module_or_name in sys.modules:
module_or_name = sys.modules[module_or_name]
if module_or_name is None:
Expand All @@ -489,6 +493,10 @@ def find_loader(fullname):
importlib.util.find_spec that converts most failures to ImportError
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",
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
remove=(3, 14))
if fullname.startswith('.'):
msg = "Relative module name {!r} not supported".format(fullname)
raise ImportError(msg)
Expand Down
41 changes: 23 additions & 18 deletions Lib/test/test_pkgutil.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path
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 sys
import importlib
Expand Down Expand Up @@ -549,25 +549,18 @@ def test_loader_deprecated(self):
with self.check_deprecated():
pkgutil.ImpLoader("", "", "", "")

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__')
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_missing_loader_attribute(self):
global __loader__
this_loader = __loader__
del __loader__
try:
with check_warnings() as w:
self.assertIsNotNone(pkgutil.get_loader(__name__))
self.assertEqual(len(w.warnings), 0)
self.assertIsNotNone(pkgutil.get_loader(__name__))
finally:
__loader__ = this_loader

@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_missing_spec_attribute(self):
name = 'spam'
mod = type(sys)(name)
Expand All @@ -577,6 +570,7 @@ def test_get_loader_handles_missing_spec_attribute(self):
loader = pkgutil.get_loader(name)
self.assertIsNone(loader)

@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_spec_attribute_none(self):
name = 'spam'
mod = type(sys)(name)
Expand All @@ -586,6 +580,7 @@ def test_get_loader_handles_spec_attribute_none(self):
loader = pkgutil.get_loader(name)
self.assertIsNone(loader)

@ignore_warnings(category=DeprecationWarning)
def test_get_loader_None_in_sys_modules(self):
name = 'totally bogus'
sys.modules[name] = None
Expand All @@ -595,18 +590,28 @@ def test_get_loader_None_in_sys_modules(self):
del sys.modules[name]
self.assertIsNone(loader)

def test_get_loader_is_deprecated(self):
for module in ["sys", "os", "test.support"]:
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
with check_warnings(
(r".*\bpkgutil.get_loader\b.*", DeprecationWarning),
):
res = pkgutil.get_loader(module)
self.assertIsNotNone(res)

def test_find_loader_is_deprecated(self):
for module in ["sys", "os", "test.support"]:
with check_warnings(
(r".*\bpkgutil.find_loader\b.*", DeprecationWarning),
):
res = pkgutil.find_loader(module)
self.assertIsNotNone(res)

@ignore_warnings(category=DeprecationWarning)
def test_find_loader_missing_module(self):
name = 'totally bogus'
loader = pkgutil.find_loader(name)
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):
# We use an illegal path so *none* of the path hooks should fire
with check_warnings() as w:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Deprecate :func:`pkgutil.find_module` and :func:`pkgutil.get_module`
sobolevn marked this conversation as resolved.
Show resolved Hide resolved
in favor of :func:`importlib.util.find_spec`.