1"""Fixer for except statements with named exceptions. 2 3The 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 25from .. import pytree 26from ..pgen2 import token 27from .. import fixer_base 28from ..fixer_util import Assign, Attr, Name, is_tuple, is_list, syms 29 30def 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 36class FixExcept(fixer_base.BaseFix): 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) 94