]> granicus.if.org Git - python/commitdiff
Close #20839: pkgutil.find_loader now uses importlib.util.find_spec
authorNick Coghlan <ncoghlan@gmail.com>
Tue, 4 Mar 2014 10:39:42 +0000 (20:39 +1000)
committerNick Coghlan <ncoghlan@gmail.com>
Tue, 4 Mar 2014 10:39:42 +0000 (20:39 +1000)
Doc/library/pkgutil.rst
Lib/pkgutil.py
Lib/test/test_pkgutil.py
Misc/NEWS

index 22d44eb9bc77963ca0cd58ddf690a52b6a0c954e..10b7848dd3dbec71279b96323d280a30c4125867 100644 (file)
@@ -74,15 +74,17 @@ support.
 
    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 @@ support.
    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='')
 
index 326657aa888c418c7c7a52d00aeee7b8dfbae406..58cccdc974c53fc59a9d5eb1d85c7573c5507eaf 100644 (file)
@@ -470,29 +470,22 @@ def get_loader(module_or_name):
 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):
index aaa9d8df6b4d6b3aee3cdf433b15d45c4435d179..c4410a9041eb20a39180940a59dde5e88c46fd46 100644 (file)
@@ -334,6 +334,25 @@ class ImportlibMigrationTests(unittest.TestCase):
             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:
index a8e7e4be1d7a2f162bfb667f265c4fb05ca92ea7..1da5d6430f20a030345a0e1d5454fc0ec3aebb5b 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -20,6 +20,10 @@ Core and Builtins
 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