1 """Fixer for except statements with named exceptions.
2
3 The following cases will be converted:
4
5 - "except E, T:" where T is a name:
6
7 except E as T:
8
9 - "except E, T:" where T is not a name, tuple or list:
10
11 except E as t:
12 T = t
13
14 This is done because the target of an "except" clause must be a
15 name.
16
17 - "except E, T:" where T is a tuple or list literal:
18
19 except E as t:
20 T = t.args
21 """
22 # Author: Collin Winter
23
24 # Local imports
25 from .. import pytree
26 from ..pgen2 import token
27 from .. import fixer_base
28 from ..fixer_util import Assign, Attr, Name, is_tuple, is_list, syms
29
30 def find_excepts(nodes):
31 for i, n in enumerate(nodes):
32 if n.type == syms.except_clause:
33 if n.children[0].value == 'except':
34 yield (n, nodes[i+2])
35
36 class ESC[4;38;5;81mFixExcept(ESC[4;38;5;149mfixer_baseESC[4;38;5;149m.ESC[4;38;5;149mBaseFix):
37 BM_compatible = True
38
39 PATTERN = """
40 try_stmt< 'try' ':' (simple_stmt | suite)
41 cleanup=(except_clause ':' (simple_stmt | suite))+
42 tail=(['except' ':' (simple_stmt | suite)]
43 ['else' ':' (simple_stmt | suite)]
44 ['finally' ':' (simple_stmt | suite)]) >
45 """
46
47 def transform(self, node, results):
48 syms = self.syms
49
50 tail = [n.clone() for n in results["tail"]]
51
52 try_cleanup = [ch.clone() for ch in results["cleanup"]]
53 for except_clause, e_suite in find_excepts(try_cleanup):
54 if len(except_clause.children) == 4:
55 (E, comma, N) = except_clause.children[1:4]
56 comma.replace(Name("as", prefix=" "))
57
58 if N.type != token.NAME:
59 # Generate a new N for the except clause
60 new_N = Name(self.new_name(), prefix=" ")
61 target = N.clone()
62 target.prefix = ""
63 N.replace(new_N)
64 new_N = new_N.clone()
65
66 # Insert "old_N = new_N" as the first statement in
67 # the except body. This loop skips leading whitespace
68 # and indents
69 #TODO(cwinter) suite-cleanup
70 suite_stmts = e_suite.children
71 for i, stmt in enumerate(suite_stmts):
72 if isinstance(stmt, pytree.Node):
73 break
74
75 # The assignment is different if old_N is a tuple or list
76 # In that case, the assignment is old_N = new_N.args
77 if is_tuple(N) or is_list(N):
78 assign = Assign(target, Attr(new_N, Name('args')))
79 else:
80 assign = Assign(target, new_N)
81
82 #TODO(cwinter) stopgap until children becomes a smart list
83 for child in reversed(suite_stmts[:i]):
84 e_suite.insert_child(0, child)
85 e_suite.insert_child(i, assign)
86 elif N.prefix == "":
87 # No space after a comma is legal; no space after "as",
88 # not so much.
89 N.prefix = " "
90
91 #TODO(cwinter) fix this when children becomes a smart list
92 children = [c.clone() for c in node.children[:3]] + try_cleanup + tail
93 return pytree.Node(node.type, children)