fix_has_key.py 3.1 KB

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