walker.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # -*- coding: utf-8 -*-
  2. class Walker(object):
  3. def __init__(self):
  4. """Walk from one node to another."""
  5. super(Walker, self).__init__()
  6. def walk(self, start, end):
  7. """
  8. Walk from `start` node to `end` node.
  9. Returns:
  10. (upwards, common, downwards): `upwards` is a list of nodes to go upward to.
  11. `common` top node. `downwards` is a list of nodes to go downward to.
  12. Raises:
  13. WalkError: on no common root node.
  14. Example:
  15. >>> from anytree import Node, RenderTree, AsciiStyle
  16. >>> f = Node("f")
  17. >>> b = Node("b", parent=f)
  18. >>> a = Node("a", parent=b)
  19. >>> d = Node("d", parent=b)
  20. >>> c = Node("c", parent=d)
  21. >>> e = Node("e", parent=d)
  22. >>> g = Node("g", parent=f)
  23. >>> i = Node("i", parent=g)
  24. >>> h = Node("h", parent=i)
  25. >>> print(RenderTree(f, style=AsciiStyle()))
  26. Node('/f')
  27. |-- Node('/f/b')
  28. | |-- Node('/f/b/a')
  29. | +-- Node('/f/b/d')
  30. | |-- Node('/f/b/d/c')
  31. | +-- Node('/f/b/d/e')
  32. +-- Node('/f/g')
  33. +-- Node('/f/g/i')
  34. +-- Node('/f/g/i/h')
  35. Create a walker:
  36. >>> w = Walker()
  37. This class is made for walking:
  38. >>> w.walk(f, f)
  39. ((), Node('/f'), ())
  40. >>> w.walk(f, b)
  41. ((), Node('/f'), (Node('/f/b'),))
  42. >>> w.walk(b, f)
  43. ((Node('/f/b'),), Node('/f'), ())
  44. >>> w.walk(h, e)
  45. ((Node('/f/g/i/h'), Node('/f/g/i'), Node('/f/g')), Node('/f'), (Node('/f/b'), Node('/f/b/d'), Node('/f/b/d/e')))
  46. >>> w.walk(d, e)
  47. ((), Node('/f/b/d'), (Node('/f/b/d/e'),))
  48. For a proper walking the nodes need to be part of the same tree:
  49. >>> w.walk(Node("a"), Node("b"))
  50. Traceback (most recent call last):
  51. ...
  52. anytree.walker.WalkError: Node('/a') and Node('/b') are not part of the same tree.
  53. """
  54. s = start.path
  55. e = end.path
  56. if start.root is not end.root:
  57. msg = "%r and %r are not part of the same tree." % (start, end)
  58. raise WalkError(msg)
  59. # common
  60. c = Walker.__calc_common(s, e)
  61. assert c[0] is start.root
  62. len_c = len(c)
  63. # up
  64. if start is c[-1]:
  65. up = tuple()
  66. else:
  67. up = tuple(reversed(s[len_c:]))
  68. # down
  69. if end is c[-1]:
  70. down = tuple()
  71. else:
  72. down = e[len_c:]
  73. return up, c[-1], down
  74. @staticmethod
  75. def __calc_common(s, e):
  76. return tuple([si for si, ei in zip(s, e) if si is ei])
  77. class WalkError(RuntimeError):
  78. """Walk Error."""