Add importlib.machinery with its first tenants, BuitinImporter and

FrozenImporter. Docs forthcoming.

I plan on all finders and loaders (and most likely hooks) to live
in imoprtlib.machinery. Utility stuff will end up in importlib.util.
Higher-level API stuff will stay on imoprtlib directly (e.g. import_module).
This commit is contained in:
Brett Cannon 2009-01-22 22:43:07 +00:00
parent 7b3c89d88c
commit 5abdc93eb8
7 changed files with 68 additions and 75 deletions

View File

@ -1,9 +1,16 @@
to do to do
///// /////
* Document:
+ The terms "importer", "finder", and "loader".
+ machinery.BuiltinImporter.
+ machinery.FrozenImporter.
* Expose resolve_name(). * Expose resolve_name().
* Backport to Python 2.7. * Backport to Python 2.7.
+ import_module + import_module
+ resolve_name + resolve_name
@ -11,9 +18,11 @@ to do
that various implementations can just subclass as needed. that various implementations can just subclass as needed.
* Expose built-in and frozen importers. * Expose built-in and frozen importers.
+ Make staticmethods so that class can be used directly. + Make staticmethods so that class can be used directly.
* Reorganize support code. * Reorganize support code.
+ Separate general support code and importer-specific (e.g. source) support + Separate general support code and importer-specific (e.g. source) support
code. code.
- Create support modules for each subdirectory (as needed). - Create support modules for each subdirectory (as needed).
@ -22,12 +31,14 @@ to do
- Use in source/test_load_module_mixed. - Use in source/test_load_module_mixed.
* API simplification? * API simplification?
+ read_source -> get_data/source_path + read_source -> get_data/source_path
+ read_bytecode -> get_data/bytecode_path + read_bytecode -> get_data/bytecode_path
+ write_bytecode -> complete set of bytes for bytecode instead of + write_bytecode -> complete set of bytes for bytecode instead of
individual arguments. individual arguments.
* Implement PEP 302 protocol for loaders (should just be a matter of testing). * Implement PEP 302 protocol for loaders (should just be a matter of testing).
+ Built-in. + Built-in.
+ Frozen. + Frozen.
+ Extension. + Extension.
@ -36,39 +47,59 @@ to do
* Create meta_path importer for sys.path. * Create meta_path importer for sys.path.
* OPTIMIZE! * OPTIMIZE!
+ Write benchmark suite. + Write benchmark suite.
+ Fast path common cases. + Fast path common cases.
- Absolute name from sys.path. - Absolute name from sys.path.
- Relative name from sys.path. - Relative name from sys.path.
* Public API to expose (w/ docs!) * Public API to expose (w/ docs!)
+ abc + abc
- Finder - Finder
* find_module * find_module
- Loader - Loader
* load_module * load_module
- ResourceLoader(Loader) - ResourceLoader(Loader)
* get_data * get_data
- InspectLoader(Loader) - InspectLoader(Loader)
* is_package * is_package
* get_code * get_code
* get_source * get_source
- (?) SourceLoader(ResourceLoader) - (?) SourceLoader(ResourceLoader)
* source_path * source_path
* bytecode_path * bytecode_path
* write_bytecode * write_bytecode
+ util + util
- get_module decorator (new name) - get_module decorator (new name)
- check_name decorator (new name) - check_name decorator (new name)
+ hooks (?)
+ machinery
- (?) Chained path hook/finder - (?) Chained path hook/finder
- BuiltinImporter - BuiltinImporter
- FrozenImporter - FrozenImporter
- (?) FileFinder - (?) FileFinder
- Extensions importers - Extensions importers
* ExtensionFinder * ExtensionFinder
* (?) Loader * (?) Loader
- Source/bytecode importers - Source/bytecode importers
* SourceFinder * SourceFinder
* (?) Loader * (?) Loader

View File

@ -90,60 +90,17 @@ def __exit__(self, *args):
self.obj.close() self.obj.close()
class _BuiltinFrozenBaseLoader(object): class BuiltinImporter:
"""Base class for meta_path loaders for built-in and frozen modules. """Meta path loader for built-in modules.
Subclasses must implement: All methods are either class or static methods, allowing direct use of the
class.
* _find(fullname:str) -> bool
Finder which returns whether the class can handle the module.
* _load(fullname:str) -> module
Loader which returns the loaded module. The check for sys.modules
does not need to be handled by this method.
* type_:str
Name of the type of module being handled. Used in error messages.
""" """
def find_module(self, fullname, path=None): @classmethod
"""Find a module.""" def find_module(cls, fullname, path=None):
if not self._find(fullname):
return None
return self
def load_module(self, fullname):
"""Load a module."""
try:
return sys.modules[fullname]
except KeyError:
pass
mod = self._load(fullname)
if not mod:
raise ImportError("expected {0} module not "
"loaded".format(self.type_))
return mod
class BuiltinImporter(_BuiltinFrozenBaseLoader):
"""Meta path loader for built-in modules."""
type_ = "built-in"
def __init__(self):
"""Set the methods needed by the class.
Cannot be set at the class level because the imp module is not
necessarily injected until after the class is created.
"""
self._find = imp.is_builtin
self._load = imp.init_builtin
def find_module(self, fullname, path=None):
"""Try to find the built-in module. """Try to find the built-in module.
If 'path' is ever specified then the search is considered a failure. If 'path' is ever specified then the search is considered a failure.
@ -151,36 +108,36 @@ def find_module(self, fullname, path=None):
""" """
if path is not None: if path is not None:
return None return None
return super().find_module(fullname, path) return cls if imp.is_builtin(fullname) else None
def load_module(self, fullname): @staticmethod
def load_module(fullname):
"""Load a built-in module.""" """Load a built-in module."""
if fullname not in sys.builtin_module_names: if fullname not in sys.builtin_module_names:
raise ImportError("{0} is not a built-in module".format(fullname)) raise ImportError("{0} is not a built-in module".format(fullname))
return super().load_module(fullname) return imp.init_builtin(fullname)
class FrozenImporter(_BuiltinFrozenBaseLoader): class FrozenImporter:
"""Meta path class for importing frozen modules.""" """Meta path class for importing frozen modules.
type_ = 'frozen' All methods are either class or static method to allow direct use of the
class.
def __init__(self):
"""Specify the methods needed by the superclass.
Because imp may not be injected until after class creation these
methods cannot be set at the class level.
""" """
self._find = imp.is_frozen
self._load = imp.init_frozen
def load_module(self, fullname): @classmethod
def find_module(cls, fullname, path=None):
"""Find a frozen module."""
return cls if imp.is_frozen(fullname) else None
@classmethod
def load_module(cls, fullname):
"""Load a frozen module.""" """Load a frozen module."""
if not self.find_module(fullname): if cls.find_module(fullname) is None:
raise ImportError("{0} is not a frozen module".format(fullname)) raise ImportError("{0} is not a frozen module".format(fullname))
return super().load_module(fullname) return imp.init_frozen(fullname)
class ChainedImporter(object): class ChainedImporter(object):
@ -707,7 +664,7 @@ def __init__(self, default_path_hook=None,
"""Store a default path hook entry and a sequence to internally extend """Store a default path hook entry and a sequence to internally extend
sys.meta_path by (passing in None uses default importers).""" sys.meta_path by (passing in None uses default importers)."""
if extended_meta_path is None: if extended_meta_path is None:
self.extended_meta_path = BuiltinImporter(), FrozenImporter() self.extended_meta_path = BuiltinImporter, FrozenImporter
else: else:
self.extended_meta_path = extended_meta_path self.extended_meta_path = extended_meta_path
self.default_path_hook = default_path_hook self.default_path_hook = default_path_hook

View File

@ -0,0 +1,4 @@
"""The machinery of importlib: finders, loaders, hooks, etc."""
from ._bootstrap import BuiltinImporter
from ._bootstrap import FrozenImporter

View File

@ -1,4 +1,4 @@
import importlib from importlib import machinery
from .. import support from .. import support
import sys import sys
@ -12,7 +12,7 @@ class FinderTests(unittest.TestCase):
name = 'errno' name = 'errno'
find_module = staticmethod(lambda name, path=None: find_module = staticmethod(lambda name, path=None:
importlib.BuiltinImporter().find_module(name, path)) machinery.BuiltinImporter.find_module(name, path))
def test_find_module(self): def test_find_module(self):

View File

@ -1,4 +1,5 @@
import importlib import importlib
from importlib import machinery
from .. import support from .. import support
import sys import sys
@ -23,7 +24,7 @@ def verify(self, module):
self.assert_(module.__name__ in sys.modules) self.assert_(module.__name__ in sys.modules)
load_module = staticmethod(lambda name: load_module = staticmethod(lambda name:
importlib.BuiltinImporter().load_module(name)) machinery.BuiltinImporter.load_module(name))
def test_load_module(self): def test_load_module(self):
# Common case. # Common case.

View File

@ -1,4 +1,4 @@
import importlib from importlib import machinery
from ..builtin import test_finder from ..builtin import test_finder
from .. import support from .. import support
@ -10,7 +10,7 @@ class FinderTests(test_finder.FinderTests):
"""Test finding frozen modules.""" """Test finding frozen modules."""
def find(self, name, path=None): def find(self, name, path=None):
finder = importlib.FrozenImporter() finder = machinery.FrozenImporter
return finder.find_module(name, path) return finder.find_module(name, path)

View File

@ -1,4 +1,4 @@
import importlib from importlib import machinery
from ..builtin import test_loader from ..builtin import test_loader
@ -6,7 +6,7 @@ class LoaderTests(test_loader.LoaderTests):
name = '__phello__' name = '__phello__'
load_module = staticmethod(lambda name: load_module = staticmethod(lambda name:
importlib.FrozenImporter().load_module(name)) machinery.FrozenImporter.load_module(name))
verification = {'__name__': '__phello__', '__file__': '<frozen>', verification = {'__name__': '__phello__', '__file__': '<frozen>',
'__package__': None, '__path__': ['__phello__']} '__package__': None, '__path__': ['__phello__']}