Merged revisions 61598-61599,61601 via svnmerge from

svn+ssh://pythondev@svn.python.org/sandbox/trunk/2to3/lib2to3

........
  r61598 | david.wolever | 2008-03-18 23:58:33 -0500 (Di, 18 Mär 2008) | 1 line

  Added fixer for zip, and refactored a bit of code in the process.  Closing #2171.
........
  r61599 | david.wolever | 2008-03-19 00:04:26 -0500 (Mi, 19 Mär 2008) | 3 lines

  Removed a bunch of duplicate code -- it's in util now.
........
  r61601 | martin.v.loewis | 2008-03-19 00:21:12 -0500 (Mi, 19 Mär 2008) | 2 lines

  Fix whitespace.
........
This commit is contained in:
Martin v. Löwis 2008-03-19 05:22:42 +00:00
parent aad2b61f44
commit ab41b370a3
24 changed files with 249 additions and 174 deletions

View File

@ -14,11 +14,9 @@ Python 2.6 figure it out.
"""
# Local imports
from .. import pytree
from .. import patcomp
from ..pgen2 import token
from . import basefix
from .util import Name, Call, ListComp, attr_chain, does_tree_import
from .util import Name, Call, ListComp, does_tree_import, in_special_context
class FixFilter(basefix.BaseFix):
@ -85,35 +83,3 @@ class FixFilter(basefix.BaseFix):
new = Call(Name("list"), [new])
new.set_prefix(node.get_prefix())
return new
P0 = """for_stmt< 'for' any 'in' node=any ':' any* >
| comp_for< 'for' any 'in' node=any any* >
"""
p0 = patcomp.compile_pattern(P0)
P1 = """
power<
( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
'any' | 'all' | (any* trailer< '.' 'join' >) )
trailer< '(' node=any ')' >
any*
>
"""
p1 = patcomp.compile_pattern(P1)
P2 = """
power<
'sorted'
trailer< '(' arglist<node=any any*> ')' >
any*
>
"""
p2 = patcomp.compile_pattern(P2)
def in_special_context(node):
patterns = [p0, p1, p2]
for pattern, parent in zip(patterns, attr_chain(node, "parent")):
results = {}
if pattern.match(parent, results) and results["node"] is node:
return True
return False

View File

@ -13,4 +13,3 @@ class FixFuture(basefix.BaseFix):
def transform(self, node, results):
return BlankLine()

View File

@ -20,11 +20,9 @@ soon as the shortest argument is exhausted.
"""
# Local imports
from .. import pytree
from .. import patcomp
from ..pgen2 import token
from . import basefix
from .util import Name, Call, ListComp, attr_chain, does_tree_import
from .util import Name, Call, ListComp, does_tree_import, in_special_context
from ..pygram import python_symbols as syms
class FixMap(basefix.BaseFix):
@ -92,35 +90,3 @@ class FixMap(basefix.BaseFix):
new = Call(Name("list"), [new])
new.set_prefix(node.get_prefix())
return new
P0 = """for_stmt< 'for' any 'in' node=any ':' any* >
| comp_for< 'for' any 'in' node=any any* >
"""
p0 = patcomp.compile_pattern(P0)
P1 = """
power<
( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
'any' | 'all' | (any* trailer< '.' 'join' >) )
trailer< '(' node=any ')' >
any*
>
"""
p1 = patcomp.compile_pattern(P1)
P2 = """
power<
'sorted'
trailer< '(' arglist<node=any any*> ')' >
any*
>
"""
p2 = patcomp.compile_pattern(P2)
def in_special_context(node):
patterns = [p0, p1, p2]
for pattern, parent in zip(patterns, attr_chain(node, "parent")):
results = {}
if pattern.match(parent, results) and results["node"] is node:
return True
return False

View File

@ -67,4 +67,3 @@ class FixRenames(basefix.BaseFix):
if mod_name and attr_name:
new_attr = LOOKUP[(mod_name.value, attr_name.value)]
attr_name.replace(Name(new_attr, prefix=attr_name.get_prefix()))

View File

@ -0,0 +1,43 @@
"""
Fixer that changes zip(seq0, seq1, ...) into list(zip(seq0, seq1, ...)
unless there exists a 'from future_builtins import zip' statement in the
top-level namespace.
We avoid the transformation if the zip() call is directly contained in
iter(<>), list(<>), tuple(<>), sorted(<>), ...join(<>), or for V in <>:.
"""
# Local imports
from . import basefix
from .util import Name, Call, does_tree_import, in_special_context
class FixZip(basefix.BaseFix):
PATTERN = """
power< 'zip' args=trailer< '(' [any] ')' >
>
"""
def start_tree(self, *args):
super(FixZip, self).start_tree(*args)
self._future_zip_found = None
def has_future_zip(self, node):
if self._future_zip_found is not None:
return self._future_zip_found
self._future_zip_found = does_tree_import('future_builtins', 'zip', node)
return self._future_zip_found
def transform(self, node, results):
if self.has_future_zip(node):
# If a future zip has been imported for this file, we won't
# be making any modifications
return
if 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

View File

@ -5,6 +5,7 @@
from ..pgen2 import token
from ..pytree import Leaf, Node
from ..pygram import python_symbols as syms
from .. import patcomp
###########################################################
@ -180,6 +181,44 @@ def attr_chain(obj, attr):
yield next
next = getattr(next, attr)
p0 = """for_stmt< 'for' any 'in' node=any ':' any* >
| comp_for< 'for' any 'in' node=any any* >
"""
p1 = """
power<
( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
'any' | 'all' | (any* trailer< '.' 'join' >) )
trailer< '(' node=any ')' >
any*
>
"""
p2 = """
power<
'sorted'
trailer< '(' arglist<node=any any*> ')' >
any*
>
"""
pats_built = False
def in_special_context(node):
""" Returns true if node is in an environment where all that is required
of it is being itterable (ie, it doesn't matter if it returns a list
or an itterator).
See test_map_nochange in test_fixers.py for some examples and tests.
"""
global p0, p1, p2, pats_built
if not pats_built:
p1 = patcomp.compile_pattern(p1)
p0 = patcomp.compile_pattern(p0)
p2 = patcomp.compile_pattern(p2)
pats_built = True
patterns = [p0, p1, p2]
for pattern, parent in zip(patterns, attr_chain(node, "parent")):
results = {}
if pattern.match(parent, results) and results["node"] is node:
return True
return False
###########################################################
### The following functions are to find bindings in a suite
###########################################################

View File

@ -2493,6 +2493,69 @@ class Test_map(FixerTestCase):
a = "from future_builtins import *; map(f, 'ham')"
self.unchanged(a)
class Test_zip(FixerTestCase):
fixer = "zip"
def check(self, b, a):
self.unchanged("from future_builtins import zip; " + b, a)
FixerTestCase.check(self, b, a)
def test_zip_basic(self):
b = """x = zip(a, b, c)"""
a = """x = list(zip(a, b, c))"""
self.check(b, a)
b = """x = len(zip(a, b))"""
a = """x = len(list(zip(a, b)))"""
self.check(b, a)
def test_zip_nochange(self):
a = """b.join(zip(a, b))"""
self.unchanged(a)
a = """(a + foo(5)).join(zip(a, b))"""
self.unchanged(a)
a = """iter(zip(a, b))"""
self.unchanged(a)
a = """list(zip(a, b))"""
self.unchanged(a)
a = """list(zip(a, b))[0]"""
self.unchanged(a)
a = """set(zip(a, b))"""
self.unchanged(a)
a = """set(zip(a, b)).pop()"""
self.unchanged(a)
a = """tuple(zip(a, b))"""
self.unchanged(a)
a = """any(zip(a, b))"""
self.unchanged(a)
a = """all(zip(a, b))"""
self.unchanged(a)
a = """sum(zip(a, b))"""
self.unchanged(a)
a = """sorted(zip(a, b))"""
self.unchanged(a)
a = """sorted(zip(a, b), key=blah)"""
self.unchanged(a)
a = """sorted(zip(a, b), key=blah)[0]"""
self.unchanged(a)
a = """for i in zip(a, b): pass"""
self.unchanged(a)
a = """[x for x in zip(a, b)]"""
self.unchanged(a)
a = """(x for x in zip(a, b))"""
self.unchanged(a)
def test_future_builtins(self):
a = "from future_builtins import spam, zip, eggs; zip(a, b)"
self.unchanged(a)
b = """from future_builtins import spam, eggs; x = zip(a, b)"""
a = """from future_builtins import spam, eggs; x = list(zip(a, b))"""
self.check(b, a)
a = "from future_builtins import *; zip(a, b)"
self.unchanged(a)
class Test_standarderror(FixerTestCase):
fixer = "standarderror"