17db96d56Sopenharmony_ci# Copyright 2006 Google, Inc. All Rights Reserved. 27db96d56Sopenharmony_ci# Licensed to PSF under a Contributor Agreement. 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_ci"""Fixer for has_key(). 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ciCalls to .has_key() methods are expressed in terms of the 'in' 77db96d56Sopenharmony_cioperator: 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci d.has_key(k) -> k in d 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ciCAVEATS: 127db96d56Sopenharmony_ci1) While the primary target of this fixer is dict.has_key(), the 137db96d56Sopenharmony_ci fixer will change any has_key() method call, regardless of its 147db96d56Sopenharmony_ci class. 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci2) Cases like this will not be converted: 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ci m = d.has_key 197db96d56Sopenharmony_ci if m(k): 207db96d56Sopenharmony_ci ... 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_ci Only *calls* to has_key() are converted. While it is possible to 237db96d56Sopenharmony_ci convert the above to something like 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci m = d.__contains__ 267db96d56Sopenharmony_ci if m(k): 277db96d56Sopenharmony_ci ... 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci this is currently not done. 307db96d56Sopenharmony_ci""" 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ci# Local imports 337db96d56Sopenharmony_cifrom .. import pytree 347db96d56Sopenharmony_cifrom .. import fixer_base 357db96d56Sopenharmony_cifrom ..fixer_util import Name, parenthesize 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_ciclass FixHasKey(fixer_base.BaseFix): 397db96d56Sopenharmony_ci BM_compatible = True 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci PATTERN = """ 427db96d56Sopenharmony_ci anchor=power< 437db96d56Sopenharmony_ci before=any+ 447db96d56Sopenharmony_ci trailer< '.' 'has_key' > 457db96d56Sopenharmony_ci trailer< 467db96d56Sopenharmony_ci '(' 477db96d56Sopenharmony_ci ( not(arglist | argument<any '=' any>) arg=any 487db96d56Sopenharmony_ci | arglist<(not argument<any '=' any>) arg=any ','> 497db96d56Sopenharmony_ci ) 507db96d56Sopenharmony_ci ')' 517db96d56Sopenharmony_ci > 527db96d56Sopenharmony_ci after=any* 537db96d56Sopenharmony_ci > 547db96d56Sopenharmony_ci | 557db96d56Sopenharmony_ci negation=not_test< 567db96d56Sopenharmony_ci 'not' 577db96d56Sopenharmony_ci anchor=power< 587db96d56Sopenharmony_ci before=any+ 597db96d56Sopenharmony_ci trailer< '.' 'has_key' > 607db96d56Sopenharmony_ci trailer< 617db96d56Sopenharmony_ci '(' 627db96d56Sopenharmony_ci ( not(arglist | argument<any '=' any>) arg=any 637db96d56Sopenharmony_ci | arglist<(not argument<any '=' any>) arg=any ','> 647db96d56Sopenharmony_ci ) 657db96d56Sopenharmony_ci ')' 667db96d56Sopenharmony_ci > 677db96d56Sopenharmony_ci > 687db96d56Sopenharmony_ci > 697db96d56Sopenharmony_ci """ 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci def transform(self, node, results): 727db96d56Sopenharmony_ci assert results 737db96d56Sopenharmony_ci syms = self.syms 747db96d56Sopenharmony_ci if (node.parent.type == syms.not_test and 757db96d56Sopenharmony_ci self.pattern.match(node.parent)): 767db96d56Sopenharmony_ci # Don't transform a node matching the first alternative of the 777db96d56Sopenharmony_ci # pattern when its parent matches the second alternative 787db96d56Sopenharmony_ci return None 797db96d56Sopenharmony_ci negation = results.get("negation") 807db96d56Sopenharmony_ci anchor = results["anchor"] 817db96d56Sopenharmony_ci prefix = node.prefix 827db96d56Sopenharmony_ci before = [n.clone() for n in results["before"]] 837db96d56Sopenharmony_ci arg = results["arg"].clone() 847db96d56Sopenharmony_ci after = results.get("after") 857db96d56Sopenharmony_ci if after: 867db96d56Sopenharmony_ci after = [n.clone() for n in after] 877db96d56Sopenharmony_ci if arg.type in (syms.comparison, syms.not_test, syms.and_test, 887db96d56Sopenharmony_ci syms.or_test, syms.test, syms.lambdef, syms.argument): 897db96d56Sopenharmony_ci arg = parenthesize(arg) 907db96d56Sopenharmony_ci if len(before) == 1: 917db96d56Sopenharmony_ci before = before[0] 927db96d56Sopenharmony_ci else: 937db96d56Sopenharmony_ci before = pytree.Node(syms.power, before) 947db96d56Sopenharmony_ci before.prefix = " " 957db96d56Sopenharmony_ci n_op = Name("in", prefix=" ") 967db96d56Sopenharmony_ci if negation: 977db96d56Sopenharmony_ci n_not = Name("not", prefix=" ") 987db96d56Sopenharmony_ci n_op = pytree.Node(syms.comp_op, (n_not, n_op)) 997db96d56Sopenharmony_ci new = pytree.Node(syms.comparison, (arg, n_op, before)) 1007db96d56Sopenharmony_ci if after: 1017db96d56Sopenharmony_ci new = parenthesize(new) 1027db96d56Sopenharmony_ci new = pytree.Node(syms.power, (new,) + tuple(after)) 1037db96d56Sopenharmony_ci if node.parent.type in (syms.comparison, syms.expr, syms.xor_expr, 1047db96d56Sopenharmony_ci syms.and_expr, syms.shift_expr, 1057db96d56Sopenharmony_ci syms.arith_expr, syms.term, 1067db96d56Sopenharmony_ci syms.factor, syms.power): 1077db96d56Sopenharmony_ci new = parenthesize(new) 1087db96d56Sopenharmony_ci new.prefix = prefix 1097db96d56Sopenharmony_ci return new 110