-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTreeWalker.py
67 lines (50 loc) · 2.41 KB
/
TreeWalker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class TreeWalker:
""" Walks the node tree rooted at given node """
def __init__(self, node, get_children = lambda node: node.all_children(0), cycle_func = lambda node, parent: None):
self.root_node = node
self.get_children = get_children
self.cycle_func = cycle_func
self.reset()
def reset(self):
""" Re-start the tree walk, beginning with the root node passed to the constructor. """
children = self.get_children(self.root_node) if self.root_node else [ ]
if children:
self.node_stack = [ children[:] ]
self.parent_stack = [ self.root_node ]
else:
self.node_stack = [ ]
self.parent_stack = [ ]
self.history = [ ]
def is_done(self):
""" Check if all child nodes have been traversed. """
return not self.node_stack
def __nonzero__(self):
""" Check if there are still child nodes to be traversed. """
return not not self.node_stack
def next_child(self):
"""
Return the next child node, together in a tuple with its immediate parent, from the node tree rooted at the initial
root node. Child nodes are traversed in depth order, but parents are enumerated before their children.
The root node itself is not returned; it will appear as the immediate parent in the tuple for the first child node,
if any.
A history of previously returned nodes is kept internally and consulted for each new node to be returned, to prevent
an infinite loop when traversing a dependency cycle.
Returns (None, None) after all children have been traversed, or if there are no children in the given root node.
"""
if self.node_stack:
parent = self.parent_stack[-1]
node = self.node_stack[-1].pop(0)
if not self.node_stack[-1]:
self.node_stack.pop()
self.parent_stack.pop()
if node not in self.history:
self.history.append(node)
children = self.get_children(node)
if children:
self.node_stack.append(children[:])
self.parent_stack.append(node)
return node, parent
else:
self.cycle_func(node, parent)
return self.next_child()
return None, None