ยปCore Development>Code coverage>Lib/lib2to3/fixes/fix_tuple_params.py

Python code coverage for Lib/lib2to3/fixes/fix_tuple_params.py

#countcontent
1n/a"""Fixer for function definitions with tuple parameters.
2n/a
3n/adef func(((a, b), c), d):
4n/a ...
5n/a
6n/a ->
7n/a
8n/adef func(x, d):
9n/a ((a, b), c) = x
10n/a ...
11n/a
12n/aIt will also support lambdas:
13n/a
14n/a lambda (x, y): x + y -> lambda t: t[0] + t[1]
15n/a
16n/a # The parens are a syntax error in Python 3
17n/a lambda (x): x + y -> lambda x: x + y
18n/a"""
19n/a# Author: Collin Winter
20n/a
21n/a# Local imports
22n/afrom .. import pytree
23n/afrom ..pgen2 import token
24n/afrom .. import fixer_base
25n/afrom ..fixer_util import Assign, Name, Newline, Number, Subscript, syms
26n/a
27n/adef is_docstring(stmt):
28n/a return isinstance(stmt, pytree.Node) and \
29n/a stmt.children[0].type == token.STRING
30n/a
31n/aclass FixTupleParams(fixer_base.BaseFix):
32n/a run_order = 4 #use a lower order since lambda is part of other
33n/a #patterns
34n/a BM_compatible = True
35n/a
36n/a PATTERN = """
37n/a funcdef< 'def' any parameters< '(' args=any ')' >
38n/a ['->' any] ':' suite=any+ >
39n/a |
40n/a lambda=
41n/a lambdef< 'lambda' args=vfpdef< '(' inner=any ')' >
42n/a ':' body=any
43n/a >
44n/a """
45n/a
46n/a def transform(self, node, results):
47n/a if "lambda" in results:
48n/a return self.transform_lambda(node, results)
49n/a
50n/a new_lines = []
51n/a suite = results["suite"]
52n/a args = results["args"]
53n/a # This crap is so "def foo(...): x = 5; y = 7" is handled correctly.
54n/a # TODO(cwinter): suite-cleanup
55n/a if suite[0].children[1].type == token.INDENT:
56n/a start = 2
57n/a indent = suite[0].children[1].value
58n/a end = Newline()
59n/a else:
60n/a start = 0
61n/a indent = "; "
62n/a end = pytree.Leaf(token.INDENT, "")
63n/a
64n/a # We need access to self for new_name(), and making this a method
65n/a # doesn't feel right. Closing over self and new_lines makes the
66n/a # code below cleaner.
67n/a def handle_tuple(tuple_arg, add_prefix=False):
68n/a n = Name(self.new_name())
69n/a arg = tuple_arg.clone()
70n/a arg.prefix = ""
71n/a stmt = Assign(arg, n.clone())
72n/a if add_prefix:
73n/a n.prefix = " "
74n/a tuple_arg.replace(n)
75n/a new_lines.append(pytree.Node(syms.simple_stmt,
76n/a [stmt, end.clone()]))
77n/a
78n/a if args.type == syms.tfpdef:
79n/a handle_tuple(args)
80n/a elif args.type == syms.typedargslist:
81n/a for i, arg in enumerate(args.children):
82n/a if arg.type == syms.tfpdef:
83n/a # Without add_prefix, the emitted code is correct,
84n/a # just ugly.
85n/a handle_tuple(arg, add_prefix=(i > 0))
86n/a
87n/a if not new_lines:
88n/a return
89n/a
90n/a # This isn't strictly necessary, but it plays nicely with other fixers.
91n/a # TODO(cwinter) get rid of this when children becomes a smart list
92n/a for line in new_lines:
93n/a line.parent = suite[0]
94n/a
95n/a # TODO(cwinter) suite-cleanup
96n/a after = start
97n/a if start == 0:
98n/a new_lines[0].prefix = " "
99n/a elif is_docstring(suite[0].children[start]):
100n/a new_lines[0].prefix = indent
101n/a after = start + 1
102n/a
103n/a for line in new_lines:
104n/a line.parent = suite[0]
105n/a suite[0].children[after:after] = new_lines
106n/a for i in range(after+1, after+len(new_lines)+1):
107n/a suite[0].children[i].prefix = indent
108n/a suite[0].changed()
109n/a
110n/a def transform_lambda(self, node, results):
111n/a args = results["args"]
112n/a body = results["body"]
113n/a inner = simplify_args(results["inner"])
114n/a
115n/a # Replace lambda ((((x)))): x with lambda x: x
116n/a if inner.type == token.NAME:
117n/a inner = inner.clone()
118n/a inner.prefix = " "
119n/a args.replace(inner)
120n/a return
121n/a
122n/a params = find_params(args)
123n/a to_index = map_to_index(params)
124n/a tup_name = self.new_name(tuple_name(params))
125n/a
126n/a new_param = Name(tup_name, prefix=" ")
127n/a args.replace(new_param.clone())
128n/a for n in body.post_order():
129n/a if n.type == token.NAME and n.value in to_index:
130n/a subscripts = [c.clone() for c in to_index[n.value]]
131n/a new = pytree.Node(syms.power,
132n/a [new_param.clone()] + subscripts)
133n/a new.prefix = n.prefix
134n/a n.replace(new)
135n/a
136n/a
137n/a### Helper functions for transform_lambda()
138n/a
139n/adef simplify_args(node):
140n/a if node.type in (syms.vfplist, token.NAME):
141n/a return node
142n/a elif node.type == syms.vfpdef:
143n/a # These look like vfpdef< '(' x ')' > where x is NAME
144n/a # or another vfpdef instance (leading to recursion).
145n/a while node.type == syms.vfpdef:
146n/a node = node.children[1]
147n/a return node
148n/a raise RuntimeError("Received unexpected node %s" % node)
149n/a
150n/adef find_params(node):
151n/a if node.type == syms.vfpdef:
152n/a return find_params(node.children[1])
153n/a elif node.type == token.NAME:
154n/a return node.value
155n/a return [find_params(c) for c in node.children if c.type != token.COMMA]
156n/a
157n/adef map_to_index(param_list, prefix=[], d=None):
158n/a if d is None:
159n/a d = {}
160n/a for i, obj in enumerate(param_list):
161n/a trailer = [Subscript(Number(str(i)))]
162n/a if isinstance(obj, list):
163n/a map_to_index(obj, trailer, d=d)
164n/a else:
165n/a d[obj] = prefix + trailer
166n/a return d
167n/a
168n/adef tuple_name(param_list):
169n/a l = []
170n/a for obj in param_list:
171n/a if isinstance(obj, list):
172n/a l.append(tuple_name(obj))
173n/a else:
174n/a l.append(obj)
175n/a return "_".join(l)