Issue #15502: Bring the importlib ABCs into line with the current state of the import protocols given PEP 420. Original patch by Eric Snow.
diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
index 7fcf2de..5e71758 100644
--- a/Lib/importlib/abc.py
+++ b/Lib/importlib/abc.py
@@ -23,6 +23,61 @@
abstract_cls.register(frozen_cls)
+class Finder(metaclass=abc.ABCMeta):
+
+ """Common abstract base class for import finders.
+
+ 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 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 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.
+ """
+ raise NotImplementedError
+
+_register(PathEntryFinder, machinery.FileFinder)
+
+
class Loader(metaclass=abc.ABCMeta):
"""Abstract base class for import loaders."""
@@ -40,33 +95,6 @@
raise NotImplementedError
-class Finder(metaclass=abc.ABCMeta):
-
- """Abstract base class for import finders."""
-
- @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()`.
- """
- raise NotImplementedError
-
- @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.
- """
- raise NotImplementedError
-
-_register(Finder, machinery.BuiltinImporter, machinery.FrozenImporter,
- machinery.PathFinder, machinery.FileFinder)
-
-
class ResourceLoader(Loader):
"""Abstract base class for loaders which can return data from their
diff --git a/Lib/test/test_importlib/source/test_abc_loader.py b/Lib/test/test_importlib/source/test_abc_loader.py
index 9db4882..0d912b6 100644
--- a/Lib/test/test_importlib/source/test_abc_loader.py
+++ b/Lib/test/test_importlib/source/test_abc_loader.py
@@ -778,23 +778,32 @@
expect = io.IncrementalNewlineDecoder(None, True).decode(source)
self.assertEqual(mock.get_source(name), expect)
+
class AbstractMethodImplTests(unittest.TestCase):
"""Test the concrete abstractmethod implementations."""
+ class MetaPathFinder(abc.MetaPathFinder):
+ def find_module(self, fullname, path):
+ super().find_module(fullname, path)
+
+ 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 Finder(abc.Finder):
- def find_module(self, _):
- super().find_module(_)
-
- def find_loader(self, _):
- super().find_loader(_)
-
class ResourceLoader(Loader, abc.ResourceLoader):
def get_data(self, _):
super().get_data(_)
diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py
index 008bd21..90f38b8 100644
--- a/Lib/test/test_importlib/test_abc.py
+++ b/Lib/test/test_importlib/test_abc.py
@@ -30,11 +30,16 @@
"{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):