diff options
Diffstat (limited to 'Lib/importlib/_bootstrap.py')
| -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]  | 
