mirror of
https://github.com/python/cpython.git
synced 2025-07-23 11:15:24 +00:00

svn+ssh://pythondev@svn.python.org/python/trunk ................ r80934 | benjamin.peterson | 2010-05-07 13:58:23 -0500 (Fri, 07 May 2010) | 69 lines Merged revisions 79911,79916-79917,80018,80418,80572-80573,80635-80639,80668,80922 via svnmerge from svn+ssh://pythondev@svn.python.org/sandbox/trunk/2to3/lib2to3 ........ r79911 | benjamin.peterson | 2010-04-09 15:38:53 -0500 (Fri, 09 Apr 2010) | 1 line use absolute import ........ r79916 | benjamin.peterson | 2010-04-09 16:05:21 -0500 (Fri, 09 Apr 2010) | 1 line generalize detection of __future__ imports and attach them to the tree ........ r79917 | benjamin.peterson | 2010-04-09 16:11:44 -0500 (Fri, 09 Apr 2010) | 1 line don't try to 'fix' relative imports when absolute_import is enabled #8858 ........ r80018 | benjamin.peterson | 2010-04-12 16:12:12 -0500 (Mon, 12 Apr 2010) | 4 lines prevent diffs from being mangled is multiprocess mode #6409 Patch by George Boutsioukis. ........ r80418 | benjamin.peterson | 2010-04-23 16:00:03 -0500 (Fri, 23 Apr 2010) | 1 line remove unhelpful description ........ r80572 | benjamin.peterson | 2010-04-27 20:33:54 -0500 (Tue, 27 Apr 2010) | 1 line use unicode literals ........ r80573 | jeffrey.yasskin | 2010-04-27 23:08:27 -0500 (Tue, 27 Apr 2010) | 6 lines Don't transform imports that are already relative. 2to3 turned from . import refactor into from .. import refactor which broke the transformation of 2to3 itself. ........ r80635 | benjamin.peterson | 2010-04-29 16:02:23 -0500 (Thu, 29 Apr 2010) | 1 line remove imports ........ r80636 | benjamin.peterson | 2010-04-29 16:02:41 -0500 (Thu, 29 Apr 2010) | 1 line unicode literal ........ r80637 | benjamin.peterson | 2010-04-29 16:03:42 -0500 (Thu, 29 Apr 2010) | 1 line must pass a string to Number ........ r80638 | benjamin.peterson | 2010-04-29 16:05:34 -0500 (Thu, 29 Apr 2010) | 1 line unicode literals ........ r80639 | benjamin.peterson | 2010-04-29 16:06:09 -0500 (Thu, 29 Apr 2010) | 1 line pass string to Number ........ r80668 | jeffrey.yasskin | 2010-04-30 18:02:47 -0500 (Fri, 30 Apr 2010) | 4 lines Make 2to3 run under Python 2.5 so that the benchmark suite at http://hg.python.org/benchmarks/ can use it and still run on implementations that haven't gotten to 2.6 yet. Fixes issue 8566. ........ r80922 | benjamin.peterson | 2010-05-07 11:06:25 -0500 (Fri, 07 May 2010) | 1 line prevent xrange transformation from wrapping range calls it produces in list ........ ................
171 lines
5.3 KiB
Python
171 lines
5.3 KiB
Python
"""Fixer for function definitions with tuple parameters.
|
|
|
|
def func(((a, b), c), d):
|
|
...
|
|
|
|
->
|
|
|
|
def func(x, d):
|
|
((a, b), c) = x
|
|
...
|
|
|
|
It will also support lambdas:
|
|
|
|
lambda (x, y): x + y -> lambda t: t[0] + t[1]
|
|
|
|
# The parens are a syntax error in Python 3
|
|
lambda (x): x + y -> lambda x: x + y
|
|
"""
|
|
# Author: Collin Winter
|
|
|
|
# Local imports
|
|
from .. import pytree
|
|
from ..pgen2 import token
|
|
from .. import fixer_base
|
|
from ..fixer_util import Assign, Name, Newline, Number, Subscript, syms
|
|
|
|
def is_docstring(stmt):
|
|
return isinstance(stmt, pytree.Node) and \
|
|
stmt.children[0].type == token.STRING
|
|
|
|
class FixTupleParams(fixer_base.BaseFix):
|
|
PATTERN = """
|
|
funcdef< 'def' any parameters< '(' args=any ')' >
|
|
['->' any] ':' suite=any+ >
|
|
|
|
|
lambda=
|
|
lambdef< 'lambda' args=vfpdef< '(' inner=any ')' >
|
|
':' body=any
|
|
>
|
|
"""
|
|
|
|
def transform(self, node, results):
|
|
if "lambda" in results:
|
|
return self.transform_lambda(node, results)
|
|
|
|
new_lines = []
|
|
suite = results["suite"]
|
|
args = results["args"]
|
|
# This crap is so "def foo(...): x = 5; y = 7" is handled correctly.
|
|
# TODO(cwinter): suite-cleanup
|
|
if suite[0].children[1].type == token.INDENT:
|
|
start = 2
|
|
indent = suite[0].children[1].value
|
|
end = Newline()
|
|
else:
|
|
start = 0
|
|
indent = "; "
|
|
end = pytree.Leaf(token.INDENT, "")
|
|
|
|
# We need access to self for new_name(), and making this a method
|
|
# doesn't feel right. Closing over self and new_lines makes the
|
|
# code below cleaner.
|
|
def handle_tuple(tuple_arg, add_prefix=False):
|
|
n = Name(self.new_name())
|
|
arg = tuple_arg.clone()
|
|
arg.prefix = ""
|
|
stmt = Assign(arg, n.clone())
|
|
if add_prefix:
|
|
n.prefix = " "
|
|
tuple_arg.replace(n)
|
|
new_lines.append(pytree.Node(syms.simple_stmt,
|
|
[stmt, end.clone()]))
|
|
|
|
if args.type == syms.tfpdef:
|
|
handle_tuple(args)
|
|
elif args.type == syms.typedargslist:
|
|
for i, arg in enumerate(args.children):
|
|
if arg.type == syms.tfpdef:
|
|
# Without add_prefix, the emitted code is correct,
|
|
# just ugly.
|
|
handle_tuple(arg, add_prefix=(i > 0))
|
|
|
|
if not new_lines:
|
|
return
|
|
|
|
# This isn't strictly necessary, but it plays nicely with other fixers.
|
|
# TODO(cwinter) get rid of this when children becomes a smart list
|
|
for line in new_lines:
|
|
line.parent = suite[0]
|
|
|
|
# TODO(cwinter) suite-cleanup
|
|
after = start
|
|
if start == 0:
|
|
new_lines[0].prefix = " "
|
|
elif is_docstring(suite[0].children[start]):
|
|
new_lines[0].prefix = indent
|
|
after = start + 1
|
|
|
|
for line in new_lines:
|
|
line.parent = suite[0]
|
|
suite[0].children[after:after] = new_lines
|
|
for i in range(after+1, after+len(new_lines)+1):
|
|
suite[0].children[i].prefix = indent
|
|
suite[0].changed()
|
|
|
|
def transform_lambda(self, node, results):
|
|
args = results["args"]
|
|
body = results["body"]
|
|
inner = simplify_args(results["inner"])
|
|
|
|
# Replace lambda ((((x)))): x with lambda x: x
|
|
if inner.type == token.NAME:
|
|
inner = inner.clone()
|
|
inner.prefix = " "
|
|
args.replace(inner)
|
|
return
|
|
|
|
params = find_params(args)
|
|
to_index = map_to_index(params)
|
|
tup_name = self.new_name(tuple_name(params))
|
|
|
|
new_param = Name(tup_name, prefix=" ")
|
|
args.replace(new_param.clone())
|
|
for n in body.post_order():
|
|
if n.type == token.NAME and n.value in to_index:
|
|
subscripts = [c.clone() for c in to_index[n.value]]
|
|
new = pytree.Node(syms.power,
|
|
[new_param.clone()] + subscripts)
|
|
new.prefix = n.prefix
|
|
n.replace(new)
|
|
|
|
|
|
### Helper functions for transform_lambda()
|
|
|
|
def simplify_args(node):
|
|
if node.type in (syms.vfplist, token.NAME):
|
|
return node
|
|
elif node.type == syms.vfpdef:
|
|
# These look like vfpdef< '(' x ')' > where x is NAME
|
|
# or another vfpdef instance (leading to recursion).
|
|
while node.type == syms.vfpdef:
|
|
node = node.children[1]
|
|
return node
|
|
raise RuntimeError("Received unexpected node %s" % node)
|
|
|
|
def find_params(node):
|
|
if node.type == syms.vfpdef:
|
|
return find_params(node.children[1])
|
|
elif node.type == token.NAME:
|
|
return node.value
|
|
return [find_params(c) for c in node.children if c.type != token.COMMA]
|
|
|
|
def map_to_index(param_list, prefix=[], d=None):
|
|
if d is None:
|
|
d = {}
|
|
for i, obj in enumerate(param_list):
|
|
trailer = [Subscript(Number(str(i)))]
|
|
if isinstance(obj, list):
|
|
map_to_index(obj, trailer, d=d)
|
|
else:
|
|
d[obj] = prefix + trailer
|
|
return d
|
|
|
|
def tuple_name(param_list):
|
|
l = []
|
|
for obj in param_list:
|
|
if isinstance(obj, list):
|
|
l.append(tuple_name(obj))
|
|
else:
|
|
l.append(obj)
|
|
return "_".join(l)
|