fix_metaclass.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. u"""
  2. Fixer for (metaclass=X) -> __metaclass__ = X
  3. Some semantics (see PEP 3115) may be altered in the translation."""
  4. from lib2to3 import fixer_base
  5. from lib2to3.fixer_util import Name, syms, Node, Leaf, Newline, find_root
  6. from lib2to3.pygram import token
  7. from libfuturize.fixer_util import indentation, suitify
  8. # from ..fixer_util import Name, syms, Node, Leaf, Newline, find_root, indentation, suitify
  9. def has_metaclass(parent):
  10. results = None
  11. for node in parent.children:
  12. kids = node.children
  13. if node.type == syms.argument:
  14. if kids[0] == Leaf(token.NAME, u"metaclass") and \
  15. kids[1] == Leaf(token.EQUAL, u"=") and \
  16. kids[2]:
  17. #Hack to avoid "class X(=):" with this case.
  18. results = [node] + kids
  19. break
  20. elif node.type == syms.arglist:
  21. # Argument list... loop through it looking for:
  22. # Node(*, [*, Leaf(token.NAME, u"metaclass"), Leaf(token.EQUAL, u"="), Leaf(*, *)]
  23. for child in node.children:
  24. if results: break
  25. if child.type == token.COMMA:
  26. #Store the last comma, which precedes the metaclass
  27. comma = child
  28. elif type(child) == Node:
  29. meta = equal = name = None
  30. for arg in child.children:
  31. if arg == Leaf(token.NAME, u"metaclass"):
  32. #We have the (metaclass) part
  33. meta = arg
  34. elif meta and arg == Leaf(token.EQUAL, u"="):
  35. #We have the (metaclass=) part
  36. equal = arg
  37. elif meta and equal:
  38. #Here we go, we have (metaclass=X)
  39. name = arg
  40. results = (comma, meta, equal, name)
  41. break
  42. return results
  43. class FixMetaclass(fixer_base.BaseFix):
  44. PATTERN = u"""
  45. classdef<any*>
  46. """
  47. def transform(self, node, results):
  48. meta_results = has_metaclass(node)
  49. if not meta_results: return
  50. for meta in meta_results:
  51. meta.remove()
  52. target = Leaf(token.NAME, u"__metaclass__")
  53. equal = Leaf(token.EQUAL, u"=", prefix=u" ")
  54. # meta is the last item in what was returned by has_metaclass(): name
  55. name = meta
  56. name.prefix = u" "
  57. stmt_node = Node(syms.atom, [target, equal, name])
  58. suitify(node)
  59. for item in node.children:
  60. if item.type == syms.suite:
  61. for stmt in item.children:
  62. if stmt.type == token.INDENT:
  63. # Insert, in reverse order, the statement, a newline,
  64. # and an indent right after the first indented line
  65. loc = item.children.index(stmt) + 1
  66. # Keep consistent indentation form
  67. ident = Leaf(token.INDENT, stmt.value)
  68. item.insert_child(loc, ident)
  69. item.insert_child(loc, Newline())
  70. item.insert_child(loc, stmt_node)
  71. break