bpo-42403: Simplify importlib external bootstrap (GH-23397)
Simplify the importlib external bootstrap code: importlib._bootstrap_external now uses regular imports to import builtin modules. When it is imported, the builtin __import__() function is already fully working and so can be used to import builtin modules like sys.
This commit is contained in:
parent
7d9d25dbed
commit
3390347aa0
|
@ -34,7 +34,7 @@ try:
|
|||
import _frozen_importlib_external as _bootstrap_external
|
||||
except ImportError:
|
||||
from . import _bootstrap_external
|
||||
_bootstrap_external._setup(_bootstrap)
|
||||
_bootstrap_external._set_bootstrap_module(_bootstrap)
|
||||
_bootstrap._bootstrap_external = _bootstrap_external
|
||||
else:
|
||||
_bootstrap_external.__name__ = 'importlib._bootstrap_external'
|
||||
|
|
|
@ -22,8 +22,15 @@ work. One should use importlib as the public-facing version of this module.
|
|||
|
||||
# Bootstrap-related code ######################################################
|
||||
|
||||
# Modules injected manually by _setup()
|
||||
_thread = None
|
||||
_warnings = None
|
||||
_weakref = None
|
||||
|
||||
# Import done by _install_external_importers()
|
||||
_bootstrap_external = None
|
||||
|
||||
|
||||
def _wrap(new, old):
|
||||
"""Simple substitute for functools.update_wrapper."""
|
||||
for replace in ['__module__', '__name__', '__qualname__', '__doc__']:
|
||||
|
|
|
@ -19,6 +19,36 @@ work. One should use importlib as the public-facing version of this module.
|
|||
# reference any injected objects! This includes not only global code but also
|
||||
# anything specified at the class level.
|
||||
|
||||
# Module injected manually by _set_bootstrap_module()
|
||||
_bootstrap = None
|
||||
|
||||
# Import builtin modules
|
||||
import _imp
|
||||
import _io
|
||||
import sys
|
||||
import _warnings
|
||||
import marshal
|
||||
|
||||
|
||||
_MS_WINDOWS = (sys.platform == 'win32')
|
||||
if _MS_WINDOWS:
|
||||
import nt as _os
|
||||
import winreg
|
||||
else:
|
||||
import posix as _os
|
||||
|
||||
|
||||
if _MS_WINDOWS:
|
||||
path_separators = ['\\', '/']
|
||||
else:
|
||||
path_separators = ['/']
|
||||
# Assumption made in _path_join()
|
||||
assert all(len(sep) == 1 for sep in path_separators)
|
||||
path_sep = path_separators[0]
|
||||
path_separators = ''.join(path_separators)
|
||||
_pathseps_with_colon = {f':{s}' for s in path_separators}
|
||||
|
||||
|
||||
# Bootstrap-related code ######################################################
|
||||
_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
|
||||
_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
|
||||
|
@ -42,6 +72,8 @@ def _make_relax_case():
|
|||
return False
|
||||
return _relax_case
|
||||
|
||||
_relax_case = _make_relax_case()
|
||||
|
||||
|
||||
def _pack_uint32(x):
|
||||
"""Convert a 32-bit integer to little-endian."""
|
||||
|
@ -294,7 +326,11 @@ _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
|||
_PYCACHE = '__pycache__'
|
||||
_OPT = 'opt-'
|
||||
|
||||
SOURCE_SUFFIXES = ['.py'] # _setup() adds .pyw as needed.
|
||||
SOURCE_SUFFIXES = ['.py']
|
||||
if _MS_WINDOWS:
|
||||
SOURCE_SUFFIXES.append('.pyw')
|
||||
|
||||
EXTENSION_SUFFIXES = _imp.extension_suffixes()
|
||||
|
||||
BYTECODE_SUFFIXES = ['.pyc']
|
||||
# Deprecated.
|
||||
|
@ -469,15 +505,18 @@ def _check_name(method):
|
|||
raise ImportError('loader for %s cannot handle %s' %
|
||||
(self.name, name), name=name)
|
||||
return method(self, name, *args, **kwargs)
|
||||
try:
|
||||
|
||||
# FIXME: @_check_name is used to define class methods before the
|
||||
# _bootstrap module is set by _set_bootstrap_module().
|
||||
if _bootstrap is not None:
|
||||
_wrap = _bootstrap._wrap
|
||||
except NameError:
|
||||
# XXX yuck
|
||||
else:
|
||||
def _wrap(new, old):
|
||||
for replace in ['__module__', '__name__', '__qualname__', '__doc__']:
|
||||
if hasattr(old, replace):
|
||||
setattr(new, replace, getattr(old, replace))
|
||||
new.__dict__.update(old.__dict__)
|
||||
|
||||
_wrap(_check_name_wrapper, method)
|
||||
return _check_name_wrapper
|
||||
|
||||
|
@ -713,7 +752,7 @@ class WindowsRegistryFinder:
|
|||
REGISTRY_KEY_DEBUG = (
|
||||
'Software\\Python\\PythonCore\\{sys_version}'
|
||||
'\\Modules\\{fullname}\\Debug')
|
||||
DEBUG_BUILD = False # Changed in _setup()
|
||||
DEBUG_BUILD = (_MS_WINDOWS and '_d.pyd' in EXTENSION_SUFFIXES)
|
||||
|
||||
@classmethod
|
||||
def _open_registry(cls, key):
|
||||
|
@ -1060,10 +1099,6 @@ class SourcelessFileLoader(FileLoader, _LoaderBasics):
|
|||
return None
|
||||
|
||||
|
||||
# Filled in by _setup().
|
||||
EXTENSION_SUFFIXES = []
|
||||
|
||||
|
||||
class ExtensionFileLoader(FileLoader, _LoaderBasics):
|
||||
|
||||
"""Loader for extension modules.
|
||||
|
@ -1552,66 +1587,14 @@ def _get_supported_file_loaders():
|
|||
return [extensions, source, bytecode]
|
||||
|
||||
|
||||
def _setup(_bootstrap_module):
|
||||
"""Setup the path-based importers for importlib by importing needed
|
||||
built-in modules and injecting them into the global namespace.
|
||||
|
||||
Other components are extracted from the core bootstrap module.
|
||||
|
||||
"""
|
||||
global sys, _imp, _bootstrap
|
||||
def _set_bootstrap_module(_bootstrap_module):
|
||||
global _bootstrap
|
||||
_bootstrap = _bootstrap_module
|
||||
sys = _bootstrap.sys
|
||||
_imp = _bootstrap._imp
|
||||
|
||||
self_module = sys.modules[__name__]
|
||||
|
||||
# Directly load the os module (needed during bootstrap).
|
||||
os_details = ('posix', ['/']), ('nt', ['\\', '/'])
|
||||
for builtin_os, path_separators in os_details:
|
||||
# Assumption made in _path_join()
|
||||
assert all(len(sep) == 1 for sep in path_separators)
|
||||
path_sep = path_separators[0]
|
||||
if builtin_os in sys.modules:
|
||||
os_module = sys.modules[builtin_os]
|
||||
break
|
||||
else:
|
||||
try:
|
||||
os_module = _bootstrap._builtin_from_name(builtin_os)
|
||||
break
|
||||
except ImportError:
|
||||
continue
|
||||
else:
|
||||
raise ImportError('importlib requires posix or nt')
|
||||
|
||||
setattr(self_module, '_os', os_module)
|
||||
setattr(self_module, 'path_sep', path_sep)
|
||||
setattr(self_module, 'path_separators', ''.join(path_separators))
|
||||
setattr(self_module, '_pathseps_with_colon', {f':{s}' for s in path_separators})
|
||||
|
||||
# Directly load built-in modules needed during bootstrap.
|
||||
builtin_names = ['_io', '_warnings', 'marshal']
|
||||
if builtin_os == 'nt':
|
||||
builtin_names.append('winreg')
|
||||
for builtin_name in builtin_names:
|
||||
if builtin_name not in sys.modules:
|
||||
builtin_module = _bootstrap._builtin_from_name(builtin_name)
|
||||
else:
|
||||
builtin_module = sys.modules[builtin_name]
|
||||
setattr(self_module, builtin_name, builtin_module)
|
||||
|
||||
# Constants
|
||||
setattr(self_module, '_relax_case', _make_relax_case())
|
||||
EXTENSION_SUFFIXES.extend(_imp.extension_suffixes())
|
||||
if builtin_os == 'nt':
|
||||
SOURCE_SUFFIXES.append('.pyw')
|
||||
if '_d.pyd' in EXTENSION_SUFFIXES:
|
||||
WindowsRegistryFinder.DEBUG_BUILD = True
|
||||
|
||||
|
||||
def _install(_bootstrap_module):
|
||||
"""Install the path-based import components."""
|
||||
_setup(_bootstrap_module)
|
||||
_set_bootstrap_module(_bootstrap_module)
|
||||
supported_loaders = _get_supported_file_loaders()
|
||||
sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
|
||||
sys.meta_path.append(PathFinder)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Simplify the :mod:`importlib` external bootstrap code:
|
||||
``importlib._bootstrap_external`` now uses regular imports to import builtin
|
||||
modules. When it is imported, the builtin :func:`__import__()` function is
|
||||
already fully working and so can be used to import builtin modules like
|
||||
:mod:`sys`. Patch by Victor Stinner.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue