1# Copyright 2006 Google, Inc. All Rights Reserved. 2# Licensed to PSF under a Contributor Agreement. 3 4"""Fixer for has_key(). 5 6Calls to .has_key() methods are expressed in terms of the 'in' 7operator: 8 9 d.has_key(k) -> k in d 10 11CAVEATS: 121) 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 162) 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 33from .. import pytree 34from .. import fixer_base 35from ..fixer_util import Name, parenthesize 36 37 38class FixHasKey(fixer_base.BaseFix): 39 BM_compatible = True 40 41 PATTERN = """ 42 anchor=power< 43 before=any+ 44 trailer< '.' 'has_key' > 45 trailer< 46 '(' 47 ( not(arglist | argument<any '=' any>) arg=any 48 | arglist<(not argument<any '=' any>) arg=any ','> 49 ) 50 ')' 51 > 52 after=any* 53 > 54 | 55 negation=not_test< 56 'not' 57 anchor=power< 58 before=any+ 59 trailer< '.' 'has_key' > 60 trailer< 61 '(' 62 ( not(arglist | argument<any '=' any>) arg=any 63 | arglist<(not argument<any '=' any>) arg=any ','> 64 ) 65 ')' 66 > 67 > 68 > 69 """ 70 71 def transform(self, node, results): 72 assert results 73 syms = self.syms 74 if (node.parent.type == syms.not_test and 75 self.pattern.match(node.parent)): 76 # Don't transform a node matching the first alternative of the 77 # pattern when its parent matches the second alternative 78 return None 79 negation = results.get("negation") 80 anchor = results["anchor"] 81 prefix = node.prefix 82 before = [n.clone() for n in results["before"]] 83 arg = results["arg"].clone() 84 after = results.get("after") 85 if after: 86 after = [n.clone() for n in after] 87 if arg.type in (syms.comparison, syms.not_test, syms.and_test, 88 syms.or_test, syms.test, syms.lambdef, syms.argument): 89 arg = parenthesize(arg) 90 if len(before) == 1: 91 before = before[0] 92 else: 93 before = pytree.Node(syms.power, before) 94 before.prefix = " " 95 n_op = Name("in", prefix=" ") 96 if negation: 97 n_not = Name("not", prefix=" ") 98 n_op = pytree.Node(syms.comp_op, (n_not, n_op)) 99 new = pytree.Node(syms.comparison, (arg, n_op, before)) 100 if after: 101 new = parenthesize(new) 102 new = pytree.Node(syms.power, (new,) + tuple(after)) 103 if node.parent.type in (syms.comparison, syms.expr, syms.xor_expr, 104 syms.and_expr, syms.shift_expr, 105 syms.arith_expr, syms.term, 106 syms.factor, syms.power): 107 new = parenthesize(new) 108 new.prefix = prefix 109 return new 110