| # Copyright 2006 Google, Inc. All Rights Reserved. | |
| # Licensed to PSF under a Contributor Agreement. | |
| """Fixer for has_key(). | |
| Calls to .has_key() methods are expressed in terms of the 'in' | |
| operator: | |
| d.has_key(k) -> k in d | |
| CAVEATS: | |
| 1) While the primary target of this fixer is dict.has_key(), the | |
| fixer will change any has_key() method call, regardless of its | |
| class. | |
| 2) Cases like this will not be converted: | |
| m = d.has_key | |
| if m(k): | |
| ... | |
| Only *calls* to has_key() are converted. While it is possible to | |
| convert the above to something like | |
| m = d.__contains__ | |
| if m(k): | |
| ... | |
| this is currently not done. | |
| """ | |
| # Local imports | |
| from .. import pytree | |
| from ..pgen2 import token | |
| from .. import fixer_base | |
| from ..fixer_util import Name, parenthesize | |
| class FixHasKey(fixer_base.BaseFix): | |
| BM_compatible = True | |
| PATTERN = """ | |
| anchor=power< | |
| before=any+ | |
| trailer< '.' 'has_key' > | |
| trailer< | |
| '(' | |
| ( not(arglist | argument<any '=' any>) arg=any | |
| | arglist<(not argument<any '=' any>) arg=any ','> | |
| ) | |
| ')' | |
| > | |
| after=any* | |
| > | |
| | | |
| negation=not_test< | |
| 'not' | |
| anchor=power< | |
| before=any+ | |
| trailer< '.' 'has_key' > | |
| trailer< | |
| '(' | |
| ( not(arglist | argument<any '=' any>) arg=any | |
| | arglist<(not argument<any '=' any>) arg=any ','> | |
| ) | |
| ')' | |
| > | |
| > | |
| > | |
| """ | |
| def transform(self, node, results): | |
| assert results | |
| syms = self.syms | |
| if (node.parent.type == syms.not_test and | |
| self.pattern.match(node.parent)): | |
| # Don't transform a node matching the first alternative of the | |
| # pattern when its parent matches the second alternative | |
| return None | |
| negation = results.get("negation") | |
| anchor = results["anchor"] | |
| prefix = node.prefix | |
| before = [n.clone() for n in results["before"]] | |
| arg = results["arg"].clone() | |
| after = results.get("after") | |
| if after: | |
| after = [n.clone() for n in after] | |
| if arg.type in (syms.comparison, syms.not_test, syms.and_test, | |
| syms.or_test, syms.test, syms.lambdef, syms.argument): | |
| arg = parenthesize(arg) | |
| if len(before) == 1: | |
| before = before[0] | |
| else: | |
| before = pytree.Node(syms.power, before) | |
| before.prefix = u" " | |
| n_op = Name(u"in", prefix=u" ") | |
| if negation: | |
| n_not = Name(u"not", prefix=u" ") | |
| n_op = pytree.Node(syms.comp_op, (n_not, n_op)) | |
| new = pytree.Node(syms.comparison, (arg, n_op, before)) | |
| if after: | |
| new = parenthesize(new) | |
| new = pytree.Node(syms.power, (new,) + tuple(after)) | |
| if node.parent.type in (syms.comparison, syms.expr, syms.xor_expr, | |
| syms.and_expr, syms.shift_expr, | |
| syms.arith_expr, syms.term, | |
| syms.factor, syms.power): | |
| new = parenthesize(new) | |
| new.prefix = prefix | |
| return new |