Commit 5abdc93e authored by Brett Cannon's avatar Brett Cannon

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).
parent 7b3c89d8
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 ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -90,60 +90,17 @@ class closing: ...@@ -90,60 +90,17 @@ class closing:
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 @@ class BuiltinImporter(_BuiltinFrozenBaseLoader): ...@@ -151,36 +108,36 @@ class BuiltinImporter(_BuiltinFrozenBaseLoader):
""" """
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):
"""Meta path class for importing frozen modules.""" class FrozenImporter:
type_ = 'frozen' """Meta path class for importing frozen modules.
def __init__(self): All methods are either class or static method to allow direct use of the
"""Specify the methods needed by the superclass. class.
Because imp may not be injected until after class creation these """
methods cannot be set at the class level.
""" @classmethod
self._find = imp.is_frozen def find_module(cls, fullname, path=None):
self._load = imp.init_frozen """Find a frozen module."""
return cls if imp.is_frozen(fullname) else None
def load_module(self, fullname): @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 @@ class Import(object): ...@@ -707,7 +664,7 @@ class Import(object):
"""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
......
"""The machinery of importlib: finders, loaders, hooks, etc."""
from ._bootstrap import BuiltinImporter
from ._bootstrap import FrozenImporter
import importlib from importlib import machinery
from .. import support from .. import support
import sys import sys
...@@ -12,7 +12,7 @@ class FinderTests(unittest.TestCase): ...@@ -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):
......
import importlib import importlib
from importlib import machinery
from .. import support from .. import support
import sys import sys
...@@ -23,7 +24,7 @@ class LoaderTests(unittest.TestCase): ...@@ -23,7 +24,7 @@ class LoaderTests(unittest.TestCase):
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.
......
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): ...@@ -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)
......
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): ...@@ -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__']}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment