bpo-41006: importlib.util no longer imports typing (GH-20938)

Create importlib._abc submodule to avoid importing typing when
importlib.util is imported. Move Loader ABC into importlib._abc.
This commit is contained in:
Victor Stinner 2020-06-17 23:15:59 +02:00 committed by GitHub
parent 236a0f5cf0
commit 9e09849d20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 51 deletions

50
Lib/importlib/_abc.py Normal file
View File

@ -0,0 +1,50 @@
"""Subset of importlib.abc used to reduce importlib.util imports."""
from . import _bootstrap
import abc
class Loader(metaclass=abc.ABCMeta):
"""Abstract base class for import loaders."""
def create_module(self, spec):
"""Return a module to initialize and into which to load.
This method should raise ImportError if anything prevents it
from creating a new module. It may return None to indicate
that the spec should create the new module.
"""
# By default, defer to default semantics for the new module.
return None
# We don't define exec_module() here since that would break
# hasattr checks we do to support backward compatibility.
def load_module(self, fullname):
"""Return the loaded module.
The module must be added to sys.modules and have import-related
attributes set properly. The fullname is a str.
ImportError is raised on failure.
This method is deprecated in favor of loader.exec_module(). If
exec_module() exists then it is used to provide a backwards-compatible
functionality for this method.
"""
if not hasattr(self, 'exec_module'):
raise ImportError
return _bootstrap._load_module_shim(self, fullname)
def module_repr(self, module):
"""Return a module's repr.
Used by the module type when the method does not raise
NotImplementedError.
This method is deprecated.
"""
# The exception will cause ModuleType.__repr__ to ignore this method.
raise NotImplementedError

View File

@ -12,6 +12,7 @@ try:
import _frozen_importlib_external import _frozen_importlib_external
except ImportError: except ImportError:
_frozen_importlib_external = _bootstrap_external _frozen_importlib_external = _bootstrap_external
from ._abc import Loader
import abc import abc
import warnings import warnings
from typing import Protocol, runtime_checkable from typing import Protocol, runtime_checkable
@ -134,53 +135,6 @@ class PathEntryFinder(Finder):
_register(PathEntryFinder, machinery.FileFinder) _register(PathEntryFinder, machinery.FileFinder)
class Loader(metaclass=abc.ABCMeta):
"""Abstract base class for import loaders."""
def create_module(self, spec):
"""Return a module to initialize and into which to load.
This method should raise ImportError if anything prevents it
from creating a new module. It may return None to indicate
that the spec should create the new module.
"""
# By default, defer to default semantics for the new module.
return None
# We don't define exec_module() here since that would break
# hasattr checks we do to support backward compatibility.
def load_module(self, fullname):
"""Return the loaded module.
The module must be added to sys.modules and have import-related
attributes set properly. The fullname is a str.
ImportError is raised on failure.
This method is deprecated in favor of loader.exec_module(). If
exec_module() exists then it is used to provide a backwards-compatible
functionality for this method.
"""
if not hasattr(self, 'exec_module'):
raise ImportError
return _bootstrap._load_module_shim(self, fullname)
def module_repr(self, module):
"""Return a module's repr.
Used by the module type when the method does not raise
NotImplementedError.
This method is deprecated.
"""
# The exception will cause ModuleType.__repr__ to ignore this method.
raise NotImplementedError
class ResourceLoader(Loader): class ResourceLoader(Loader):
"""Abstract base class for loaders which can return data from their """Abstract base class for loaders which can return data from their

View File

@ -1,5 +1,5 @@
"""Utility code for constructing importers, etc.""" """Utility code for constructing importers, etc."""
from . import abc from ._abc import Loader
from ._bootstrap import module_from_spec from ._bootstrap import module_from_spec
from ._bootstrap import _resolve_name from ._bootstrap import _resolve_name
from ._bootstrap import spec_from_loader from ._bootstrap import spec_from_loader
@ -263,7 +263,7 @@ class _LazyModule(types.ModuleType):
delattr(self, attr) delattr(self, attr)
class LazyLoader(abc.Loader): class LazyLoader(Loader):
"""A loader that creates a module which defers loading until attribute access.""" """A loader that creates a module which defers loading until attribute access."""

View File

@ -650,8 +650,8 @@ class FactoryTests:
# Need to use a circuitous route to get at importlib.machinery to make # Need to use a circuitous route to get at importlib.machinery to make
# sure the same class object is used in the isinstance() check as # sure the same class object is used in the isinstance() check as
# would have been used to create the loader. # would have been used to create the loader.
self.assertIsInstance(spec.loader, SourceFileLoader = self.util.spec_from_file_location.__globals__['SourceFileLoader']
self.util.abc.machinery.SourceFileLoader) self.assertIsInstance(spec.loader, SourceFileLoader)
self.assertEqual(spec.loader.name, self.name) self.assertEqual(spec.loader.name, self.name)
self.assertEqual(spec.loader.path, self.path) self.assertEqual(spec.loader.path, self.path)
self.assertEqual(spec.origin, self.path) self.assertEqual(spec.origin, self.path)