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

# Python code coverage for Lib/lib2to3/fixes/fix_idioms.py

#countcontent
1n/a"""Adjust some old Python 2 idioms to their modern counterparts.
2n/a
3n/a* Change some type comparisons to isinstance() calls:
4n/a type(x) == T -> isinstance(x, T)
5n/a type(x) is T -> isinstance(x, T)
6n/a type(x) != T -> not isinstance(x, T)
7n/a type(x) is not T -> not isinstance(x, T)
8n/a
9n/a* Change "while 1:" into "while True:".
10n/a
11n/a* Change both
12n/a
13n/a v = list(EXPR)
14n/a v.sort()
15n/a foo(v)
16n/a
17n/aand the more general
18n/a
19n/a v = EXPR
20n/a v.sort()
21n/a foo(v)
22n/a
23n/ainto
24n/a
25n/a v = sorted(EXPR)
26n/a foo(v)
27n/a"""
28n/a# Author: Jacques Frechet, Collin Winter
29n/a
30n/a# Local imports
31n/afrom .. import fixer_base
32n/afrom ..fixer_util import Call, Comma, Name, Node, BlankLine, syms
33n/a
34n/aCMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)"
35n/aTYPE = "power< 'type' trailer< '(' x=any ')' > >"
36n/a
37n/aclass FixIdioms(fixer_base.BaseFix):
38n/a explicit = True # The user must ask for this fixer
39n/a
40n/a PATTERN = r"""
41n/a isinstance=comparison< %s %s T=any >
42n/a |
43n/a isinstance=comparison< T=any %s %s >
44n/a |
45n/a while_stmt< 'while' while='1' ':' any+ >
46n/a |
47n/a sorted=any<
48n/a any*
49n/a simple_stmt<
50n/a expr_stmt< id1=any '='
51n/a power< list='list' trailer< '(' (not arglist<any+>) any ')' > >
52n/a >
53n/a '\n'
54n/a >
55n/a sort=
56n/a simple_stmt<
57n/a power< id2=any
58n/a trailer< '.' 'sort' > trailer< '(' ')' >
59n/a >
60n/a '\n'
61n/a >
62n/a next=any*
63n/a >
64n/a |
65n/a sorted=any<
66n/a any*
67n/a simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' >
68n/a sort=
69n/a simple_stmt<
70n/a power< id2=any
71n/a trailer< '.' 'sort' > trailer< '(' ')' >
72n/a >
73n/a '\n'
74n/a >
75n/a next=any*
76n/a >
77n/a """ % (TYPE, CMP, CMP, TYPE)
78n/a
79n/a def match(self, node):
80n/a r = super(FixIdioms, self).match(node)
81n/a # If we've matched one of the sort/sorted subpatterns above, we
82n/a # want to reject matches where the initial assignment and the
83n/a # subsequent .sort() call involve different identifiers.
84n/a if r and "sorted" in r:
85n/a if r["id1"] == r["id2"]:
86n/a return r
87n/a return None
88n/a return r
89n/a
90n/a def transform(self, node, results):
91n/a if "isinstance" in results:
92n/a return self.transform_isinstance(node, results)
93n/a elif "while" in results:
94n/a return self.transform_while(node, results)
95n/a elif "sorted" in results:
96n/a return self.transform_sort(node, results)
97n/a else:
98n/a raise RuntimeError("Invalid match")
99n/a
100n/a def transform_isinstance(self, node, results):
101n/a x = results["x"].clone() # The thing inside of type()
102n/a T = results["T"].clone() # The type being compared against
103n/a x.prefix = ""
104n/a T.prefix = " "
105n/a test = Call(Name("isinstance"), [x, Comma(), T])
106n/a if "n" in results:
107n/a test.prefix = " "
108n/a test = Node(syms.not_test, [Name("not"), test])
109n/a test.prefix = node.prefix
110n/a return test
111n/a
112n/a def transform_while(self, node, results):
113n/a one = results["while"]
114n/a one.replace(Name("True", prefix=one.prefix))
115n/a
116n/a def transform_sort(self, node, results):
117n/a sort_stmt = results["sort"]
118n/a next_stmt = results["next"]
119n/a list_call = results.get("list")
120n/a simple_expr = results.get("expr")
121n/a
122n/a if list_call:
123n/a list_call.replace(Name("sorted", prefix=list_call.prefix))
124n/a elif simple_expr:
125n/a new = simple_expr.clone()
126n/a new.prefix = ""
127n/a simple_expr.replace(Call(Name("sorted"), [new],
128n/a prefix=simple_expr.prefix))
129n/a else:
130n/a raise RuntimeError("should not have reached here")
131n/a sort_stmt.remove()
132n/a
133n/a btwn = sort_stmt.prefix
134n/a # Keep any prefix lines between the sort_stmt and the list_call and
135n/a # shove them right after the sorted() call.
136n/a if "\n" in btwn:
137n/a if next_stmt:
138n/a # The new prefix should be everything from the sort_stmt's
139n/a # prefix up to the last newline, then the old prefix after a new
140n/a # line.
141n/a prefix_lines = (btwn.rpartition("\n")[0], next_stmt[0].prefix)
142n/a next_stmt[0].prefix = "\n".join(prefix_lines)
143n/a else:
144n/a assert list_call.parent
145n/a assert list_call.next_sibling is None
146n/a # Put a blank line after list_call and set its prefix.
147n/a end_line = BlankLine()
148n/a list_call.parent.append_child(end_line)
149n/a assert list_call.next_sibling is end_line
150n/a # The new prefix should be everything up to the first new line
151n/a # of sort_stmt's prefix.
152n/a end_line.prefix = btwn.rpartition("\n")[0]