17db96d56Sopenharmony_ci"""Fixer for except statements with named exceptions. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciThe following cases will be converted: 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ci- "except E, T:" where T is a name: 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ci except E as T: 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci- "except E, T:" where T is not a name, tuple or list: 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci except E as t: 127db96d56Sopenharmony_ci T = t 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci This is done because the target of an "except" clause must be a 157db96d56Sopenharmony_ci name. 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci- "except E, T:" where T is a tuple or list literal: 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci except E as t: 207db96d56Sopenharmony_ci T = t.args 217db96d56Sopenharmony_ci""" 227db96d56Sopenharmony_ci# Author: Collin Winter 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci# Local imports 257db96d56Sopenharmony_cifrom .. import pytree 267db96d56Sopenharmony_cifrom ..pgen2 import token 277db96d56Sopenharmony_cifrom .. import fixer_base 287db96d56Sopenharmony_cifrom ..fixer_util import Assign, Attr, Name, is_tuple, is_list, syms 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_cidef find_excepts(nodes): 317db96d56Sopenharmony_ci for i, n in enumerate(nodes): 327db96d56Sopenharmony_ci if n.type == syms.except_clause: 337db96d56Sopenharmony_ci if n.children[0].value == 'except': 347db96d56Sopenharmony_ci yield (n, nodes[i+2]) 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ciclass FixExcept(fixer_base.BaseFix): 377db96d56Sopenharmony_ci BM_compatible = True 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci PATTERN = """ 407db96d56Sopenharmony_ci try_stmt< 'try' ':' (simple_stmt | suite) 417db96d56Sopenharmony_ci cleanup=(except_clause ':' (simple_stmt | suite))+ 427db96d56Sopenharmony_ci tail=(['except' ':' (simple_stmt | suite)] 437db96d56Sopenharmony_ci ['else' ':' (simple_stmt | suite)] 447db96d56Sopenharmony_ci ['finally' ':' (simple_stmt | suite)]) > 457db96d56Sopenharmony_ci """ 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci def transform(self, node, results): 487db96d56Sopenharmony_ci syms = self.syms 497db96d56Sopenharmony_ci 507db96d56Sopenharmony_ci tail = [n.clone() for n in results["tail"]] 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci try_cleanup = [ch.clone() for ch in results["cleanup"]] 537db96d56Sopenharmony_ci for except_clause, e_suite in find_excepts(try_cleanup): 547db96d56Sopenharmony_ci if len(except_clause.children) == 4: 557db96d56Sopenharmony_ci (E, comma, N) = except_clause.children[1:4] 567db96d56Sopenharmony_ci comma.replace(Name("as", prefix=" ")) 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci if N.type != token.NAME: 597db96d56Sopenharmony_ci # Generate a new N for the except clause 607db96d56Sopenharmony_ci new_N = Name(self.new_name(), prefix=" ") 617db96d56Sopenharmony_ci target = N.clone() 627db96d56Sopenharmony_ci target.prefix = "" 637db96d56Sopenharmony_ci N.replace(new_N) 647db96d56Sopenharmony_ci new_N = new_N.clone() 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci # Insert "old_N = new_N" as the first statement in 677db96d56Sopenharmony_ci # the except body. This loop skips leading whitespace 687db96d56Sopenharmony_ci # and indents 697db96d56Sopenharmony_ci #TODO(cwinter) suite-cleanup 707db96d56Sopenharmony_ci suite_stmts = e_suite.children 717db96d56Sopenharmony_ci for i, stmt in enumerate(suite_stmts): 727db96d56Sopenharmony_ci if isinstance(stmt, pytree.Node): 737db96d56Sopenharmony_ci break 747db96d56Sopenharmony_ci 757db96d56Sopenharmony_ci # The assignment is different if old_N is a tuple or list 767db96d56Sopenharmony_ci # In that case, the assignment is old_N = new_N.args 777db96d56Sopenharmony_ci if is_tuple(N) or is_list(N): 787db96d56Sopenharmony_ci assign = Assign(target, Attr(new_N, Name('args'))) 797db96d56Sopenharmony_ci else: 807db96d56Sopenharmony_ci assign = Assign(target, new_N) 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci #TODO(cwinter) stopgap until children becomes a smart list 837db96d56Sopenharmony_ci for child in reversed(suite_stmts[:i]): 847db96d56Sopenharmony_ci e_suite.insert_child(0, child) 857db96d56Sopenharmony_ci e_suite.insert_child(i, assign) 867db96d56Sopenharmony_ci elif N.prefix == "": 877db96d56Sopenharmony_ci # No space after a comma is legal; no space after "as", 887db96d56Sopenharmony_ci # not so much. 897db96d56Sopenharmony_ci N.prefix = " " 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci #TODO(cwinter) fix this when children becomes a smart list 927db96d56Sopenharmony_ci children = [c.clone() for c in node.children[:3]] + try_cleanup + tail 937db96d56Sopenharmony_ci return pytree.Node(node.type, children) 94