1 # Copyright 2006 Google, Inc. All Rights Reserved. 2 # Licensed to PSF under a Contributor Agreement. 3 4 """Fixer for has_key(). 5 6 Calls to .has_key() methods are expressed in terms of the 'in' 7 operator: 8 9 d.has_key(k) -> k in d 10 11 CAVEATS: 12 1) While the primary target of this fixer is dict.has_key(), the 13 fixer will change any has_key() method call, regardless of its 14 class. 15 16 2) Cases like this will not be converted: 17 18 m = d.has_key 19 if m(k): 20 ... 21 22 Only *calls* to has_key() are converted. While it is possible to 23 convert the above to something like 24 25 m = d.__contains__ 26 if m(k): 27 ... 28 29 this is currently not done. 30 """ 31 32 # Local imports 33 from .. import pytree 34 from ..pgen2 import token 35 from .. import fixer_base 36 from ..fixer_util import Name, parenthesize 37 38 39 class FixHasKey(fixer_base.BaseFix): 40 BM_compatible = True 41 42 PATTERN = """ 43 anchor=power< 44 before=any+ 45 trailer< '.' 'has_key' > 46 trailer< 47 '(' 48 ( not(arglist | argument<any '=' any>) arg=any 49 | arglist<(not argument<any '=' any>) arg=any ','> 50 ) 51 ')' 52 > 53 after=any* 54 > 55 | 56 negation=not_test< 57 'not' 58 anchor=power< 59 before=any+ 60 trailer< '.' 'has_key' > 61 trailer< 62 '(' 63 ( not(arglist | argument<any '=' any>) arg=any 64 | arglist<(not argument<any '=' any>) arg=any ','> 65 ) 66 ')' 67 > 68 > 69 > 70 """ 71 72 def transform(self, node, results): 73 assert results 74 syms = self.syms 75 if (node.parent.type == syms.not_test and 76 self.pattern.match(node.parent)): 77 # Don't transform a node matching the first alternative of the 78 # pattern when its parent matches the second alternative 79 return None 80 negation = results.get("negation") 81 anchor = results["anchor"] 82 prefix = node.prefix 83 before = [n.clone() for n in results["before"]] 84 arg = results["arg"].clone() 85 after = results.get("after") 86 if after: 87 after = [n.clone() for n in after] 88 if arg.type in (syms.comparison, syms.not_test, syms.and_test, 89 syms.or_test, syms.test, syms.lambdef, syms.argument): 90 arg = parenthesize(arg) 91 if len(before) == 1: 92 before = before[0] 93 else: 94 before = pytree.Node(syms.power, before) 95 before.prefix = u" " 96 n_op = Name(u"in", prefix=u" ") 97 if negation: 98 n_not = Name(u"not", prefix=u" ") 99 n_op = pytree.Node(syms.comp_op, (n_not, n_op)) 100 new = pytree.Node(syms.comparison, (arg, n_op, before)) 101 if after: 102 new = parenthesize(new) 103 new = pytree.Node(syms.power, (new,) + tuple(after)) 104 if node.parent.type in (syms.comparison, syms.expr, syms.xor_expr, 105 syms.and_expr, syms.shift_expr, 106 syms.arith_expr, syms.term, 107 syms.factor, syms.power): 108 new = parenthesize(new) 109 new.prefix = prefix 110 return new 111