17db96d56Sopenharmony_ci"""Adjust some old Python 2 idioms to their modern counterparts. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci* Change some type comparisons to isinstance() calls: 47db96d56Sopenharmony_ci type(x) == T -> isinstance(x, T) 57db96d56Sopenharmony_ci type(x) is T -> isinstance(x, T) 67db96d56Sopenharmony_ci type(x) != T -> not isinstance(x, T) 77db96d56Sopenharmony_ci type(x) is not T -> not isinstance(x, T) 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci* Change "while 1:" into "while True:". 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci* Change both 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ci v = list(EXPR) 147db96d56Sopenharmony_ci v.sort() 157db96d56Sopenharmony_ci foo(v) 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciand the more general 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci v = EXPR 207db96d56Sopenharmony_ci v.sort() 217db96d56Sopenharmony_ci foo(v) 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ciinto 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci v = sorted(EXPR) 267db96d56Sopenharmony_ci foo(v) 277db96d56Sopenharmony_ci""" 287db96d56Sopenharmony_ci# Author: Jacques Frechet, Collin Winter 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_ci# Local imports 317db96d56Sopenharmony_cifrom .. import fixer_base 327db96d56Sopenharmony_cifrom ..fixer_util import Call, Comma, Name, Node, BlankLine, syms 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ciCMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)" 357db96d56Sopenharmony_ciTYPE = "power< 'type' trailer< '(' x=any ')' > >" 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ciclass FixIdioms(fixer_base.BaseFix): 387db96d56Sopenharmony_ci explicit = True # The user must ask for this fixer 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ci PATTERN = r""" 417db96d56Sopenharmony_ci isinstance=comparison< %s %s T=any > 427db96d56Sopenharmony_ci | 437db96d56Sopenharmony_ci isinstance=comparison< T=any %s %s > 447db96d56Sopenharmony_ci | 457db96d56Sopenharmony_ci while_stmt< 'while' while='1' ':' any+ > 467db96d56Sopenharmony_ci | 477db96d56Sopenharmony_ci sorted=any< 487db96d56Sopenharmony_ci any* 497db96d56Sopenharmony_ci simple_stmt< 507db96d56Sopenharmony_ci expr_stmt< id1=any '=' 517db96d56Sopenharmony_ci power< list='list' trailer< '(' (not arglist<any+>) any ')' > > 527db96d56Sopenharmony_ci > 537db96d56Sopenharmony_ci '\n' 547db96d56Sopenharmony_ci > 557db96d56Sopenharmony_ci sort= 567db96d56Sopenharmony_ci simple_stmt< 577db96d56Sopenharmony_ci power< id2=any 587db96d56Sopenharmony_ci trailer< '.' 'sort' > trailer< '(' ')' > 597db96d56Sopenharmony_ci > 607db96d56Sopenharmony_ci '\n' 617db96d56Sopenharmony_ci > 627db96d56Sopenharmony_ci next=any* 637db96d56Sopenharmony_ci > 647db96d56Sopenharmony_ci | 657db96d56Sopenharmony_ci sorted=any< 667db96d56Sopenharmony_ci any* 677db96d56Sopenharmony_ci simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' > 687db96d56Sopenharmony_ci sort= 697db96d56Sopenharmony_ci simple_stmt< 707db96d56Sopenharmony_ci power< id2=any 717db96d56Sopenharmony_ci trailer< '.' 'sort' > trailer< '(' ')' > 727db96d56Sopenharmony_ci > 737db96d56Sopenharmony_ci '\n' 747db96d56Sopenharmony_ci > 757db96d56Sopenharmony_ci next=any* 767db96d56Sopenharmony_ci > 777db96d56Sopenharmony_ci """ % (TYPE, CMP, CMP, TYPE) 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci def match(self, node): 807db96d56Sopenharmony_ci r = super(FixIdioms, self).match(node) 817db96d56Sopenharmony_ci # If we've matched one of the sort/sorted subpatterns above, we 827db96d56Sopenharmony_ci # want to reject matches where the initial assignment and the 837db96d56Sopenharmony_ci # subsequent .sort() call involve different identifiers. 847db96d56Sopenharmony_ci if r and "sorted" in r: 857db96d56Sopenharmony_ci if r["id1"] == r["id2"]: 867db96d56Sopenharmony_ci return r 877db96d56Sopenharmony_ci return None 887db96d56Sopenharmony_ci return r 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci def transform(self, node, results): 917db96d56Sopenharmony_ci if "isinstance" in results: 927db96d56Sopenharmony_ci return self.transform_isinstance(node, results) 937db96d56Sopenharmony_ci elif "while" in results: 947db96d56Sopenharmony_ci return self.transform_while(node, results) 957db96d56Sopenharmony_ci elif "sorted" in results: 967db96d56Sopenharmony_ci return self.transform_sort(node, results) 977db96d56Sopenharmony_ci else: 987db96d56Sopenharmony_ci raise RuntimeError("Invalid match") 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci def transform_isinstance(self, node, results): 1017db96d56Sopenharmony_ci x = results["x"].clone() # The thing inside of type() 1027db96d56Sopenharmony_ci T = results["T"].clone() # The type being compared against 1037db96d56Sopenharmony_ci x.prefix = "" 1047db96d56Sopenharmony_ci T.prefix = " " 1057db96d56Sopenharmony_ci test = Call(Name("isinstance"), [x, Comma(), T]) 1067db96d56Sopenharmony_ci if "n" in results: 1077db96d56Sopenharmony_ci test.prefix = " " 1087db96d56Sopenharmony_ci test = Node(syms.not_test, [Name("not"), test]) 1097db96d56Sopenharmony_ci test.prefix = node.prefix 1107db96d56Sopenharmony_ci return test 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci def transform_while(self, node, results): 1137db96d56Sopenharmony_ci one = results["while"] 1147db96d56Sopenharmony_ci one.replace(Name("True", prefix=one.prefix)) 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci def transform_sort(self, node, results): 1177db96d56Sopenharmony_ci sort_stmt = results["sort"] 1187db96d56Sopenharmony_ci next_stmt = results["next"] 1197db96d56Sopenharmony_ci list_call = results.get("list") 1207db96d56Sopenharmony_ci simple_expr = results.get("expr") 1217db96d56Sopenharmony_ci 1227db96d56Sopenharmony_ci if list_call: 1237db96d56Sopenharmony_ci list_call.replace(Name("sorted", prefix=list_call.prefix)) 1247db96d56Sopenharmony_ci elif simple_expr: 1257db96d56Sopenharmony_ci new = simple_expr.clone() 1267db96d56Sopenharmony_ci new.prefix = "" 1277db96d56Sopenharmony_ci simple_expr.replace(Call(Name("sorted"), [new], 1287db96d56Sopenharmony_ci prefix=simple_expr.prefix)) 1297db96d56Sopenharmony_ci else: 1307db96d56Sopenharmony_ci raise RuntimeError("should not have reached here") 1317db96d56Sopenharmony_ci sort_stmt.remove() 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci btwn = sort_stmt.prefix 1347db96d56Sopenharmony_ci # Keep any prefix lines between the sort_stmt and the list_call and 1357db96d56Sopenharmony_ci # shove them right after the sorted() call. 1367db96d56Sopenharmony_ci if "\n" in btwn: 1377db96d56Sopenharmony_ci if next_stmt: 1387db96d56Sopenharmony_ci # The new prefix should be everything from the sort_stmt's 1397db96d56Sopenharmony_ci # prefix up to the last newline, then the old prefix after a new 1407db96d56Sopenharmony_ci # line. 1417db96d56Sopenharmony_ci prefix_lines = (btwn.rpartition("\n")[0], next_stmt[0].prefix) 1427db96d56Sopenharmony_ci next_stmt[0].prefix = "\n".join(prefix_lines) 1437db96d56Sopenharmony_ci else: 1447db96d56Sopenharmony_ci assert list_call.parent 1457db96d56Sopenharmony_ci assert list_call.next_sibling is None 1467db96d56Sopenharmony_ci # Put a blank line after list_call and set its prefix. 1477db96d56Sopenharmony_ci end_line = BlankLine() 1487db96d56Sopenharmony_ci list_call.parent.append_child(end_line) 1497db96d56Sopenharmony_ci assert list_call.next_sibling is end_line 1507db96d56Sopenharmony_ci # The new prefix should be everything up to the first new line 1517db96d56Sopenharmony_ci # of sort_stmt's prefix. 1527db96d56Sopenharmony_ci end_line.prefix = btwn.rpartition("\n")[0] 153