Kaydet (Commit) 8a9080fe authored tarafından Nick Coghlan's avatar Nick Coghlan

Issue #15502: Bring the importlib ABCs into line with the current state of the…

Issue #15502: Bring the importlib ABCs into line with the current state of the import protocols given PEP 420. Original patch by Eric Snow.
üst a90f311d
...@@ -125,32 +125,49 @@ are also provided to help in implementing the core ABCs. ...@@ -125,32 +125,49 @@ are also provided to help in implementing the core ABCs.
.. class:: Finder .. class:: Finder
An abstract base class representing a :term:`finder`. An abstract base class representing a :term:`finder`. Finder
See :pep:`302` for the exact definition for a 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 An optional method which, when called, should invalidate any internal
module. Returns a 2-tuple of ``(loader, portion)`` where portion is a cache used by the finder. Used by :func:`invalidate_caches()` when
sequence of file system locations contributing to part of a namespace invalidating the caches of all cached finders.
package. The sequence may be empty. When present, `find_loader()` is
preferred over `find_module()`.
.. 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 .. class:: MetaPathFinder(Finder)
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.
.. 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 An abstract method for finding a :term:`loader` for the specified
cache used by the finder. Used by :func:`invalidate_caches()` when module. Returns a 2-tuple of ``(loader, portion)`` where portion is a
invalidating the caches of all cached finders. sequence of file system locations contributing to part of a namespace
package. The sequence may be empty.
.. class:: Loader .. class:: Loader
...@@ -569,8 +586,8 @@ find and load modules. ...@@ -569,8 +586,8 @@ find and load modules.
An :term:`importer` for built-in modules. All known built-in modules are An :term:`importer` for built-in modules. All known built-in modules are
listed in :data:`sys.builtin_module_names`. This class implements the listed in :data:`sys.builtin_module_names`. This class implements the
:class:`importlib.abc.Finder` and :class:`importlib.abc.InspectLoader` :class:`importlib.abc.MetaPathFinder` and
ABCs. :class:`importlib.abc.InspectLoader` ABCs.
Only class methods are defined by this class to alleviate the need for Only class methods are defined by this class to alleviate the need for
instantiation. instantiation.
...@@ -579,8 +596,8 @@ find and load modules. ...@@ -579,8 +596,8 @@ find and load modules.
.. class:: FrozenImporter .. class:: FrozenImporter
An :term:`importer` for frozen modules. This class implements the An :term:`importer` for frozen modules. This class implements the
:class:`importlib.abc.Finder` and :class:`importlib.abc.InspectLoader` :class:`importlib.abc.MetaPathFinder` and
ABCs. :class:`importlib.abc.InspectLoader` ABCs.
Only class methods are defined by this class to alleviate the need for Only class methods are defined by this class to alleviate the need for
instantiation. instantiation.
...@@ -589,7 +606,7 @@ find and load modules. ...@@ -589,7 +606,7 @@ find and load modules.
.. class:: PathFinder .. class:: PathFinder
:term:`Finder` for :data:`sys.path`. This class implements the :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 This class does not perfectly mirror the semantics of :keyword:`import` in
terms of :data:`sys.path`. No implicit path hooks are assumed for terms of :data:`sys.path`. No implicit path hooks are assumed for
...@@ -616,8 +633,8 @@ find and load modules. ...@@ -616,8 +633,8 @@ find and load modules.
.. class:: FileFinder(path, \*loader_details) .. class:: FileFinder(path, \*loader_details)
A concrete implementation of :class:`importlib.abc.Finder` which caches A concrete implementation of :class:`importlib.abc.PathEntryFinder` which
results from the file system. caches results from the file system.
The *path* argument is the directory for which the finder is in charge of The *path* argument is the directory for which the finder is in charge of
searching. searching.
......
...@@ -23,48 +23,76 @@ def _register(abstract_cls, *classes): ...@@ -23,48 +23,76 @@ def _register(abstract_cls, *classes):
abstract_cls.register(frozen_cls) 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 Finder implementations should derive from the more specific
def load_module(self, fullname): MetaPathFinder or PathEntryFinder ABCs rather than directly from Finder.
"""Abstract method which when implemented should load a module. """
The fullname is a str."""
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 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 @abc.abstractmethod
def module_repr(self, module): def find_module(self, fullname, path):
"""Abstract method which when implemented calculates and returns the """Abstract method which when implemented should find a module.
given module's repr.""" The fullname is a str and the path is a str or None.
Returns a Loader object.
"""
raise NotImplementedError 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 @abc.abstractmethod
def find_loader(self, fullname): def find_loader(self, fullname):
"""Abstract method which when implemented returns a module loader. """Abstract method which when implemented returns a module loader.
The fullname is a str. Returns a 2-tuple of (Loader, portion) where 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 portion is a sequence of file system locations contributing to part of
a namespace package. The sequence may be empty. When present, a namespace package. The sequence may be empty.
`find_loader()` is preferred over `find_module()`.
""" """
raise NotImplementedError raise NotImplementedError
_register(PathEntryFinder, machinery.FileFinder)
class Loader(metaclass=abc.ABCMeta):
"""Abstract base class for import loaders."""
@abc.abstractmethod @abc.abstractmethod
def find_module(self, fullname, path=None): def load_module(self, fullname):
"""Abstract method which when implemented should find a module. """Abstract method which when implemented should load a module.
The fullname is a str and the optional path is a str or None. The fullname is a str."""
Returns a Loader object. This method is only called if
`find_loader()` is not present.
"""
raise NotImplementedError raise NotImplementedError
_register(Finder, machinery.BuiltinImporter, machinery.FrozenImporter, @abc.abstractmethod
machinery.PathFinder, machinery.FileFinder) def module_repr(self, module):
"""Abstract method which when implemented calculates and returns the
given module's repr."""
raise NotImplementedError
class ResourceLoader(Loader): class ResourceLoader(Loader):
......
...@@ -778,23 +778,32 @@ class SourceLoaderGetSourceTests(unittest.TestCase): ...@@ -778,23 +778,32 @@ class SourceLoaderGetSourceTests(unittest.TestCase):
expect = io.IncrementalNewlineDecoder(None, True).decode(source) expect = io.IncrementalNewlineDecoder(None, True).decode(source)
self.assertEqual(mock.get_source(name), expect) self.assertEqual(mock.get_source(name), expect)
class AbstractMethodImplTests(unittest.TestCase): class AbstractMethodImplTests(unittest.TestCase):
"""Test the concrete abstractmethod implementations.""" """Test the concrete abstractmethod implementations."""
class Loader(abc.Loader): class MetaPathFinder(abc.MetaPathFinder):
def load_module(self, fullname): def find_module(self, fullname, path):
super().load_module(fullname) super().find_module(fullname, path)
def module_repr(self, module):
super().module_repr(module)
class Finder(abc.Finder): class PathEntryFinder(abc.PathEntryFinder):
def find_module(self, _): def find_module(self, _):
super().find_module(_) super().find_module(_)
def find_loader(self, _): def find_loader(self, _):
super().find_loader(_) 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): class ResourceLoader(Loader, abc.ResourceLoader):
def get_data(self, _): def get_data(self, _):
super().get_data(_) super().get_data(_)
......
...@@ -30,11 +30,16 @@ class InheritanceTests: ...@@ -30,11 +30,16 @@ class InheritanceTests:
"{0} is not a superclass of {1}".format(superclass, self.__test)) "{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, subclasses = [machinery.BuiltinImporter, machinery.FrozenImporter,
machinery.PathFinder] machinery.PathFinder]
class PathEntryFinder(InheritanceTests, unittest.TestCase):
superclasses = [abc.Finder]
subclasses = [machinery.FileFinder]
class Loader(InheritanceTests, unittest.TestCase): class Loader(InheritanceTests, unittest.TestCase):
......
...@@ -72,6 +72,9 @@ Core and Builtins ...@@ -72,6 +72,9 @@ Core and Builtins
Library 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 - Issue #15499: Launching a webbrowser in Unix used to sleep for a few
seconds. Original patch by Anton Barkovsky. seconds. Original patch by Anton Barkovsky.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment