Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 62b4b9e

Browse files
committed
Close #20839: pkgutil.find_loader now uses importlib.util.find_spec
1 parent 01cc2d5 commit 62b4b9e

4 files changed

Lines changed: 41 additions & 21 deletions

File tree

Doc/library/pkgutil.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,17 @@ support.
7474

7575
Retrieve a :pep:`302` module loader for the given *fullname*.
7676

77-
This is a convenience wrapper around :func:`importlib.find_loader` that
78-
sets the *path* argument correctly when searching for submodules, and
79-
also ensures parent packages (if any) are imported before searching for
80-
submodules.
77+
This is a backwards compatibility wrapper around
78+
:func:`importlib.util.find_spec` that converts most failures to
79+
:exc:`ImportError` and only returns the loader rather than the full
80+
:class:`ModuleSpec`.
8181

8282
.. versionchanged:: 3.3
8383
Updated to be based directly on :mod:`importlib` rather than relying
8484
on the package internal PEP 302 import emulation.
8585

86+
.. versionchanged:: 3.4
87+
Updated to be based on :pep:`451`
8688

8789
.. function:: get_importer(path_item)
8890

@@ -109,14 +111,13 @@ support.
109111
not already imported, its containing package (if any) is imported, in order
110112
to establish the package ``__path__``.
111113

112-
This function uses :func:`iter_importers`, and is thus subject to the same
113-
limitations regarding platform-specific special import locations such as the
114-
Windows registry.
115-
116114
.. versionchanged:: 3.3
117115
Updated to be based directly on :mod:`importlib` rather than relying
118116
on the package internal PEP 302 import emulation.
119117

118+
.. versionchanged:: 3.4
119+
Updated to be based on :pep:`451`
120+
120121

121122
.. function:: iter_importers(fullname='')
122123

Lib/pkgutil.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -470,29 +470,22 @@ def get_loader(module_or_name):
470470
def find_loader(fullname):
471471
"""Find a PEP 302 "loader" object for fullname
472472
473-
This is s convenience wrapper around :func:`importlib.find_loader` that
474-
sets the *path* argument correctly when searching for submodules, and
475-
also ensures parent packages (if any) are imported before searching for
476-
submodules.
473+
This is a backwards compatibility wrapper around
474+
importlib.util.find_spec that converts most failures to ImportError
475+
and only returns the loader rather than the full spec
477476
"""
478477
if fullname.startswith('.'):
479478
msg = "Relative module name {!r} not supported".format(fullname)
480479
raise ImportError(msg)
481-
path = None
482-
pkg_name = fullname.rpartition(".")[0]
483-
if pkg_name:
484-
pkg = importlib.import_module(pkg_name)
485-
path = getattr(pkg, "__path__", None)
486-
if path is None:
487-
return None
488480
try:
489-
return importlib.find_loader(fullname, path)
481+
spec = importlib.util.find_spec(fullname)
490482
except (ImportError, AttributeError, TypeError, ValueError) as ex:
491483
# This hack fixes an impedance mismatch between pkgutil and
492484
# importlib, where the latter raises other errors for cases where
493485
# pkgutil previously raised ImportError
494486
msg = "Error while finding loader for {!r} ({}: {})"
495487
raise ImportError(msg.format(fullname, type(ex), ex)) from ex
488+
return spec.loader
496489

497490

498491
def extend_path(path, name):

Lib/test/test_pkgutil.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,25 @@ def test_get_loader_avoids_emulation(self):
334334
self.assertIsNotNone(pkgutil.get_loader("test.support"))
335335
self.assertEqual(len(w.warnings), 0)
336336

337+
def test_get_loader_handles_missing_loader_attribute(self):
338+
global __loader__
339+
this_loader = __loader__
340+
del __loader__
341+
try:
342+
with check_warnings() as w:
343+
self.assertIsNotNone(pkgutil.get_loader(__name__))
344+
self.assertEqual(len(w.warnings), 0)
345+
finally:
346+
__loader__ = this_loader
347+
348+
349+
def test_find_loader_avoids_emulation(self):
350+
with check_warnings() as w:
351+
self.assertIsNotNone(pkgutil.find_loader("sys"))
352+
self.assertIsNotNone(pkgutil.find_loader("os"))
353+
self.assertIsNotNone(pkgutil.find_loader("test.support"))
354+
self.assertEqual(len(w.warnings), 0)
355+
337356
def test_get_importer_avoids_emulation(self):
338357
# We use an illegal path so *none* of the path hooks should fire
339358
with check_warnings() as w:

Misc/NEWS

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ Core and Builtins
1212
- Issue #20786: Fix signatures for dict.__delitem__ and
1313
property.__delete__ builtins.
1414

15+
Library
16+
-------
17+
18+
- Issue #20839: Don't trigger a DeprecationWarning in the still supported
19+
pkgutil.get_loader() API when __loader__ isn't set on a module (nor
20+
when pkgutil.find_loader() is called directly).
21+
1522
Build
1623
-----
1724

@@ -27,7 +34,7 @@ Build
2734
uninstalling pip (rather than failing) if the user has updated pip to a
2835
different version from the one bundled with ensurepip.
2936

30-
- Issue #20465: Update OS X and Windows installer builds to use
37+
- Issue #20465: Update OS X and Windows installer builds to use
3138
SQLite 3.8.3.1.
3239

3340

0 commit comments

Comments
 (0)