[Python-checkins] r61543 - in sandbox/trunk/2to3/lib2to3: fixes/fix_map.py fixes/util.py tests/test_util.py

david.wolever python-checkins at python.org
Tue Mar 18 20:24:06 CET 2008


Author: david.wolever
Date: Tue Mar 18 20:24:06 2008
New Revision: 61543

Modified:
   sandbox/trunk/2to3/lib2to3/fixes/fix_map.py
   sandbox/trunk/2to3/lib2to3/fixes/util.py
   sandbox/trunk/2to3/lib2to3/tests/test_util.py
Log:
Added a does_tree_import function to util, which determines wether or not a top-level import statement exists.



Modified: sandbox/trunk/2to3/lib2to3/fixes/fix_map.py
==============================================================================
--- sandbox/trunk/2to3/lib2to3/fixes/fix_map.py	(original)
+++ sandbox/trunk/2to3/lib2to3/fixes/fix_map.py	Tue Mar 18 20:24:06 2008
@@ -24,7 +24,7 @@
 from .. import patcomp
 from ..pgen2 import token
 from . import basefix
-from .util import Name, Call, ListComp, attr_chain, find_binding
+from .util import Name, Call, ListComp, attr_chain, does_tree_import
 from ..pygram import python_symbols as syms
 
 class FixMap(basefix.BaseFix):
@@ -63,21 +63,7 @@
     def has_future_map(self, node):
         if self._future_map_found is not None:
             return self._future_map_found
-
-        # Scamper up to the top level namespace
-        top = node
-        while top.type != syms.file_input:
-            assert top.parent, "Tree is insane! root found before "\
-                               "file_input node was found."
-            top = top.parent
-        top=top.children[0]
-
-        self._future_map_found = False
-
-        binding = find_binding('map', top, 'future_builtins')
-
-        self._future_map_found = bool(binding)
-
+        self._future_map_found = does_tree_import('future_builtins', 'map', node)
         return self._future_map_found
 
     def transform(self, node, results):

Modified: sandbox/trunk/2to3/lib2to3/fixes/util.py
==============================================================================
--- sandbox/trunk/2to3/lib2to3/fixes/util.py	(original)
+++ sandbox/trunk/2to3/lib2to3/fixes/util.py	Tue Mar 18 20:24:06 2008
@@ -193,23 +193,26 @@
     suite.parent = parent
     return suite
 
+def does_tree_import(package, name, node):
+    """ Returns true if name is imported from package at the
+        top level of the tree which node belongs to.
+        To cover the case of an import like 'import foo', use
+        Null for the package and 'foo' for the name. """
+    # Scamper up to the top level namespace
+    while node.type != syms.file_input:
+        assert node.parent, "Tree is insane! root found before "\
+                           "file_input node was found."
+        node = node.parent
+
+    binding = find_binding(name, node, package)
+    return bool(binding)
+
 _def_syms = set([syms.classdef, syms.funcdef])
 def find_binding(name, node, package=None):
     """ Returns the node which binds variable name, otherwise None.
         If optional argument package is supplied, only imports will
         be returned.
-        >>> for args in (('map', 'map = 3'),
-                         ('map', 'from foo import map'),
-                         ('map', 'from foo import map', 'foo'),
-                         ('map', 'from bar import map', 'foo'),
-                         ('map', 'map = 3', 'foo')):
-                print bool(find_binding(*args))
-        True
-        True
-        True
-        False
-        False
-        >>> """
+        See test cases for examples."""
     for child in node.children:
         ret = None
         if child.type == syms.for_stmt:
@@ -233,17 +236,18 @@
         elif child.type in _def_syms and child.children[1].value == name:
             ret = child
         elif _is_import_binding(child, name, package):
-            return child
+            ret = child
         elif child.type == syms.simple_stmt:
             ret = find_binding(name, child, package)
         elif child.type == syms.expr_stmt:
                 if _find(name, child.children[0]):
                     ret = child
 
-        if not package and ret:
-            # Because the _is_import_binding returns directly, we don't want
-            # to return here if a package is defined.
-            return ret
+        if ret:
+            if not package:
+                return ret
+            if ret.type in (syms.import_name, syms.import_from):
+                return ret
     return None
 
 _block_syms = set([syms.funcdef, syms.classdef, syms.trailer])
@@ -260,20 +264,9 @@
 def _is_import_binding(node, name, package=None):
     """ Will reuturn node if node will import name, or node
         will import * from package.  None is returned otherwise.
-        >>> for n in ('from datetime import date',
-                      'from datetime import *',
-                      'import date',
-                      'from spam import date'):
-                print bool(_is_import_binding(n, 'date', 'datetime'))
-        True
-        True
-        True
-        False
-        >>> bool(_is_import_binding('from spam import date', 'date')
-        True
-        >>> """
+        See test cases for examples. """
 
-    if node.type == syms.import_name:
+    if node.type == syms.import_name and not package:
         imp = node.children[1]
         if imp.type == syms.dotted_as_names:
             for child in imp.children:
@@ -289,10 +282,15 @@
         elif imp.type == token.NAME and imp.value == name:
             return node
     elif node.type == syms.import_from:
-        if package and node.children[1].value != package:
+        # unicode(...) is used to make life easier here, because
+        # from a.b import parses to ['import', ['a', '.', 'b'], ...]
+        if package and unicode(node.children[1]).strip() != package:
             return None
         n = node.children[3]
-        if n.type == syms.import_as_names and _find(name, n):
+        if package and _find('as', n):
+            # See test_from_import_as for explanation
+            return None
+        elif n.type == syms.import_as_names and _find(name, n):
             return node
         elif n.type == syms.import_as_name:
             child = n.children[2]

Modified: sandbox/trunk/2to3/lib2to3/tests/test_util.py
==============================================================================
--- sandbox/trunk/2to3/lib2to3/tests/test_util.py	(original)
+++ sandbox/trunk/2to3/lib2to3/tests/test_util.py	Tue Mar 18 20:24:06 2008
@@ -84,9 +84,53 @@
         self.assertStr(Name("a", prefix="b"), "ba")
 
 
+class Test_does_tree_import(support.TestCase):
+    def _find_bind_rec(self, name, node):
+        # Search a tree for a binding -- used to find the starting
+        # point for these tests.
+        c = util.find_binding(name, node)
+        if c: return c
+        for child in node.children:
+            c = self._find_bind_rec(name, child)
+            if c: return c
+
+    def does_tree_import(self, package, name, string):
+        node = parse(string)
+        # Find the binding of start -- that's what we'll go from
+        node = self._find_bind_rec('start', node)
+        return util.does_tree_import(package, name, node)
+
+    def try_with(self, string):
+        failing_tests = (("a", "a", "from a import b"),
+                         ("a.d", "a", "from a.d import b"),
+                         ("d.a", "a", "from d.a import b"),
+                         (None, "a", "import b"),
+                         (None, "a", "import b, c, d"))
+        for package, name, import_ in failing_tests:
+            n = self.does_tree_import(package, name, import_ + "\n" + string)
+            self.failIf(n)
+            n = self.does_tree_import(package, name, string + "\n" + import_)
+            self.failIf(n)
+
+        passing_tests = (("a", "a", "from a import a"),
+                         ("x", "a", "from x import a"),
+                         ("x", "a", "from x import b, c, a, d"),
+                         ("x.b", "a", "from x.b import a"),
+                         ("x.b", "a", "from x.b import b, c, a, d"),
+                         (None, "a", "import a"),
+                         (None, "a", "import b, c, a, d"))
+        for package, name, import_ in passing_tests:
+            n = self.does_tree_import(package, name, import_ + "\n" + string)
+            self.failUnless(n)
+            n = self.does_tree_import(package, name, string + "\n" + import_)
+            self.failUnless(n)
+
+    def test_in_function(self):
+        self.try_with("def foo():\n\tbar.baz()\n\tstart=3")
+
 class Test_find_binding(support.TestCase):
-    def find_binding(self, name, string):
-        return util.find_binding(name, parse(string))
+    def find_binding(self, name, string, package=None):
+        return util.find_binding(name, parse(string), package)
 
     def test_simple_assignment(self):
         self.failUnless(self.find_binding("a", "a = b"))
@@ -149,6 +193,42 @@
         self.failIf(self.find_binding("a", "from a.d import b as t"))
         self.failIf(self.find_binding("a", "from d.a import b as t"))
 
+    def test_simple_import_with_package(self):
+        self.failUnless(self.find_binding("b", "import b"))
+        self.failUnless(self.find_binding("b", "import b, c, d"))
+        self.failIf(self.find_binding("b", "import b", "b"))
+        self.failIf(self.find_binding("b", "import b, c, d", "c"))
+
+    def test_from_import_with_package(self):
+        self.failUnless(self.find_binding("a", "from x import a", "x"))
+        self.failUnless(self.find_binding("a", "from a import a", "a"))
+        self.failUnless(self.find_binding("a", "from x import *", "x"))
+        self.failUnless(self.find_binding("a", "from x import b, c, a, d", "x"))
+        self.failUnless(self.find_binding("a", "from x.b import a", "x.b"))
+        self.failUnless(self.find_binding("a", "from x.b import *", "x.b"))
+        self.failUnless(self.find_binding("a", "from x.b import b, c, a, d", "x.b"))
+        self.failIf(self.find_binding("a", "from a import b", "a"))
+        self.failIf(self.find_binding("a", "from a.d import b", "a.d"))
+        self.failIf(self.find_binding("a", "from d.a import b", "a.d"))
+        self.failIf(self.find_binding("a", "from x.y import *", "a.b"))
+
+    def test_import_as_with_package(self):
+        self.failIf(self.find_binding("a", "import b.c as a", "b.c"))
+        self.failIf(self.find_binding("a", "import a as f", "f"))
+        self.failIf(self.find_binding("a", "import a as f", "a"))
+
+    def test_from_import_as_with_package(self):
+        # Because it would take a lot of special-case code in the fixers
+        # to deal with from foo import bar as baz, we'll simply always
+        # fail if there is an "from ... import ... as ..."
+        self.failIf(self.find_binding("a", "from x import b as a", "x"))
+        self.failIf(self.find_binding("a", "from x import g as a, d as b", "x"))
+        self.failIf(self.find_binding("a", "from x.b import t as a", "x.b"))
+        self.failIf(self.find_binding("a", "from x.b import g as a, d", "x.b"))
+        self.failIf(self.find_binding("a", "from a import b as t", "a"))
+        self.failIf(self.find_binding("a", "from a import b as t", "b"))
+        self.failIf(self.find_binding("a", "from a import b as t", "t"))
+
     def test_function_def(self):
         self.failUnless(self.find_binding("a", "def a(): pass"))
         self.failUnless(self.find_binding("a", "def a(b, c, d): pass"))


More information about the Python-checkins mailing list