[Python-checkins] r56881 - in sandbox/trunk/import_in_py: NOTES _importlib.py tests/test_path_hooks.py
brett.cannon
python-checkins at python.org
Fri Aug 10 03:42:10 CEST 2007
Author: brett.cannon
Date: Fri Aug 10 03:42:09 2007
New Revision: 56881
Added:
sandbox/trunk/import_in_py/NOTES (contents, props changed)
sandbox/trunk/import_in_py/tests/test_path_hooks.py (contents, props changed)
Modified:
sandbox/trunk/import_in_py/_importlib.py
Log:
Implement a generic chaining path hook that returns a chaining importer.
Include tests for the path hook (but not for the importer yet).
The eventual goal is a reworking of the filesystem importer and loader so that
it is not quite so generic in order to have a more reasonable API for loaders
as expected by the py/pyc handler.
Added: sandbox/trunk/import_in_py/NOTES
==============================================================================
--- (empty file)
+++ sandbox/trunk/import_in_py/NOTES Fri Aug 10 03:42:09 2007
@@ -0,0 +1,28 @@
+py/pyc loader API (beyond load_module):
+* mod_time(module_name) -> int
+ Find out the modification time for a source module. If no source module
+ exists, raise XXX.
+* source(module_name) -> str
+ Return the text for a source module.
+ XXX Can this be replaced by get_source? Only if expected to be defined on
+ a loader.
+* bytecode(module_name) -> bytes|str
+ Return the bytes for a bytecode module.
+ XXX Rename to get_bytecode if get_source is viable for source().
+* write_bytecode(module_name, data:bytes|str) -> bool
+ Write out the new representation of a bytecode module. Returns a boolean
+ representing whether the bytes were actually written out or not.
+
+
+Handler API:
+* cannot_handle(name:str) -> bool
+ Can the handler handle with the specified module?
+* handle_code(loader:object, mod_name:str, file_path:str,
+ source:bool, bytecode:bool,
+ package_path:str|None=None) -> object
+ Handle the loading of the specified module. All needed objects to be set
+ as attributes on the module are passed in as arguments (__file__,
+ __loader__, and __path__). Also any other information that must be known
+ for any proper import to occur is specified up front. All other
+ information that is optional and varies depending on what the loader can
+ provide is done through a separate API provided by the loader.
Modified: sandbox/trunk/import_in_py/_importlib.py
==============================================================================
--- sandbox/trunk/import_in_py/_importlib.py (original)
+++ sandbox/trunk/import_in_py/_importlib.py Fri Aug 10 03:42:09 2007
@@ -161,6 +161,44 @@
self._load = imp.init_frozen
+class ChainedImporter(object):
+
+ """Importer that sequentially calls other importers."""
+
+ def __init__(self, *importers):
+ self._importers = importers
+
+ def find_module(fullname, path=None):
+ for importer in self._importers:
+ result = importer.find_module(fullname, path)
+ if result:
+ return result
+ else:
+ return None
+
+
+def chaining_fs_path_hook(*path_hooks):
+ """Create a path hook that sequentially asks other path hooks if they can
+ handle a sys.path entry, returning a chained importer for those that said
+ they could."""
+ def chained_fs_path_hook(path_entry):
+ """Check which of the associated importers are able to handle the
+ filesystem path entry."""
+ absolute_path = _path_absolute(path_entry)
+ if not _path_isdir(absolute_path):
+ raise ImportError("only directories are supported")
+ accepted = []
+ for path_hook in path_hooks:
+ try:
+ accepted.append(path_hook(absolute_path))
+ except ImportError:
+ continue
+ if not accepted:
+ raise ImportError("no path hooks could handle %s" % path_entry)
+ return ChainedImporter(*accepted)
+ return chained_fs_path_hook
+
+
class FileSystemFactory(object):
"""Factory function for sys.path_hooks for directory entries on sys.path.
Added: sandbox/trunk/import_in_py/tests/test_path_hooks.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/import_in_py/tests/test_path_hooks.py Fri Aug 10 03:42:09 2007
@@ -0,0 +1,61 @@
+import importlib
+from tests import mock_importlib
+
+import os
+from test import test_support
+import unittest
+
+
+class ChainingPathHook(unittest.TestCase):
+
+ def test_single_hook(self):
+ # A single hook argument should work as expected.
+ hook = importlib.chaining_fs_path_hook(mock_importlib.SucceedImporter())
+ self.assert_(hook('.'))
+ hook = importlib.chaining_fs_path_hook(mock_importlib.PassImporter())
+ self.assertRaises(ImportError, hook, '.')
+
+ def test_path_acceptance(self):
+ # Valid paths should be accepted, but non-existent paths should be
+ # rejected outright.
+ succeed_hook = mock_importlib.SucceedImporter()
+ hook = importlib.chaining_fs_path_hook(succeed_hook)
+ self.assert_(hook('.'))
+ self.assertRaises(ImportError, hook, '_nonexistentdirectory')
+
+ def test_multiple_hooks(self):
+ # Multiple hooks should work.
+ succeed_hook = mock_importlib.SucceedImporter()
+ pass_hook = mock_importlib.PassImporter()
+ hook = importlib.chaining_fs_path_hook(pass_hook, succeed_hook)
+ self.assert_(hook('.'))
+ hook = importlib.chaining_fs_path_hook(succeed_hook, pass_hook)
+ self.assert_(hook('.'))
+ hook = importlib.chaining_fs_path_hook(pass_hook, pass_hook)
+ self.assertRaises(ImportError, hook, '.')
+
+ # Dependent on implementation details.
+ def test_order_preservation(self):
+ # The order of importers to call should be maintained.
+ succeed1 = mock_importlib.SucceedImporter()
+ succeed2 = mock_importlib.SucceedImporter()
+ hook = importlib.chaining_fs_path_hook(succeed1, succeed2)
+ importer = hook('.')
+ self.assert_(importer._importers[0] is succeed1)
+ self.assert_(importer._importers[1] is succeed2)
+
+ def test_absolute_path(self):
+ # The path hooks that are called should be passed an absolute path.
+ succeed = mock_importlib.SucceedImporter()
+ hook = importlib.chaining_fs_path_hook(succeed)
+ hook('.')
+ absolute_path = os.path.abspath('.')
+ self.assertEquals(os.path.normpath(succeed.path_entries[0]), absolute_path)
+
+
+def test_main():
+ test_support.run_unittest(ChainingPathHook)
+
+
+if __name__ == '__main__':
+ test_main()
More information about the Python-checkins
mailing list