[Python-checkins] cpython: Close #20839: pkgutil.find_loader now uses importlib.util.find_spec

nick.coghlan python-checkins at python.org
Tue Mar 4 11:39:56 CET 2014


http://hg.python.org/cpython/rev/ea827c809765
changeset:   89473:ea827c809765
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Tue Mar 04 20:39:42 2014 +1000
summary:
  Close #20839: pkgutil.find_loader now uses importlib.util.find_spec

files:
  Doc/library/pkgutil.rst  |  17 +++++++++--------
  Lib/pkgutil.py           |  17 +++++------------
  Lib/test/test_pkgutil.py |  19 +++++++++++++++++++
  Misc/NEWS                |   4 ++++
  4 files changed, 37 insertions(+), 20 deletions(-)


diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst
--- a/Doc/library/pkgutil.rst
+++ b/Doc/library/pkgutil.rst
@@ -74,15 +74,17 @@
 
    Retrieve a :pep:`302` module loader for the given *fullname*.
 
-   This is a convenience wrapper around :func:`importlib.find_loader` that
-   sets the *path* argument correctly when searching for submodules, and
-   also ensures parent packages (if any) are imported before searching for
-   submodules.
+   This is a backwards compatibility wrapper around
+   :func:`importlib.util.find_spec` that converts most failures to
+   :exc:`ImportError` and only returns the loader rather than the full
+   :class:`ModuleSpec`.
 
    .. versionchanged:: 3.3
       Updated to be based directly on :mod:`importlib` rather than relying
       on the package internal PEP 302 import emulation.
 
+   .. versionchanged:: 3.4
+      Updated to be based on :pep:`451`
 
 .. function:: get_importer(path_item)
 
@@ -109,14 +111,13 @@
    not already imported, its containing package (if any) is imported, in order
    to establish the package ``__path__``.
 
-   This function uses :func:`iter_importers`, and is thus subject to the same
-   limitations regarding platform-specific special import locations such as the
-   Windows registry.
-
    .. versionchanged:: 3.3
       Updated to be based directly on :mod:`importlib` rather than relying
       on the package internal PEP 302 import emulation.
 
+   .. versionchanged:: 3.4
+      Updated to be based on :pep:`451`
+
 
 .. function:: iter_importers(fullname='')
 
diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py
--- a/Lib/pkgutil.py
+++ b/Lib/pkgutil.py
@@ -470,29 +470,22 @@
 def find_loader(fullname):
     """Find a PEP 302 "loader" object for fullname
 
-    This is s convenience wrapper around :func:`importlib.find_loader` that
-    sets the *path* argument correctly when searching for submodules, and
-    also ensures parent packages (if any) are imported before searching for
-    submodules.
+    This is a backwards compatibility wrapper around
+    importlib.util.find_spec that converts most failures to ImportError
+    and only returns the loader rather than the full spec
     """
     if fullname.startswith('.'):
         msg = "Relative module name {!r} not supported".format(fullname)
         raise ImportError(msg)
-    path = None
-    pkg_name = fullname.rpartition(".")[0]
-    if pkg_name:
-        pkg = importlib.import_module(pkg_name)
-        path = getattr(pkg, "__path__", None)
-        if path is None:
-            return None
     try:
-        return importlib.find_loader(fullname, path)
+        spec = importlib.util.find_spec(fullname)
     except (ImportError, AttributeError, TypeError, ValueError) as ex:
         # This hack fixes an impedance mismatch between pkgutil and
         # importlib, where the latter raises other errors for cases where
         # pkgutil previously raised ImportError
         msg = "Error while finding loader for {!r} ({}: {})"
         raise ImportError(msg.format(fullname, type(ex), ex)) from ex
+    return spec.loader
 
 
 def extend_path(path, name):
diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py
--- a/Lib/test/test_pkgutil.py
+++ b/Lib/test/test_pkgutil.py
@@ -334,6 +334,25 @@
             self.assertIsNotNone(pkgutil.get_loader("test.support"))
             self.assertEqual(len(w.warnings), 0)
 
+    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)
+        finally:
+            __loader__ = this_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:
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -20,6 +20,10 @@
 Library
 -------
 
+- Issue #20839: Don't trigger a DeprecationWarning in the still supported
+  pkgutil.get_loader() API when __loader__ isn't set on a module (nor
+  when pkgutil.find_loader() is called directly).
+
 - Issue #20778: Fix modulefinder to work with bytecode-only modules.
 
 - Issue #20791: copy.copy() now doesn't make a copy when the input is

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list