[Python-checkins] r57319 - in sandbox/trunk/import_in_py: Py3K_TODO _importlib.py regrtest.sh tests/test_fs_loader.py

brett.cannon python-checkins at python.org
Thu Aug 23 16:37:20 CEST 2007


Author: brett.cannon
Date: Thu Aug 23 16:37:20 2007
New Revision: 57319

Modified:
   sandbox/trunk/import_in_py/Py3K_TODO
   sandbox/trunk/import_in_py/_importlib.py
   sandbox/trunk/import_in_py/regrtest.sh
   sandbox/trunk/import_in_py/tests/test_fs_loader.py
Log:
Add proper support for reloading of modules by not deleting the module if the
reload failed.  This led to exception handling during module initialization
being pushed into module_init.

test_import now passes.


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 16:37:20 2007
@@ -5,8 +5,6 @@
     * Be backwards-compatible.
         + Must pass 2.6 stdlib test suite using importlib.
             - Use regrtest.sh editing so all tests are run.
-            - test_import
-                * test_failing_reload
             - test_xmlrpc
                 * Passes in isolation.
     * Rewrite zipimport.

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 16:37:20 2007
@@ -271,17 +271,44 @@
 
 
 def init_module(loader, code_object, name, path, is_pkg):
-    """Return an initialized module."""
+    """Return an initialized module.
+
+    If initialization fails and the module did not already exist, then remove
+    it from sys.modules to prevent a partially initialized module from being
+    left around.  If this action is for a reload (i.e., the module already
+    existed), leave the original module state in place.
+
+    """
     module = sys.modules.get(name)
-    if module is None:
+    is_reload = True if module is not None else False
+    if not is_reload:
         module = imp.new_module(name)
         sys.modules[name] = module
+    else:
+        original_values = {}
+        modified_attrs = ['__loader__', '__name__', '__file__']
+        for attr in modified_attrs:
+            try:
+                original_values[attr] = getattr(module, attr)
+            except AttributeError:
+                pass
     module.__loader__ = loader
     module.__name__ = name
     module.__file__ = path
     if is_pkg:
         module.__path__  = [module.__file__.rsplit(path_sep, 1)[0]]
-    exec code_object in module.__dict__
+    try:
+        exec code_object in module.__dict__
+    except:
+        if not is_reload:
+            del sys.modules[name]
+        else:
+            for attr in modified_attrs:
+                if attr in original_values:
+                    setattr(module, attr, original_values[attr])
+                else:
+                    delattr(module, attr)
+        raise
     return module
 
 
@@ -392,13 +419,7 @@
                                                 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:
-            # Don't leave a partially initialized module in sys.modules.
-            if fullname in sys.modules:
-                del sys.modules[fullname]
-            raise
+        return self._module_init(code_object, fullname, path, self._is_pkg)
 
     @check_name
     def mod_time(self, name):

Modified: sandbox/trunk/import_in_py/regrtest.sh
==============================================================================
--- sandbox/trunk/import_in_py/regrtest.sh	(original)
+++ sandbox/trunk/import_in_py/regrtest.sh	Thu Aug 23 16:37:20 2007
@@ -2,5 +2,5 @@
 # 'verbose=1' argument outputs test runs.
 # 'tests' argument specifies tests to run.
 echo 'test_pkg failure known and is OK'
-$1 -c "import importlib; importlib._set__import__(); from test.regrtest import main; main(['test_import'])"
+$1 -c "import importlib; importlib._set__import__(); from test.regrtest import main; main()"
 echo 'test_pkg failure known and is OK'

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 16:37:20 2007
@@ -1,5 +1,6 @@
 import importlib
 
+from tests import mock_importlib
 from tests.ext_help import find_ext_location
 from tests.py_help import TestPyPycPackages
 
@@ -140,6 +141,24 @@
         test_support.unlink(self.pyc_path)
         self.assertRaises(ImportError, loader.load_module, self.module_name)
 
+    def test_reload_failure(self):
+        # If a module is reloaded and something happens during loading, the
+        # module should be left in place and not cleared out.
+        test_support.unlink(self.pyc_path)
+        with open(self.py_path, 'w') as source_file:
+            source_file.write('x = 42/0')
+        mock_module = mock_importlib.MockModule(self.module_name)
+        mock_module.__file__ = 'blah'
+        if hasattr(mock_module, '__loader__'):
+            delattr(mock_module, '__loader__')
+        sys.modules[self.module_name] = mock_module
+        loader = importlib._PyFileLoader(self.module_name, self.py_path, False)
+        self.assertRaises(ZeroDivisionError, loader.load_module,
+                            self.module_name)
+        self.assert_(self.module_name in sys.modules)
+        self.assertEquals(mock_module.__file__, 'blah')
+        self.assert_(not hasattr(mock_module, '__loader__'))
+
 
 def log_call(instance, method_name):
     """Log a method call."""


More information about the Python-checkins mailing list