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