[Python-checkins] r56146 - in sandbox/trunk/2to3: example.py fixes/fix_filter.py fixes/fix_map.py fixes/util.py tests/test_fixers.py

guido.van.rossum python-checkins at python.org
Mon Jul 2 15:20:43 CEST 2007


Author: guido.van.rossum
Date: Mon Jul  2 15:20:43 2007
New Revision: 56146

Added:
   sandbox/trunk/2to3/fixes/fix_filter.py   (contents, props changed)
   sandbox/trunk/2to3/fixes/fix_map.py   (contents, props changed)
Modified:
   sandbox/trunk/2to3/example.py
   sandbox/trunk/2to3/fixes/util.py
   sandbox/trunk/2to3/tests/test_fixers.py
Log:
Add fixers for map and filter.  Not perfect, but a start.


Modified: sandbox/trunk/2to3/example.py
==============================================================================
--- sandbox/trunk/2to3/example.py	(original)
+++ sandbox/trunk/2to3/example.py	Mon Jul  2 15:20:43 2007
@@ -344,4 +344,17 @@
     a = raw_input()
     b = raw_input(a.rstrip())
 
+def filter_examples():
+    filter(os.unlink, filenames)
+    filter(None, "whatever")
+    filter(lambda x: not x, range(4))
+
+def map_examples():
+    map(None, foo.bar)
+    map(None, foo.bar,)
+    map(None, foo, bar)
+    map(f, foo.bar)
+    map(lambda x: x+1, range(10))
+    
+
 # This is the last line.

Added: sandbox/trunk/2to3/fixes/fix_filter.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/2to3/fixes/fix_filter.py	Mon Jul  2 15:20:43 2007
@@ -0,0 +1,107 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Fixer that changes filter(F, X) into list(filter(F, X)).
+
+We avoid the transformation if the filter() call is directly contained
+in iter(<>), list(<>), tuple(<>), sorted(<>), ...join(<>), or
+for V in <>:.
+
+NOTE: This is still not correct if the original code was depending on
+filter(F, X) to return a string if X is a string and a tuple if X is a
+tuple.  That would require type inference, which we don't do.  Let
+Python 2.6 figure it out.
+"""
+
+# Local imports
+import pytree
+import patcomp
+from pgen2 import token
+from fixes import basefix
+from fixes.util import Name, Call, ListComp
+
+class FixFilter(basefix.BaseFix):
+
+    PATTERN = """
+    filter_lambda=power<
+        'filter'
+        trailer<
+            '('
+            arglist<
+                lambdef< 'lambda' fp=NAME ':' xp=any >
+                ','
+                it=any
+            >
+            ')'
+        >
+    >
+    |
+    power<
+        'filter'
+        args=trailer< '(' [any] ')' >
+    >
+    """
+
+    def transform(self, node):
+        results = self.match(node)
+        if "filter_lambda" in results:
+            new = ListComp(results.get("fp").clone(),
+                           results.get("fp").clone(),
+                           results.get("it").clone(),
+                           results.get("xp").clone())
+        else:
+            if self.in_special_context(node):
+                return None
+            new = node.clone()
+            new.set_prefix("")
+            new = Call(Name("list"), [new])
+        new.set_prefix(node.get_prefix())
+        return new
+
+    P0 = """for_stmt< 'for' any 'in' node=any ':' any* >
+            | list_for< 'for' any 'in' node=any any* >
+            | gen_for< 'for' any 'in' node=any any* >
+         """
+    p0 = patcomp.PatternCompiler().compile_pattern(P0)
+
+    P1 = """
+    power<
+        NAME< 'iter' | 'list' | 'tuple' | 'sorted' >
+        trailer< '(' node=any ')' >
+        any*
+    >
+    """
+    p1 = patcomp.PatternCompiler().compile_pattern(P1)
+
+    P2 = """
+    power<
+        'sorted'
+        trailer< '(' arglist<node=any any*> ')' >
+        any*
+    >
+    """
+    p2 = patcomp.PatternCompiler().compile_pattern(P2)
+
+    def in_special_context(self, node):
+        p = node.parent
+        if p is None:
+            return False
+        results = {}
+        if self.p0.match(p, results) and results["node"] is node:
+            return True
+
+        pp = p.parent
+        if pp is None:
+            return False
+        results = {}
+        if self.p1.match(pp, results) and results["node"] is node:
+            return True
+
+        ppp = pp.parent
+        if ppp is None:
+            return False
+        results = {}
+        if self.p2.match(ppp, results) and results["node"] is node:
+            return True
+        
+        return False

Added: sandbox/trunk/2to3/fixes/fix_map.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/2to3/fixes/fix_map.py	Mon Jul  2 15:20:43 2007
@@ -0,0 +1,119 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Fixer that changes map(F, ...) into list(map(F, ...)).
+
+As a special case, map(None, X) is changed into list(X).  (This is
+necessary because the semantics are changed in this case -- the new
+map(None, X) is equivalent to [(x,) for x in X].)
+
+We avoid the transformation (except for the special case mentioned
+above) if the map() call is directly contained in iter(<>), list(<>),
+tuple(<>), sorted(<>), ...join(<>), or for V in <>:.
+
+NOTE: This is still not correct if the original code was depending on
+map(F, X, Y, ...) to go on until the longest argument is exhausted,
+substituting None for missing values -- like zip(), it now stops as
+soon as the shortest argument is exhausted.
+"""
+
+# Local imports
+import pytree
+import patcomp
+from pgen2 import token
+from fixes import basefix
+from fixes.util import Name, Call, ListComp
+from pygram import python_symbols as syms
+
+class FixMap(basefix.BaseFix):
+
+    PATTERN = """
+    map_none=power<
+        'map'
+        trailer< '(' arglist< 'None' ',' arg=any [','] > ')' >
+    >
+    |
+    map_lambda=power<
+        'map'
+        trailer<
+            '('
+            arglist<
+                lambdef< 'lambda' fp=NAME ':' xp=any >
+                ','
+                it=any
+            >
+            ')'
+        >
+    >
+    |
+    power<
+        'map'
+        args=trailer< '(' [any] ')' >
+    >
+    """
+
+    def transform(self, node):
+        results = self.match(node)
+        if "map_lambda" in results:
+            new = ListComp(results.get("xp").clone(),
+                           results.get("fp").clone(),
+                           results.get("it").clone())
+        else:
+            if "map_none" in results:
+                new = results["arg"].clone()
+            else:
+                if self.in_special_context(node):
+                    return None
+                new = node.clone()
+            new.set_prefix("")
+            new = Call(Name("list"), [new])
+        new.set_prefix(node.get_prefix())
+        return new
+
+    P0 = """for_stmt< 'for' any 'in' node=any ':' any* >
+            | list_for< 'for' any 'in' node=any any* >
+            | gen_for< 'for' any 'in' node=any any* >
+         """
+    p0 = patcomp.PatternCompiler().compile_pattern(P0)
+
+    P1 = """
+    power<
+        NAME< 'iter' | 'list' | 'tuple' | 'sorted' >
+        trailer< '(' node=any ')' >
+        any*
+    >
+    """
+    p1 = patcomp.PatternCompiler().compile_pattern(P1)
+
+    P2 = """
+    power<
+        'sorted'
+        trailer< '(' arglist<node=any any*> ')' >
+        any*
+    >
+    """
+    p2 = patcomp.PatternCompiler().compile_pattern(P2)
+
+    def in_special_context(self, node):
+        p = node.parent
+        if p is None:
+            return False
+        results = {}
+        if self.p0.match(p, results) and results["node"] is node:
+            return True
+
+        pp = p.parent
+        if pp is None:
+            return False
+        results = {}
+        if self.p1.match(pp, results) and results["node"] is node:
+            return True
+
+        ppp = pp.parent
+        if ppp is None:
+            return False
+        results = {}
+        if self.p2.match(ppp, results) and results["node"] is node:
+            return True
+        
+        return False

Modified: sandbox/trunk/2to3/fixes/util.py
==============================================================================
--- sandbox/trunk/2to3/fixes/util.py	(original)
+++ sandbox/trunk/2to3/fixes/util.py	Mon Jul  2 15:20:43 2007
@@ -76,6 +76,30 @@
     """A string leaf"""
     return Leaf(token.STRING, string, prefix=prefix)
 
+def ListComp(xp, fp, it, test=None):
+    """A list comprehension of the form [xp for fp in it if test].
+
+    If test is None, the "if test" part is omitted.
+    """
+    xp.set_prefix("")
+    fp.set_prefix(" ")
+    it.set_prefix(" ")
+    for_leaf = Leaf(token.NAME, "for")
+    for_leaf.set_prefix(" ")
+    in_leaf = Leaf(token.NAME, "in")
+    in_leaf.set_prefix(" ")
+    inner_args = [for_leaf, fp, in_leaf, it]
+    if test:
+        test.set_prefix(" ")
+        if_leaf = Leaf(token.NAME, "if")
+        if_leaf.set_prefix(" ")
+        inner_args.append(Node(syms.list_if, [if_leaf, test]))
+    inner = Node(syms.listmaker, [xp, Node(syms.list_for, inner_args)])
+    return Node(syms.atom,
+                       [Leaf(token.LBRACE, "["),
+                        inner,
+                        Leaf(token.RBRACE, "]")])
+    
 ###########################################################
 ### Determine whether a node represents a given literal
 ###########################################################

Modified: sandbox/trunk/2to3/tests/test_fixers.py
==============================================================================
--- sandbox/trunk/2to3/tests/test_fixers.py	(original)
+++ sandbox/trunk/2to3/tests/test_fixers.py	Mon Jul  2 15:20:43 2007
@@ -1858,6 +1858,100 @@
         a = """callable(x, kw=y)"""
         self.check(a, a)
 
+class Test_filter(FixerTestCase):
+    fixer = "filter"
+
+    def test_filter_basic(self):
+        b = """x = filter(None, 'abc')"""
+        a = """x = list(filter(None, 'abc'))"""
+        self.check(b, a)
+
+        b = """x = filter(f, 'abc')"""
+        a = """x = list(filter(f, 'abc'))"""
+        self.check(b, a)
+
+        b = """x = filter(lambda x: x%2 == 0, range(10))"""
+        a = """x = [x for x in range(10) if x%2 == 0]"""
+        self.check(b, a)
+
+        # XXX This (rare) case is not supported
+##         b = """x = filter(f, 'abc')[0]"""
+##         a = """x = list(filter(f, 'abc'))[0]"""
+##         self.check(b, a)
+
+    def test_filter_nochange(self):
+        a = """iter(filter(f, 'abc'))"""
+        self.check(a, a)
+        a = """list(filter(f, 'abc'))"""
+        self.check(a, a)
+        a = """list(filter(f, 'abc'))[0]"""
+        self.check(a, a)
+        a = """tuple(filter(f, 'abc'))"""
+        self.check(a, a)
+        a = """sorted(filter(f, 'abc'))"""
+        self.check(a, a)
+        a = """sorted(filter(f, 'abc'), key=blah)"""
+        self.check(a, a)
+        a = """sorted(filter(f, 'abc'), key=blah)[0]"""
+        self.check(a, a)
+        a = """for i in filter(f, 'abc'): pass"""
+        self.check(a, a)
+        a = """[x for x in filter(f, 'abc')]"""
+        self.check(a, a)
+        a = """(x for x in filter(f, 'abc'))"""
+        self.check(a, a)
+
+class Test_map(FixerTestCase):
+    fixer = "map"
+
+    def test_map_basic(self):
+        b = """x = map(f, 'abc')"""
+        a = """x = list(map(f, 'abc'))"""
+        self.check(b, a)
+
+        b = """x = map(f, 'abc', 'def')"""
+        a = """x = list(map(f, 'abc', 'def'))"""
+        self.check(b, a)
+
+        b = """x = map(None, 'abc')"""
+        a = """x = list('abc')"""
+        self.check(b, a)
+
+        b = """x = map(None, 'abc', 'def')"""
+        a = """x = list(map(None, 'abc', 'def'))"""
+        self.check(b, a)
+
+        b = """x = map(lambda x: x+1, range(4))"""
+        a = """x = [x+1 for x in range(4)]"""
+        self.check(b, a)
+
+        # XXX This (rare) case is not supported
+##         b = """x = map(f, 'abc')[0]"""
+##         a = """x = list(map(f, 'abc'))[0]"""
+##         self.check(b, a)
+
+    def test_map_nochange(self):
+        a = """iter(map(f, 'abc'))"""
+        self.check(a, a)
+        a = """list(map(f, 'abc'))"""
+        self.check(a, a)
+        a = """list(map(f, 'abc'))[0]"""
+        self.check(a, a)
+        a = """tuple(map(f, 'abc'))"""
+        self.check(a, a)
+        a = """sorted(map(f, 'abc'))"""
+        self.check(a, a)
+        a = """sorted(map(f, 'abc'), key=blah)"""
+        self.check(a, a)
+        a = """sorted(map(f, 'abc'), key=blah)[0]"""
+        self.check(a, a)
+        a = """for i in map(f, 'abc'): pass"""
+        self.check(a, a)
+        a = """[x for x in map(f, 'abc')]"""
+        self.check(a, a)
+        a = """(x for x in map(f, 'abc'))"""
+        self.check(a, a)
+
 
 if __name__ == "__main__":
     import __main__


More information about the Python-checkins mailing list