blob: 18c560fd850fc14977656f9344d88c8b27e747c7 [file] [log] [blame]
Martin v. Löwisef04c442008-03-19 05:04:44 +00001# 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 ...
Martin v. Löwisf733c602008-03-19 05:26:18 +000021
Martin v. Löwisef04c442008-03-19 05:04:44 +000022 Only *calls* to has_key() are converted. While it is possible to
23 convert the above to something like
Martin v. Löwisf733c602008-03-19 05:26:18 +000024
Martin v. Löwisef04c442008-03-19 05:04:44 +000025 m = d.__contains__
26 if m(k):
27 ...
Martin v. Löwisf733c602008-03-19 05:26:18 +000028
Martin v. Löwisef04c442008-03-19 05:04:44 +000029 this is currently not done.
30"""
31
32# Local imports
33from .. import pytree
34from ..pgen2 import token
Benjamin Petersondf6dc8f2008-06-15 02:57:40 +000035from .. import fixer_base
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +000036from ..fixer_util import Name, parenthesize
Martin v. Löwisef04c442008-03-19 05:04:44 +000037
38
Benjamin Petersondf6dc8f2008-06-15 02:57:40 +000039class FixHasKey(fixer_base.BaseFix):
Benjamin Petersonf37eb3a2010-10-14 23:00:04 +000040 BM_compatible = True
Martin v. Löwisef04c442008-03-19 05:04:44 +000041
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"]
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000082 prefix = node.prefix
Martin v. Löwisef04c442008-03-19 05:04:44 +000083 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):
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +000090 arg = parenthesize(arg)
Martin v. Löwisef04c442008-03-19 05:04:44 +000091 if len(before) == 1:
92 before = before[0]
93 else:
94 before = pytree.Node(syms.power, before)
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000095 before.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +000096 n_op = Name("in", prefix=" ")
97 if negation:
98 n_not = Name("not", prefix=" ")
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:
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000102 new = parenthesize(new)
Martin v. Löwisef04c442008-03-19 05:04:44 +0000103 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):
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000108 new = parenthesize(new)
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +0000109 new.prefix = prefix
Martin v. Löwisef04c442008-03-19 05:04:44 +0000110 return new