[Python-checkins] r57267 - sandbox/trunk/import_in_py/_importlib.py sandbox/trunk/import_in_py/controlled_importlib.py

brett.cannon python-checkins at python.org
Tue Aug 21 23:09:22 CEST 2007


Author: brett.cannon
Date: Tue Aug 21 23:09:21 2007
New Revision: 57267

Modified:
   sandbox/trunk/import_in_py/_importlib.py
   sandbox/trunk/import_in_py/controlled_importlib.py
Log:
Reimplement get_code for the source loader so as to return the code object that
load_module would have used had it been called.

This led to handle_py becoming handle_code to make this situation much easier.
Also introduced init_module which takes the code object and relevant
information and initializes a module for the import.


Modified: sandbox/trunk/import_in_py/_importlib.py
==============================================================================
--- sandbox/trunk/import_in_py/_importlib.py	(original)
+++ sandbox/trunk/import_in_py/_importlib.py	Tue Aug 21 23:09:21 2007
@@ -266,21 +266,28 @@
             if suffix[2] == suffix_type]
 
 
-def handle_py(loader, name, source_path, bytecode_path, is_pkg):
-    """Handle the initialization of a module by Python source or bytecode."""
-    assert source_path or bytecode_path
-    source_timestamp = None
+def init_module(loader, code_object, name, path, is_pkg):
+    """Return an initialized module."""
     module = sys.modules.get(name)
     if module is None:
         module = imp.new_module(name)
         sys.modules[name] = module
-    # __file__, __path__, and __loader__ *must* be set on the module before
-    # any code is executed by the import.  __name__ is set by new_module.
     module.__loader__ = loader
-    # Just so that the attribute has some value to start with.
-    module.__file__ = source_path or bytecode_path
+    module.__name__ = name
+    module.__file__ = path
     if is_pkg:
         module.__path__  = [module.__file__.rsplit(path_sep, 1)[0]]
+    exec code_object in module.__dict__
+    return module
+
+
+def handle_code(loader, name, source_path, bytecode_path):
+    """Return the code object and the location of the code used to create the
+    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
+    source_timestamp = None
     # Try to use bytecode if it is available.
     if bytecode_path:
         magic, pyc_timestamp, bytecode = loader.get_bytecode(name)
@@ -297,9 +304,7 @@
                     raise ImportError("bytcode is stale")
             # Bytecode seems fine, so try to use it.
             try:
-                exec marshal.loads(bytecode) in module.__dict__
-                module.__file__ = bytecode_path
-                return module
+                return marshal.loads(bytecode), bytecode_path
             except ValueError:
                 # XXX Does this have to be true?
                 # Since bad bytecode halts the import entirely, having the
@@ -315,27 +320,28 @@
     # Use the source.
     source = loader.get_source(name)
     code_object = compile(source, source_path, 'exec')
-    exec code_object in module.__dict__
-    module.__file__ = source_path
     # Generate bytecode and write it out.
     if source_timestamp is None:  # May have from bytecode verification.
         source_timestamp = loader.mod_time(name)
     data = marshal.dumps(code_object)
     loader.write_bytecode(name, source_timestamp, data)
-    return module
+    return code_object, source_path
 
 
 class _PyFileLoader(object):
 
     """Load a Python source or bytecode file."""
 
-    _handler = handle_py
+    _handler = handle_code
+    _module_init = init_module
 
     # XXX Take in fullname from importer to make sure loader is not called for
     # another module?
     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):
@@ -359,17 +365,10 @@
     @check_name
     def load_module(self, fullname):
         """Load a Python source or bytecode file."""
-        if hasattr(self, '_source_path'):
-            source_path = self._source_path
-        else:
-            source_path = None
-        if hasattr(self, '_bytecode_path'):
-            bytecode_path = self._bytecode_path
-        else:
-            bytecode_path = None
+        code_object, path = self._handler(fullname, self._source_path,
+                                            self._bytecode_path)
         try:
-            return self._handler(fullname, source_path, bytecode_path,
-                                    self._is_pkg)
+            return self._module_init(code_object, fullname, path, self._is_pkg)
         except:
             # Don't leave a partially initialized module in sys.modules.
             if fullname in sys.modules:
@@ -384,10 +383,10 @@
         if the loader cannot handle the module.
 
         """
-        try:
+        if self._source_path:
             return int(_os.stat(self._source_path).st_mtime)
-        except AttributeError:
-            return ValueError('no source for %s' % name)
+        else:
+            raise ValueError('no source for %s' % name)
 
     @check_name
     def get_source(self, fullname):
@@ -397,14 +396,12 @@
         Raises ImportError if the loader cannot handle the module.
 
         """
-        try:
+        if self._source_path and _path_exists(self._source_path):
             return open(self._source_path, 'U').read()
-        except (IOError, AttributeError):
-            if (hasattr(self, '_bytecode_path') and
-                    _path_exists(self._bytecode_path)):
-                return None
-            else:
-                raise ImportError('no source or bytecode available')
+        elif self._bytecode_path and _path_exists(self._bytecode_path):
+            return None
+        else:
+            raise ImportError('no source or bytecode available')
 
     @check_name
     def get_bytecode(self, name):
@@ -432,9 +429,9 @@
         cannot be handled by the loader.
 
         """
-        try:
+        if self._bytecode_path:
             bytecode_path = self._bytecode_path
-        except AttributeError:
+        else:
             base_path = _path_without_ext(self._source_path)
             bytecode_path = base_path + suffix_list(imp.PY_COMPILED)[0]
         try:
@@ -471,14 +468,7 @@
         specified module.
         
         """
-        source = self.get_source(fullname)
-        if source is not None:
-            return compile(source, self._source_path, 'exec')
-        else:
-            magic, mtime, bytecode = self.get_bytecode(fullname)
-            if imp.get_magic() != magic:
-                raise ImportError('no source and bytecode bad')
-            return marshal.loads(bytecode)
+        return self._handler(fullname, self._source_path, self._bytecode_path)[0]
 
 
 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	Tue Aug 21 23:09:21 2007
@@ -81,10 +81,7 @@
     def __init__(self, *args, **kwargs):
         """Remove the bytecode path."""
         super(PyOnlyFileLoader, self).__init__(*args, **kwargs)
-        try:
-            del self._bytecode_path
-        except AttributeError:
-            pass
+        self._bytecode_path = None
 
     def write_bytecode(self, *args, **kwargs):
         """Do not write out any bytecode."""


More information about the Python-checkins mailing list