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

brett.cannon python-checkins at python.org
Thu Dec 7 22:32:33 CET 2006


Author: brett.cannon
Date: Thu Dec  7 22:32:32 2006
New Revision: 52960

Modified:
   sandbox/trunk/import_in_py/importer.py
   sandbox/trunk/import_in_py/test_importer.py
Log:
Add proper support for ``from . import ...``.  Required tweaking allowing the
empty string for a module name and relative name resolution.

Also beefed up tests for absolute import support when doing a relative name.


Modified: sandbox/trunk/import_in_py/importer.py
==============================================================================
--- sandbox/trunk/import_in_py/importer.py	(original)
+++ sandbox/trunk/import_in_py/importer.py	Thu Dec  7 22:32:32 2006
@@ -713,14 +713,24 @@
     def resolve_name(self, name, caller_name, caller_is_package, level):
         """Return the absolute name of the module specified by 'name' based on
         where the module is being imported and the requested change in dotted
-        name level."""
+        name level.
+        
+        Absolute imports always take the form of ``from <name> import ...``.
+        This means that the number of leading dots in '<name>' becomes 'level'
+        and the rest of '<name>' becomes 'name'.  This leads to the possibility
+        that 'name' is the empty string, representing the current package.
+        
+        """
         if caller_is_package:
             level -= 1
         if caller_name.count('.') < level:
             raise ImportError("attempted relative import beyond top-level "
                                 "pacakge")
         base_name = caller_name.rsplit('.', level)[0]
-        return base_name + '.' + name
+        if name:
+            return base_name + '.' + name
+        else:
+            return base_name
         
     def return_module(self, absolute_name, relative_name, fromlist):
         """Return the proper module based on what module was requested (and its
@@ -810,8 +820,7 @@
         (e.g. has a value of 2 for ``from .. import foo``).
 
         """
-        if not name:
-            #print repr(name), globals['__name__'], fromlist, level
+        if not name and level < 1:
             raise ValueError("Empty module name")
         is_pkg = True if '__path__' in globals else False
         caller_name = globals.get('__name__')
@@ -846,7 +855,7 @@
             else:
                 imported_name = name
                 self.import_full_module(name)
-            relative_name = '' if imported_name != name else name
-            return self.return_module(imported_name, name, fromlist)
+            relative_name = '' if imported_name == name else name
+            return self.return_module(imported_name, relative_name, fromlist)
         finally:
             imp.release_lock()

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	Thu Dec  7 22:32:32 2006
@@ -785,16 +785,18 @@
                                                                 False)
         self.failUnlessEqual(resolved_name, self.full_child_name)
 
-    def test_relative_import_in_package(self):
+    def test_relative_import_in_package_for_a_module(self):
         # Trying to import a single level within a package within it's __init__
         # module should stay within the package.
+        # ``from .child_name import ...`` in a package.
         resolved_name = self.importer.resolve_name(self.child_name,
                                                     self.parent_name, True, 1)
         self.failUnlessEqual(resolved_name, self.full_child_name)
 
-    def test_relative_import_in_module(self):
+    def test_relative_import_in_module_for_a_module(self):
         # Importing from within a module in a package should try to import from
         # within the same directory as the module requesting the import.
+        # ``from .child_name import ...`` in a package module.
         calling_from = self.parent_name + '.' + '<calling from>'
         resolved_name = self.importer.resolve_name(self.child_name,
                                                     calling_from, False, 1)
@@ -812,12 +814,14 @@
     def test_attempt_to_escape_out_of_package_init(self):
         # Attempting to go too high out of a package in its __init__ file
         # should raise ImportError.
+        # ``from ..child_name import ...`` in a top-level package.
         self.failUnlessRaises(ImportError, self.importer.resolve_name,
                 self.child_name, self.parent_name, True, 2)
 
     def test_attempt_to_escape_out_of_package_module(self):
         # Attempting to go too high in the package from a module should raise
         # ImportError.
+        # ``from ..child_name import ...`` in a top-level package module.
         calling_from = self.parent_name + '.' + '<calling from>'
         self.failUnlessRaises(ImportError, self.importer.resolve_name,
                                 self.child_name, calling_from, False, 2)
@@ -825,8 +829,21 @@
     def test_relative_import_in_top_level(self):
         # Attempting a relative import in a top-level location should raise
         # ImportError.
+        # ``from .child_name import ...`` outside of a package.
         self.failUnlessRaises(ImportError, self.importer.resolve_name,
                                 self.child_name, self.parent_name, False, 1)
+                                
+    def test_relative_import_in_package_init(self):
+        # ``from . import ...`` in a package.
+        resolved_name = self.importer.resolve_name('', self.parent_name, True,
+                                                    1)
+        self.failUnlessEqual(resolved_name, self.parent_name)
+        
+    def test_relative_import_in_package_module(self):
+        # ``from . import ...`` in a package module.
+        resolved_name = self.importer.resolve_name('', self.full_child_name,
+                                                    False, 1)
+        self.failUnlessEqual(resolved_name, self.parent_name)
 
     def test_relative_import_redirection(self):
         # Having a relative module name resolve to a name that has a value of
@@ -1345,18 +1362,37 @@
     def test_relative_import_in_package_init(self):
         # Importing a module with a relative name in a package's __init__ file
         # should work.
-        # XXX
-        package_globals = {'__name__':self.pkg_name, '__path__':self.pkg_path}
-        module = self.import_(self.module_name, package_globals, level=1)
-        self.verify_package(module, self.pkg_module_name)
+        # ``from . import module`` for 'package'.
+        caller_globals = {'__name__':self.pkg_name, '__path__':[self.pkg_path]}
+        module = self.import_('', caller_globals, fromlist=[self.module_name],
+                                level=1)
+        self.verify_package(module, self.pkg_name)
 
     def test_relative_import_in_package(self):
         # Importing a module with a relative name in another module should
         # work.
+        # ``from . import module`` for 'package.module'.
+        caller_globals = {'__name__':self.pkg_module_name}
+        module = self.import_('', caller_globals, fromlist=[self.module_name],
+                                level=1)
+        self.verify_package(module, self.pkg_name)
+        
+    def test_relative_import_in_subpackages(self):
+        # ``from .. import module`` in 'package.subpackage'.
+        caller_globals = {'__name__':self.sub_pkg_name,
+                            '__path__':[self.sub_pkg_path]}
+        module = self.import_('', caller_globals, fromlist=[self.module_name],
+                                level=2)
+        self.verify_package(module, self.pkg_name)
+        
+    def test_relative_import_of_package(self):
+        # ``from ..subpackage import module`` in 'package.subpackage'.
         # XXX
-        module_globals = {'__name__':self.pkg_name + '.another_module'}
-        module = self.import_(self.module_name, module_globals, level=1)
-        self.verify_package(module, self.pkg_module_name)
+        caller_globals = {'__name__':self.sub_pkg_name,
+                            '__path__':[self.sub_pkg_path]}
+        module = self.import_(self.sub_pkg_tail_name, caller_globals,
+                                fromlist=[self.module_name], level=2)
+        self.verify_package(module, self.sub_pkg_name)
         
     def test_relative_import_return(self):
         # When importing from a relative name, the module up to the first dot


More information about the Python-checkins mailing list