diff options
author | Brett Cannon <brett@python.org> | 2012-04-22 23:58:33 (GMT) |
---|---|---|
committer | Brett Cannon <brett@python.org> | 2012-04-22 23:58:33 (GMT) |
commit | 938d44d59c9cc142d35f51a908cabf781b482f26 (patch) | |
tree | 93d2bd601f966f742ef2f6caca7b374e84f6a0b2 /Lib/importlib/_bootstrap.py | |
parent | 8c5e920ae3e98ebc5b37a105cf86e4c1e9649f57 (diff) | |
download | cpython-938d44d59c9cc142d35f51a908cabf781b482f26.zip cpython-938d44d59c9cc142d35f51a908cabf781b482f26.tar.gz cpython-938d44d59c9cc142d35f51a908cabf781b482f26.tar.bz2 |
Issue #14605: Expose importlib.abc.FileLoader and
importlib.machinery.(FileFinder, SourceFileLoader,
_SourcelessFileLoader, ExtensionFileLoader).
This exposes all of importlib's mechanisms that will become public on
the sys module.
Diffstat (limited to 'Lib/importlib/_bootstrap.py')
-rw-r--r-- | Lib/importlib/_bootstrap.py | 101 |
1 files changed, 47 insertions, 54 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 04ceb56..d9df2b7 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -13,6 +13,9 @@ 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. +# XXX Make sure all public names have no single leading underscore and all +# others do. + # Bootstrap-related code ###################################################### @@ -283,7 +286,7 @@ def _check_name(method): """ def _check_name_wrapper(self, name, *args, **kwargs): - if self._name != name: + if self.name != name: raise ImportError("loader cannot handle %s" % name, name=name) return method(self, name, *args, **kwargs) _wrap(_check_name_wrapper, method) @@ -423,7 +426,7 @@ class FrozenImporter: class _LoaderBasics: """Base class of common code needed by both SourceLoader and - _SourcelessFileLoader.""" + SourcelessFileLoader.""" def is_package(self, fullname): """Concrete implementation of InspectLoader.is_package by checking if @@ -608,7 +611,7 @@ class SourceLoader(_LoaderBasics): return self._load_module(fullname) -class _FileLoader: +class FileLoader: """Base file loader class which implements the loader protocol methods that require file system usage.""" @@ -616,13 +619,13 @@ class _FileLoader: def __init__(self, fullname, path): """Cache the module name and the path to the file found by the finder.""" - self._name = fullname - self._path = path + self.name = fullname + self.path = path @_check_name def get_filename(self, fullname): """Return the path to the source file as found by the finder.""" - return self._path + return self.path def get_data(self, path): """Return the data from path as raw bytes.""" @@ -630,7 +633,7 @@ class _FileLoader: return file.read() -class _SourceFileLoader(_FileLoader, SourceLoader): +class SourceFileLoader(FileLoader, SourceLoader): """Concrete implementation of SourceLoader using the file system.""" @@ -668,7 +671,7 @@ class _SourceFileLoader(_FileLoader, SourceLoader): pass -class _SourcelessFileLoader(_FileLoader, _LoaderBasics): +class _SourcelessFileLoader(FileLoader, _LoaderBasics): """Loader which handles sourceless file imports.""" @@ -692,7 +695,7 @@ class _SourcelessFileLoader(_FileLoader, _LoaderBasics): return None -class _ExtensionFileLoader: +class ExtensionFileLoader: """Loader for extension modules. @@ -701,8 +704,8 @@ class _ExtensionFileLoader: """ def __init__(self, name, path): - self._name = name - self._path = path + self.name = name + self.path = path @_check_name @set_package @@ -711,8 +714,8 @@ class _ExtensionFileLoader: """Load an extension module.""" is_reload = fullname in sys.modules try: - module = _imp.load_dynamic(fullname, self._path) - verbose_message('extension module loaded from {!r}', self._path) + module = _imp.load_dynamic(fullname, self.path) + verbose_message('extension module loaded from {!r}', self.path) return module except: if not is_reload and fullname in sys.modules: @@ -805,24 +808,25 @@ class PathFinder: return None -class _FileFinder: +class FileFinder: """File-based finder. - Constructor takes a list of objects detailing what file extensions their - loader supports along with whether it can be used for a package. + Interactions with the file system are cached for performance, being + refreshed when the directory the finder is handling has been modified. """ def __init__(self, path, *details): - """Initialize with finder details.""" + """Initialize with the path to search on and a variable number of + 3-tuples containing the loader, file suffixes the loader recognizes, and + a boolean of whether the loader handles packages.""" packages = [] modules = [] - for detail in details: - modules.extend((suffix, detail.loader) for suffix in detail.suffixes) - if detail.supports_packages: - packages.extend((suffix, detail.loader) - for suffix in detail.suffixes) + for loader, suffixes, supports_packages in details: + modules.extend((suffix, loader) for suffix in suffixes) + if supports_packages: + packages.extend((suffix, loader) for suffix in suffixes) self.packages = packages self.modules = modules # Base (directory) path @@ -898,46 +902,29 @@ class _FileFinder: if sys.platform.startswith(CASE_INSENSITIVE_PLATFORMS): self._relaxed_path_cache = set(fn.lower() for fn in contents) + @classmethod + def path_hook(cls, *loader_details): + """A class method which returns a closure to use on sys.path_hook + which will return an instance using the specified loaders and the path + called on the closure. -class _SourceFinderDetails: - - loader = _SourceFileLoader - supports_packages = True - - def __init__(self): - self.suffixes = _suffix_list(_imp.PY_SOURCE) - -class _SourcelessFinderDetails: - - loader = _SourcelessFileLoader - supports_packages = True - - def __init__(self): - self.suffixes = _suffix_list(_imp.PY_COMPILED) - + If the path called on the closure is not a directory, ImportError is + raised. -class _ExtensionFinderDetails: + """ + def path_hook_for_FileFinder(path): + """Path hook for importlib.machinery.FileFinder.""" + if not _path_isdir(path): + raise ImportError("only directories are supported", path=path) + return cls(path, *loader_details) - loader = _ExtensionFileLoader - supports_packages = False + return path_hook_for_FileFinder - def __init__(self): - self.suffixes = _suffix_list(_imp.C_EXTENSION) # Import itself ############################################################### -def _file_path_hook(path): - """If the path is a directory, return a file-based finder.""" - if _path_isdir(path): - return _FileFinder(path, _ExtensionFinderDetails(), - _SourceFinderDetails(), - _SourcelessFinderDetails()) - else: - raise ImportError("only directories are supported", path=path) - - -_DEFAULT_PATH_HOOK = _file_path_hook +_DEFAULT_PATH_HOOK = None # Set in _setup() class _DefaultPathFinder(PathFinder): @@ -1209,6 +1196,12 @@ def _setup(sys_module, _imp_module): if builtin_os == 'nt': SOURCE_SUFFIXES.append('.pyw') + supported_loaders = [(ExtensionFileLoader, _suffix_list(3), False), + (SourceFileLoader, _suffix_list(1), True), + (_SourcelessFileLoader, _suffix_list(2), True)] + setattr(self_module, '_DEFAULT_PATH_HOOK', + FileFinder.path_hook(*supported_loaders)) + def _install(sys_module, _imp_module): """Install importlib as the implementation of import. |