[Python-checkins] r57306 - in sandbox/trunk/import_in_py: Py3K_TODO _importlib.py controlled_importlib.py tests/test_fs_loader.py
brett.cannon
python-checkins at python.org
Thu Aug 23 02:03:06 CEST 2007
Author: brett.cannon
Date: Thu Aug 23 02:03:06 2007
New Revision: 57306
Modified:
sandbox/trunk/import_in_py/Py3K_TODO
sandbox/trunk/import_in_py/_importlib.py
sandbox/trunk/import_in_py/controlled_importlib.py
sandbox/trunk/import_in_py/tests/test_fs_loader.py
Log:
Make the source loader stateless. Ups the amount of stat calls that need to be
made slightly, but it is not atrocious.
Modified: sandbox/trunk/import_in_py/Py3K_TODO
==============================================================================
--- sandbox/trunk/import_in_py/Py3K_TODO (original)
+++ sandbox/trunk/import_in_py/Py3K_TODO Thu Aug 23 02:03:06 2007
@@ -4,8 +4,8 @@
- 2.6-specific
* Be backwards-compatible.
+ All tests must pass!
- - importlib tests.
- - 2.6 stdlib tests using importlib (see regrtest.sh).
+ - 2.6 stdlib tests using importlib.
+ * Use regrtest.sh editing so all tests are run.
* Rewrite zipimport.
* Put into 2.6 stdlib.
- Py3K-specific
Modified: sandbox/trunk/import_in_py/_importlib.py
==============================================================================
--- sandbox/trunk/import_in_py/_importlib.py (original)
+++ sandbox/trunk/import_in_py/_importlib.py Thu Aug 23 02:03:06 2007
@@ -95,9 +95,13 @@
"""Replacement for os.path.isdir."""
return _path_is_mode_type(path, 0040000)
-def _path_without_ext(path):
+def _path_without_ext(path, ext_type):
"""Replacement for os.path.splitext()[0]."""
- return path.rsplit('.', 1)[0]
+ for suffix in suffix_list(ext_type):
+ if path.endswith(suffix):
+ return path[:-len(suffix)]
+ else:
+ raise ValueError("path is not of the specified type")
def _path_absolute(path):
"""Replacement for os.path.abspath."""
@@ -286,7 +290,9 @@
code object in a two-item sequence."""
# Request paths instead of just booleans since 'compile' needs it for
# source.
- assert source_path or bytecode_path
+ if not source_path and not bytecode_path:
+ raise ValueError("neither source nor bytecode was specified as "
+ "available")
source_timestamp = None
# Try to use bytecode if it is available.
if bytecode_path:
@@ -340,33 +346,44 @@
def __init__(self, name, path, is_pkg):
self._name = name
self._is_pkg = is_pkg
- self._source_path = None
- self._bytecode_path = None
- # Figure out whether source and/or bytecode exists.
- for suffix in suffix_list(imp.PY_SOURCE):
- if path.endswith(suffix):
- # Source was found, but we don't know about the bytecode as the
- # importer guarantees to check for source first.
- self._source_path = path
- base_path = _path_without_ext(path)
- for suffix in suffix_list(imp.PY_COMPILED):
- bytecode_path = base_path + suffix
- if _path_exists(bytecode_path):
- self._bytecode_path = bytecode_path
- break
- # Source was found, but no corresponding bytecode exists.
- # Since source was found, the loop should be stopped.
- break
- else:
- # The loader is being asked to load a bytecode file since it was
- # not asked to load a source file and that is searched for first.
- self._bytecode_path = path
+ # Figure out the base path based on whether it was source or bytecode
+ # that was found.
+ try:
+ self._base_path = _path_without_ext(path, imp.PY_SOURCE)
+ except ValueError:
+ self._base_path = _path_without_ext(path, imp.PY_COMPILED)
+
+ def _find_path(self, ext_type):
+ """Find a path from the base path and the specified extension type that
+ exists, returning None if one is not found."""
+ for suffix in suffix_list(ext_type):
+ path = self._base_path + suffix
+ if _path_exists(path):
+ return path
+ else:
+ return None
+
+
+ def _source_path(self):
+ """Return the path to an existing source file for the module, or None
+ if one cannot be found."""
+ # Not a property so that it is easy to override.
+ return self._find_path(imp.PY_SOURCE)
+
+ def _bytecode_path(self):
+ """Return the path to a bytecode file, or None if one does not
+ exist."""
+ # Not a property for easy overriding.
+ return self._find_path(imp.PY_COMPILED)
@check_name
def load_module(self, fullname):
"""Load a Python source or bytecode file."""
- code_object, path = self._handler(fullname, self._source_path,
- self._bytecode_path)
+ try:
+ code_object, path = self._handler(fullname, self._source_path(),
+ self._bytecode_path())
+ except ValueError:
+ raise ImportError("loader cannot handle %s" % fullname)
try:
return self._module_init(code_object, fullname, path, self._is_pkg)
except:
@@ -383,8 +400,9 @@
if the loader cannot handle the module.
"""
- if self._source_path:
- return int(_os.stat(self._source_path).st_mtime)
+ source_path = self._source_path()
+ if source_path:
+ return int(_os.stat(source_path).st_mtime)
else:
raise ValueError('no source for %s' % name)
@@ -396,9 +414,10 @@
Raises ImportError if the loader cannot handle the module.
"""
- if self._source_path and _path_exists(self._source_path):
- return open(self._source_path, 'U').read()
- elif self._bytecode_path and _path_exists(self._bytecode_path):
+ source_path = self._source_path()
+ if source_path:
+ return open(source_path, 'U').read()
+ elif self._bytecode_path():
return None
else:
raise ImportError('no source or bytecode available')
@@ -413,7 +432,7 @@
"""
try:
- with open(self._bytecode_path, 'rb') as bytecode_file:
+ with open(self._bytecode_path(), 'rb') as bytecode_file:
data = bytecode_file.read()
return data[:4], _r_long(data[4:8]), data[8:]
except AttributeError:
@@ -429,11 +448,9 @@
cannot be handled by the loader.
"""
- if self._bytecode_path:
- bytecode_path = self._bytecode_path
- else:
- base_path = _path_without_ext(self._source_path)
- bytecode_path = base_path + suffix_list(imp.PY_COMPILED)[0]
+ bytecode_path = self._bytecode_path()
+ if not bytecode_path:
+ bytecode_path = self._base_path + suffix_list(imp.PY_COMPILED)[0]
try:
with open(bytecode_path, 'wb') as bytecode_file:
bytecode_file.write(imp.get_magic())
@@ -468,7 +485,11 @@
specified module.
"""
- return self._handler(fullname, self._source_path, self._bytecode_path)[0]
+ try:
+ return self._handler(fullname, self._source_path(),
+ self._bytecode_path())[0]
+ except ValueError:
+ raise ImportError("cannot get the code for %s" % fullname)
class FileImporter(object):
Modified: sandbox/trunk/import_in_py/controlled_importlib.py
==============================================================================
--- sandbox/trunk/import_in_py/controlled_importlib.py (original)
+++ sandbox/trunk/import_in_py/controlled_importlib.py Thu Aug 23 02:03:06 2007
@@ -81,7 +81,7 @@
def __init__(self, *args, **kwargs):
"""Remove the bytecode path."""
super(PyOnlyFileLoader, self).__init__(*args, **kwargs)
- self._bytecode_path = None
+ self._bytecode_path = lambda: None
def write_bytecode(self, *args, **kwargs):
"""Do not write out any bytecode."""
Modified: sandbox/trunk/import_in_py/tests/test_fs_loader.py
==============================================================================
--- sandbox/trunk/import_in_py/tests/test_fs_loader.py (original)
+++ sandbox/trunk/import_in_py/tests/test_fs_loader.py Thu Aug 23 02:03:06 2007
@@ -132,6 +132,14 @@
found = loader.load_module(self.module_name)
self.verify_package(found, self.module_name)
+ def test_fails_with_no_files_post_init(self):
+ # The loader should fail gracefully if the files it would have used to
+ # load the module have been removed.
+ loader = importlib._PyFileLoader(self.module_name, self.py_path, False)
+ test_support.unlink(self.py_path)
+ test_support.unlink(self.pyc_path)
+ self.assertRaises(ImportError, loader.load_module, self.module_name)
+
def log_call(instance, method_name):
"""Log a method call."""
@@ -360,6 +368,8 @@
self.assertRaises(ImportError, loader.get_code, self.module_name)
# Nothing available.
os.unlink(self.pyc_path)
+ assert not os.path.exists(self.py_path)
+ assert not os.path.exists(self.pyc_path)
loader = importlib._PyFileLoader(self.module_name, self.py_path, False)
self.assertRaises(ImportError, loader.get_code, self.module_name)
More information about the Python-checkins
mailing list