[Python-checkins] r52771 - sandbox/trunk/import_in_py/importer.py sandbox/trunk/import_in_py/test_importer.py

brett.cannon python-checkins at python.org
Fri Nov 17 00:39:32 CET 2006


Author: brett.cannon
Date: Fri Nov 17 00:39:31 2006
New Revision: 52771

Modified:
   sandbox/trunk/import_in_py/importer.py
   sandbox/trunk/import_in_py/test_importer.py
Log:
Handle redirection entries (i.e., entries in sys.modules with a value of None).


Modified: sandbox/trunk/import_in_py/importer.py
==============================================================================
--- sandbox/trunk/import_in_py/importer.py	(original)
+++ sandbox/trunk/import_in_py/importer.py	Fri Nov 17 00:39:31 2006
@@ -44,11 +44,6 @@
     + Bytecode handles pulling every attribute off of module.
     + Do need to make sure all entries in __all__ are an attribute of the
       module, though.
-* Modules in sys.modules with a value of None are for redirection to a
-  top-level module that was imported in a submodule [pacakge essay].
-    + If classic relative import fails but absolute import succeeds, create
-      redirection entry in sys.modules for resolved relative name.
-    + If both imports fail then no need to create redirection entry.
 
 Bytecode
 --------
@@ -766,17 +761,25 @@
             # Handle the classic style of import: relative first, then
             # absolute.
             if level == -1:
-                imported_name = self.classic_resolve_name(name, caller_name,
+                relative_name = self.classic_resolve_name(name, caller_name,
                                                             is_pkg)
+                imported_name = relative_name
                 try:
-                    # Try a relative import first.
+                    # Check that a redirection entry does not already exist for
+                    # the relative import name.
+                    if (relative_name in sys.modules and
+                            sys.modules[relative_name] is None):
+                        raise ImportError("import redirection")
+                    # Try a relative import.
                     self.import_full_module(imported_name)
-                    # XXX Probably need to do something about values of None
-                    # being in sys.modules here.
                 except ImportError:
-                    # If the relative import fails, try an absolute import.
+                    # If the relative import fails (or is redirected), try an
+                    # absolute import.
                     imported_name = name
                     self.import_full_module(name)
+                    # Redirection entry for resolved relative name to instead
+                    # redirect to the absolute import.
+                    sys.modules[relative_name] = None
             # If using absolute imports with a relative path, only attempt with
             # the fully-resolved module name.
             else:

Modified: sandbox/trunk/import_in_py/test_importer.py
==============================================================================
--- sandbox/trunk/import_in_py/test_importer.py	(original)
+++ sandbox/trunk/import_in_py/test_importer.py	Fri Nov 17 00:39:31 2006
@@ -866,6 +866,31 @@
         # ImportError.
         self.failUnlessRaises(ImportError, self.importer.resolve_name,
                                 self.child_name, self.parent_name, False, 1)
+
+    def test_relative_import_redirection(self):
+        # Having a relative module name resolve to a name that has a value of
+        # None in sys.modules should redirect to import an absolute import for
+        # the specified name.
+        module_name = '<to import>'
+        pkg_name = '<pkg>'
+        resolved_relative_name = module_name + '.' + pkg_name
+        expected_module = mock_importer.MockModule(module_name)
+        sys.modules[resolved_relative_name] = None
+        sys.modules[module_name] = expected_module
+        importing_globals = {'__name__':pkg_name, '__path__':['some path']}
+        imported = self.importer(module_name, importing_globals, level=-1)
+        self.failUnless(imported is expected_module)
+
+    def test_None_not_set_for_import_failure(self):
+        # If an import that is tried both relative and absolute fails there
+        # should be an entry of None for the resolved relative name.
+        module_name = '<should fail>'
+        pkg_name = '<non-existent package>'
+        resolved_name = module_name + '.' + pkg_name
+        importing_globals = {'__name__':pkg_name, '__path__':['path']}
+        self.failUnlessRaises(ImportError, self.importer, module_name,
+                                importing_globals, {}, [], -1)
+        self.failUnless(resolved_name not in sys.modules)
           
 class ImportMetaPathTests(ImportHelper):
     
@@ -1155,12 +1180,15 @@
     def test_absolute_name_in_classic_relative_context(self):
         # Importing a module that happens to be ambiguous in terms of being
         # relative or absolute, but only exists in an absolute name context,
-        # should work.
+        # should work.  It should also lead to a value for None in sys.modules
+        # for the resolved relative name.
         package_module_globals = {'__name__':self.pkg_module_name}
         module = self.import_(self.top_level_module_name,
                                 package_module_globals, level=-1)
+        resolved_name = self.pkg_name + '.' + self.top_level_module_name
         self.verify_package(module)
         self.failUnlessEqual(module.__name__, self.top_level_module_name)
+        self.failUnless(sys.modules[resolved_name] is None)
 
     def test_relative_import_in_package_init(self):
         # Importing a module with a relative name in a package's __init__ file


More information about the Python-checkins mailing list