[Python-checkins] r51982 - in python/branches/theller_modulefinder/Lib: modulefinder.py test/test_modulefinder.py

thomas.heller python-checkins at python.org
Fri Sep 22 16:41:31 CEST 2006


Author: thomas.heller
Date: Fri Sep 22 16:41:30 2006
New Revision: 51982

Modified:
   python/branches/theller_modulefinder/Lib/modulefinder.py
   python/branches/theller_modulefinder/Lib/test/test_modulefinder.py
Log:
Partial progress with relative imports.
'from ...x import y' seems to work, 'from ... import z' does not.

Modified: python/branches/theller_modulefinder/Lib/modulefinder.py
==============================================================================
--- python/branches/theller_modulefinder/Lib/modulefinder.py	(original)
+++ python/branches/theller_modulefinder/Lib/modulefinder.py	Fri Sep 22 16:41:30 2006
@@ -122,10 +122,7 @@
 
     def import_hook(self, name, caller=None, fromlist=None, level=-1):
         self.msg(3, "import_hook", name, caller, fromlist, level)
-        if level == 0: # absolute import
-            parent = None
-        else:
-            parent = self.determine_parent(caller)
+        parent = self.determine_parent(caller, level=level)
         q, tail = self.find_head_package(parent, name)
         m = self.load_tail(q, tail)
         if not fromlist:
@@ -134,12 +131,21 @@
             self.ensure_fromlist(m, fromlist)
         return None
 
-    def determine_parent(self, caller):
-        self.msgin(4, "determine_parent", caller)
-        if not caller:
+    def determine_parent(self, caller, level=-1):
+        self.msgin(4, "determine_parent", caller, level)
+        if not caller or level == 0:
             self.msgout(4, "determine_parent -> None")
             return None
         pname = caller.__name__
+        if level >= 1:
+            if caller.__path__:
+                level -= 1
+            if pname.count(".") < level:
+                raise ImportError, "relative importpath too deep"
+            pname = ".".join(pname.split(".")[:-level])
+            parent = self.modules[pname]
+            self.msgout(4, "determine_parent ->", parent)
+            return parent
         if caller.__path__:
             parent = self.modules[pname]
             assert caller is parent
@@ -325,6 +331,7 @@
     def scan_opcodes(self, co,
                      unpack = struct.unpack):
         # Scan the code, and yield 'interesting' opcode combinations
+        # Version for Python 2.4 and older
         code = co.co_code
         names = co.co_names
         consts = co.co_consts
@@ -348,6 +355,7 @@
     def scan_opcodes_25(self, co,
                      unpack = struct.unpack):
         # Scan the code, and yield 'interesting' opcode combinations
+        # Python 2.5 version (has absolute and relative imports)
         code = co.co_code
         names = co.co_names
         consts = co.co_consts
@@ -418,7 +426,9 @@
                 self._safe_import_hook(name, m, fromlist, level=0)
                 # XXX code missing, see above
             elif what == "relative_import":
-                raise NotImplementedError("relative import not yet implemented")
+                level, fromlist, name = args
+                # XXX code missing, see above
+                self._safe_import_hook(name, m, fromlist, level=level)
             else:
                 # We don't expect anything else from the generator.
                 raise RuntimeError(what)

Modified: python/branches/theller_modulefinder/Lib/test/test_modulefinder.py
==============================================================================
--- python/branches/theller_modulefinder/Lib/test/test_modulefinder.py	(original)
+++ python/branches/theller_modulefinder/Lib/test/test_modulefinder.py	Fri Sep 22 16:41:30 2006
@@ -55,20 +55,20 @@
     "a.module",
     ["a", "a.module",
      "b", "b.x", "b.y", "b.z",
-     "__future__", "sys", "time"],
+     "__future__", "sys", "exceptions"],
     ["blahblah"],
     """\
 mymodule.py
 a/__init__.py
 a/module.py
                                 from __future__ import absolute_import
-                                import sys # this is a.sys
+                                import sys # sys
                                 import blahblah # fails
-                                import time # this is NOT a.time
-                                import b.x # this is NOT a.b.x
-                                from b import y
-                                from b.z import *
-a/time.py
+                                import exceptions # exceptions
+                                import b.x # b.x
+                                from b import y # b.y
+                                from b.z import * # b.z.*
+a/exceptions.py
 a/sys.py
                                 import mymodule
 a/b/__init__.py
@@ -85,33 +85,41 @@
 
 relative_import_test = [
     "a.module",
-    ["a", "a.module",
-     "b", "b.x", "b.y", "b.z",
-     "__future__", "sys", "time"],
-    ["blahblah"],
+    ["__future__",
+     "a", "a.module",
+     "a.b", "a.b.y", "a.b.z",
+     "a.b.c", "a.b.c.moduleC",
+     "a.b.c.d", "a.b.c.e",
+     "exceptions"],
+    [],
+# The 'from ... import name' constructs stil fail'
     """\
 mymodule.py
 a/__init__.py
+                                ##from . import sys # a.sys
 a/module.py
-                                from __future__ import absolute_import
-                                import sys # this is a.sys
-                                import blahblah # fails
-                                import time # this is NOT a.time
-                                from . import x # this is a.b.x
+                                from __future__ import absolute_import # __future__
+                                import exceptions # exceptions
+                                #from . import x # a.x
                                 from .b import y, z
-a/time.py
+                                #from . import sys # a.sys
+a/exceptions.py
 a/sys.py
-                                import mymodule
 a/b/__init__.py
+                                #from .c import moduleC
+                                from a.b.c import moduleC
 a/b/x.py
 a/b/y.py
 a/b/z.py
-b/__init__.py
-                                import z
-b/unused.py
-b/x.py
-b/y.py
-b/z.py
+a/b/c/__init__.py
+                                from ..c import e # a.b.c.e
+a/b/c/moduleC.py
+                                #
+                                #from .. import c
+                                #from .. import x # a.b.x
+                                from ..c import d # a.b.c.d
+a/b/c/d.py
+a/b/c/e.py
 """]
 
 def open_file(path):
@@ -129,13 +137,23 @@
             ofi = open_file(os.path.join(TEST_DIR, line.strip()))
 
 class ModuleFinderTest(unittest.TestCase):
-    def _do_test(self, info):
+    def _do_test(self, info, report=False):
         import_this, modules, missing, source = info
         create_package(source)
         try:
             mf = modulefinder.ModuleFinder(path=TEST_PATH)
             mf.import_hook(import_this)
-##            mf.report()
+            if report:
+                mf.report()
+
+                opath = sys.path[:]
+                sys.path = TEST_PATH
+                try:
+                    __import__(import_this)
+                except:
+                    import traceback; traceback.print_exc()
+                sys.path = opath
+
             modules = set(modules)
             found = set(mf.modules.keys())
             more = list(found - modules)
@@ -158,14 +176,7 @@
             self._do_test(absolute_import_test)
 
         def test_relative_imports(self):
-            import_this, modules, missing, source = relative_import_test
-            create_package(source)
-            try:
-                mf = modulefinder.ModuleFinder(path=TEST_PATH)
-                self.assertRaises(NotImplementedError,
-                                  lambda: mf.import_hook(import_this))
-            finally:
-                distutils.dir_util.remove_tree(TEST_DIR)
+            self._do_test(relative_import_test)
 
 def test_main():
     test_support.run_unittest(ModuleFinderTest)


More information about the Python-checkins mailing list