]> granicus.if.org Git - python/commitdiff
Issue #15502: Bring the importlib ABCs into line with the current state of the import...
authorNick Coghlan <ncoghlan@gmail.com>
Thu, 2 Aug 2012 11:26:03 +0000 (21:26 +1000)
committerNick Coghlan <ncoghlan@gmail.com>
Thu, 2 Aug 2012 11:26:03 +0000 (21:26 +1000)
Doc/library/importlib.rst
Lib/importlib/abc.py
Lib/test/test_importlib/source/test_abc_loader.py
Lib/test/test_importlib/test_abc.py
Misc/NEWS

index 05b18d3a4b1e4ce5bcd8ebde9f8e0f697f90553d..49ad46f1e2995fd5b70bac7dc26c7d34696a6dab 100644 (file)
@@ -125,32 +125,49 @@ are also provided to help in implementing the core ABCs.
 
 .. class:: Finder
 
-    An abstract base class representing a :term:`finder`.
-    See :pep:`302` for the exact definition for a finder.
+   An abstract base class representing a :term:`finder`.  Finder
+   implementations should derive from (or register with) the more specific
+   :class:`MetaPathFinder` or :class:`PathEntryFinder` ABCs.
 
-    .. method:: find_loader(self, fullname):
+   .. method:: invalidate_caches()
 
-        An abstract method for finding a :term:`loader` for the specified
-        module.  Returns a 2-tuple of ``(loader, portion)`` where portion is a
-        sequence of file system locations contributing to part of a namespace
-        package.  The sequence may be empty.  When present, `find_loader()` is
-        preferred over `find_module()`.
+      An optional method which, when called, should invalidate any internal
+      cache used by the finder. Used by :func:`invalidate_caches()` when
+      invalidating the caches of all cached finders.
 
-        .. versionadded: 3.3
+   .. versionchanged:: 3.3
+      The API signatures for meta path finders and path entry finders
+      were separated by PEP 420. Accordingly, the Finder ABC no
+      longer requires implementation of a ``find_module()`` method.
 
-    .. method:: find_module(fullname, path=None)
 
-        An abstract method for finding a :term:`loader` for the specified
-        module. If the :term:`finder` is found on :data:`sys.meta_path` and the
-        module to be searched for is a subpackage or module then *path* will
-        be the value of :attr:`__path__` from the parent package. If a loader
-        cannot be found, ``None`` is returned.
+.. class:: MetaPathFinder(Finder)
 
-   .. method:: invalidate_caches()
+   An abstract base class representing a :term:`meta path finder`.
+
+   .. versionadded:: 3.3
+
+   .. method:: find_module(fullname, path)
+
+      An abstract method for finding a :term:`loader` for the specified
+      module.  If this is a top-level import, *path* will be ``None``.
+      Otheriwse, this is a search for a subpackage or module and *path*
+      will be the value of :attr:`__path__` from the parent
+      package. If a loader cannot be found, ``None`` is returned.
+
+
+.. class:: PathEntryFinder(Finder)
+
+   An abstract base class representing a :term:`path entry finder`.
+
+   .. versionadded:: 3.3
+
+   .. method:: find_loader(self, fullname):
 
-        An optional method which, when called, should invalidate any internal
-        cache used by the finder. Used by :func:`invalidate_caches()` when
-        invalidating the caches of all cached finders.
+      An abstract method for finding a :term:`loader` for the specified
+      module.  Returns a 2-tuple of ``(loader, portion)`` where portion is a
+      sequence of file system locations contributing to part of a namespace
+      package.  The sequence may be empty.
 
 
 .. class:: Loader
@@ -569,8 +586,8 @@ find and load modules.
 
     An :term:`importer` for built-in modules. All known built-in modules are
     listed in :data:`sys.builtin_module_names`. This class implements the
-    :class:`importlib.abc.Finder` and :class:`importlib.abc.InspectLoader`
-    ABCs.
+    :class:`importlib.abc.MetaPathFinder` and
+    :class:`importlib.abc.InspectLoader` ABCs.
 
     Only class methods are defined by this class to alleviate the need for
     instantiation.
@@ -579,8 +596,8 @@ find and load modules.
 .. class:: FrozenImporter
 
     An :term:`importer` for frozen modules. This class implements the
-    :class:`importlib.abc.Finder` and :class:`importlib.abc.InspectLoader`
-    ABCs.
+    :class:`importlib.abc.MetaPathFinder` and
+    :class:`importlib.abc.InspectLoader` ABCs.
 
     Only class methods are defined by this class to alleviate the need for
     instantiation.
@@ -589,7 +606,7 @@ find and load modules.
 .. class:: PathFinder
 
     :term:`Finder` for :data:`sys.path`. This class implements the
-    :class:`importlib.abc.Finder` ABC.
+    :class:`importlib.abc.MetaPathFinder` ABC.
 
     This class does not perfectly mirror the semantics of :keyword:`import` in
     terms of :data:`sys.path`. No implicit path hooks are assumed for
@@ -616,8 +633,8 @@ find and load modules.
 
 .. class:: FileFinder(path, \*loader_details)
 
-   A concrete implementation of :class:`importlib.abc.Finder` which caches
-   results from the file system.
+   A concrete implementation of :class:`importlib.abc.PathEntryFinder` which
+   caches results from the file system.
 
    The *path* argument is the directory for which the finder is in charge of
    searching.
index 7fcf2de438fc38c313f2100bccd88807836525b7..5e71758afcfd1d4c05fe551851e6d1ce71271fc6 100644 (file)
@@ -23,48 +23,76 @@ def _register(abstract_cls, *classes):
             abstract_cls.register(frozen_cls)
 
 
-class Loader(metaclass=abc.ABCMeta):
+class Finder(metaclass=abc.ABCMeta):
 
-    """Abstract base class for import loaders."""
+    """Common abstract base class for import finders.
 
-    @abc.abstractmethod
-    def load_module(self, fullname):
-        """Abstract method which when implemented should load a module.
-        The fullname is a str."""
+    Finder implementations should derive from the more specific
+    MetaPathFinder or PathEntryFinder ABCs rather than directly from Finder.
+    """
+
+    def find_module(self, fullname, path=None):
+        """An optional legacy method that should find a module.
+        The fullname is a str and the optional path is a str or None.
+        Returns a Loader object.
+
+        The path finder will use this method only if find_loader() does
+        not exist. It may optionally be implemented for compatibility
+        with legacy third party reimplementations of the import system.
+        """
         raise NotImplementedError
 
+    # invalidate_caches() is a completely optional method, so no default
+    # implementation is provided. See the docs for details.
+
+
+class MetaPathFinder(Finder):
+
+    """Abstract base class for import finders on sys.meta_path."""
+
     @abc.abstractmethod
-    def module_repr(self, module):
-        """Abstract method which when implemented calculates and returns the
-        given module's repr."""
+    def find_module(self, fullname, path):
+        """Abstract method which when implemented should find a module.
+        The fullname is a str and the path is a str or None.
+        Returns a Loader object.
+        """
         raise NotImplementedError
 
+_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
+          machinery.PathFinder)
 
-class Finder(metaclass=abc.ABCMeta):
 
-    """Abstract base class for import finders."""
+class PathEntryFinder(Finder):
+
+    """Abstract base class for path entry finders used by PathFinder."""
 
     @abc.abstractmethod
     def find_loader(self, fullname):
         """Abstract method which when implemented returns a module loader.
         The fullname is a str.  Returns a 2-tuple of (Loader, portion) where
         portion is a sequence of file system locations contributing to part of
-        a namespace package.  The sequence may be empty.  When present,
-        `find_loader()` is preferred over `find_module()`.
+        a namespace package.  The sequence may be empty.
         """
         raise NotImplementedError
 
+_register(PathEntryFinder, machinery.FileFinder)
+
+
+class Loader(metaclass=abc.ABCMeta):
+
+    """Abstract base class for import loaders."""
+
     @abc.abstractmethod
-    def find_module(self, fullname, path=None):
-        """Abstract method which when implemented should find a module.
-        The fullname is a str and the optional path is a str or None.
-        Returns a Loader object.  This method is only called if
-        `find_loader()` is not present.
-        """
+    def load_module(self, fullname):
+        """Abstract method which when implemented should load a module.
+        The fullname is a str."""
         raise NotImplementedError
 
-_register(Finder, machinery.BuiltinImporter, machinery.FrozenImporter,
-          machinery.PathFinder, machinery.FileFinder)
+    @abc.abstractmethod
+    def module_repr(self, module):
+        """Abstract method which when implemented calculates and returns the
+        given module's repr."""
+        raise NotImplementedError
 
 
 class ResourceLoader(Loader):
index 9db48821771a24f8ea4aea3dc980eea8996d343a..0d912b64692a022b4e85f517bda2023367f951a8 100644 (file)
@@ -778,23 +778,32 @@ class SourceLoaderGetSourceTests(unittest.TestCase):
         expect = io.IncrementalNewlineDecoder(None, True).decode(source)
         self.assertEqual(mock.get_source(name), expect)
 
+
 class AbstractMethodImplTests(unittest.TestCase):
 
     """Test the concrete abstractmethod implementations."""
 
-    class Loader(abc.Loader):
-        def load_module(self, fullname):
-            super().load_module(fullname)
-        def module_repr(self, module):
-            super().module_repr(module)
+    class MetaPathFinder(abc.MetaPathFinder):
+        def find_module(self, fullname, path):
+            super().find_module(fullname, path)
 
-    class Finder(abc.Finder):
+    class PathEntryFinder(abc.PathEntryFinder):
         def find_module(self, _):
             super().find_module(_)
 
         def find_loader(self, _):
             super().find_loader(_)
 
+    class Finder(abc.Finder):
+        def find_module(self, fullname, path):
+            super().find_module(fullname, path)
+
+    class Loader(abc.Loader):
+        def load_module(self, fullname):
+            super().load_module(fullname)
+        def module_repr(self, module):
+            super().module_repr(module)
+
     class ResourceLoader(Loader, abc.ResourceLoader):
         def get_data(self, _):
             super().get_data(_)
index 008bd21ff885e00465708bf50172e40617b384fc..90f38b82d2d5f2ced4f2770ebfb89dd436e9b5fd 100644 (file)
@@ -30,11 +30,16 @@ class InheritanceTests:
                "{0} is not a superclass of {1}".format(superclass, self.__test))
 
 
-class Finder(InheritanceTests, unittest.TestCase):
+class MetaPathFinder(InheritanceTests, unittest.TestCase):
 
+    superclasses = [abc.Finder]
     subclasses = [machinery.BuiltinImporter, machinery.FrozenImporter,
                     machinery.PathFinder]
 
+class PathEntryFinder(InheritanceTests, unittest.TestCase):
+
+    superclasses = [abc.Finder]
+    subclasses = [machinery.FileFinder]
 
 class Loader(InheritanceTests, unittest.TestCase):
 
index f4dae73f4abf07e4bd35686780961213ba1f8919..58a331d1c3c34d318a176b1ce54ce08e4fb29e74 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -72,6 +72,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #15502: Bring the importlib ABCs into line with the current state
+  of the import protocols given PEP 420. Original patch by Eric Snow.
+
 - Issue #15499: Launching a webbrowser in Unix used to sleep for a few
   seconds.  Original patch by Anton Barkovsky.