diff options
-rw-r--r-- | Lib/importlib/_bootstrap.py | 345 |
1 files changed, 173 insertions, 172 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 0383c9a..c5588e0 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -173,7 +173,13 @@ def _check_name(method): return inner -# Finders/loaders ############################################################# +def _suffix_list(suffix_type): + """Return a list of file suffixes based on the imp file type.""" + return [suffix[0] for suffix in imp.get_suffixes() + if suffix[2] == suffix_type] + + +# Loaders ##################################################################### class BuiltinImporter: @@ -241,100 +247,6 @@ class FrozenImporter: raise -def _chained_path_hook(*path_hooks): - """Create a closure which sequentially checks path hooks to see which ones - (if any) can work with a path.""" - def path_hook(entry): - """Check to see if 'entry' matches any of the enclosed path hooks.""" - finders = [] - for hook in path_hooks: - try: - finder = hook(entry) - except ImportError: - continue - else: - finders.append(finder) - if not finders: - raise ImportError("no finder found") - else: - return _ChainedFinder(*finders) - - return path_hook - - -class _ChainedFinder: - - """Finder that sequentially calls other finders.""" - - def __init__(self, *finders): - self._finders = finders - - def find_module(self, fullname, path=None): - for finder in self._finders: - result = finder.find_module(fullname, path) - if result: - return result - else: - return None - - - -class _ExtensionFileLoader: - - """Loader for extension modules. - - The constructor is designed to work with FileFinder. - - """ - - def __init__(self, name, path, is_pkg): - """Initialize the loader. - - If is_pkg is True then an exception is raised as extension modules - cannot be the __init__ module for an extension module. - - """ - self._name = name - self._path = path - if is_pkg: - raise ValueError("extension modules cannot be packages") - - @_check_name - @set_package - @set_loader - def load_module(self, fullname): - """Load an extension module.""" - is_reload = fullname in sys.modules - try: - return imp.load_dynamic(fullname, self._path) - except: - if not is_reload and fullname in sys.modules: - del sys.modules[fullname] - raise - - @_check_name - def is_package(self, fullname): - """Return False as an extension module can never be a package.""" - return False - - @_check_name - def get_code(self, fullname): - """Return None as an extension module cannot create a code object.""" - return None - - @_check_name - def get_source(self, fullname): - """Return None as extension modules have no source code.""" - return None - - -def _suffix_list(suffix_type): - """Return a list of file suffixes based on the imp file type.""" - return [suffix[0] for suffix in imp.get_suffixes() - if suffix[2] == suffix_type] - - - class PyLoader: """Loader base class for Python source. @@ -584,6 +496,136 @@ class PyPycFileLoader(PyPycLoader, PyFileLoader): raise +class _ExtensionFileLoader: + + """Loader for extension modules. + + The constructor is designed to work with FileFinder. + + """ + + def __init__(self, name, path, is_pkg): + """Initialize the loader. + + If is_pkg is True then an exception is raised as extension modules + cannot be the __init__ module for an extension module. + + """ + self._name = name + self._path = path + if is_pkg: + raise ValueError("extension modules cannot be packages") + + @_check_name + @set_package + @set_loader + def load_module(self, fullname): + """Load an extension module.""" + is_reload = fullname in sys.modules + try: + return imp.load_dynamic(fullname, self._path) + except: + if not is_reload and fullname in sys.modules: + del sys.modules[fullname] + raise + + @_check_name + def is_package(self, fullname): + """Return False as an extension module can never be a package.""" + return False + + @_check_name + def get_code(self, fullname): + """Return None as an extension module cannot create a code object.""" + return None + + @_check_name + def get_source(self, fullname): + """Return None as extension modules have no source code.""" + return None + + +# Finders ##################################################################### + +class PathFinder: + + """Meta path finder for sys.(path|path_hooks|path_importer_cache).""" + + @classmethod + def _path_hooks(cls, path, hooks=None): + """Search sequence of hooks for a finder for 'path'. + + If 'hooks' is false then use sys.path_hooks. + + """ + if not hooks: + hooks = sys.path_hooks + for hook in hooks: + try: + return hook(path) + except ImportError: + continue + else: + raise ImportError("no path hook found for {0}".format(path)) + + @classmethod + def _path_importer_cache(cls, path, default=None): + """Get the finder for the path from sys.path_importer_cache. + + If the path is not in the cache, find the appropriate finder and cache + it. If None is cached, get the default finder and cache that + (if applicable). + + Because of NullImporter, some finder should be returned. The only + explicit fail case is if None is cached but the path cannot be used for + the default hook, for which ImportError is raised. + + """ + try: + finder = sys.path_importer_cache[path] + except KeyError: + finder = cls._path_hooks(path) + sys.path_importer_cache[path] = finder + else: + if finder is None and default: + # Raises ImportError on failure. + finder = default(path) + sys.path_importer_cache[path] = finder + return finder + + @classmethod + def find_module(cls, fullname, path=None): + """Find the module on sys.path or 'path'.""" + if not path: + path = sys.path + for entry in path: + try: + finder = cls._path_importer_cache(entry) + except ImportError: + continue + loader = finder.find_module(fullname) + if loader: + return loader + else: + return None + + +class _ChainedFinder: + + """Finder that sequentially calls other finders.""" + + def __init__(self, *finders): + self._finders = finders + + def find_module(self, fullname, path=None): + for finder in self._finders: + result = finder.find_module(fullname, path) + if result: + return result + else: + return None + + class FileFinder: """Base class for file finders. @@ -643,20 +685,6 @@ class FileFinder: return None -class ExtensionFileFinder(FileFinder): - - """Importer for extension files.""" - - _possible_package = False - _loader = _ExtensionFileLoader - - def __init__(self, path_entry): - # Assigning to _suffixes here instead of at the class level because - # imp is not imported at the time of class creation. - self._suffixes = _suffix_list(imp.C_EXTENSION) - super().__init__(path_entry) - - class PyFileFinder(FileFinder): """Importer for source/bytecode files.""" @@ -683,82 +711,43 @@ class PyPycFileFinder(PyFileFinder): self._suffixes += _suffix_list(imp.PY_COMPILED) -class PathFinder: - """Meta path finder for sys.(path|path_hooks|path_importer_cache).""" - @classmethod - def _path_hooks(cls, path, hooks=None): - """Search sequence of hooks for a finder for 'path'. - - If 'hooks' is false then use sys.path_hooks. +class ExtensionFileFinder(FileFinder): - """ - if not hooks: - hooks = sys.path_hooks - for hook in hooks: - try: - return hook(path) - except ImportError: - continue - else: - raise ImportError("no path hook found for {0}".format(path)) + """Importer for extension files.""" - @classmethod - def _path_importer_cache(cls, path, default=None): - """Get the finder for the path from sys.path_importer_cache. + _possible_package = False + _loader = _ExtensionFileLoader - If the path is not in the cache, find the appropriate finder and cache - it. If None is cached, get the default finder and cache that - (if applicable). + def __init__(self, path_entry): + # Assigning to _suffixes here instead of at the class level because + # imp is not imported at the time of class creation. + self._suffixes = _suffix_list(imp.C_EXTENSION) + super().__init__(path_entry) - Because of NullImporter, some finder should be returned. The only - explicit fail case is if None is cached but the path cannot be used for - the default hook, for which ImportError is raised. - """ - try: - finder = sys.path_importer_cache[path] - except KeyError: - finder = cls._path_hooks(path) - sys.path_importer_cache[path] = finder - else: - if finder is None and default: - # Raises ImportError on failure. - finder = default(path) - sys.path_importer_cache[path] = finder - return finder +# Import itself ############################################################### - @classmethod - def find_module(cls, fullname, path=None): - """Find the module on sys.path or 'path'.""" - if not path: - path = sys.path - for entry in path: +def _chained_path_hook(*path_hooks): + """Create a closure which sequentially checks path hooks to see which ones + (if any) can work with a path.""" + def path_hook(entry): + """Check to see if 'entry' matches any of the enclosed path hooks.""" + finders = [] + for hook in path_hooks: try: - finder = cls._path_importer_cache(entry) + finder = hook(entry) except ImportError: continue - loader = finder.find_module(fullname) - if loader: - return loader + else: + finders.append(finder) + if not finders: + raise ImportError("no finder found") else: - return None - - -# Import itself ############################################################### - -class _ImportLockContext: - - """Context manager for the import lock.""" - - def __enter__(self): - """Acquire the import lock.""" - imp.acquire_lock() + return _ChainedFinder(*finders) - def __exit__(self, exc_type, exc_value, exc_traceback): - """Release the import lock regardless of any raised exceptions.""" - imp.release_lock() + return path_hook _DEFAULT_PATH_HOOK = _chained_path_hook(ExtensionFileFinder, PyPycFileFinder) @@ -784,6 +773,18 @@ class _DefaultPathFinder(PathFinder): return super()._path_importer_cache(path, _DEFAULT_PATH_HOOK) +class _ImportLockContext: + + """Context manager for the import lock.""" + + def __enter__(self): + """Acquire the import lock.""" + imp.acquire_lock() + + def __exit__(self, exc_type, exc_value, exc_traceback): + """Release the import lock regardless of any raised exceptions.""" + imp.release_lock() + _IMPLICIT_META_PATH = [BuiltinImporter, FrozenImporter, _DefaultPathFinder] |