10 |
10 |
11 class RecursionError(OverflowError, ValueError): |
11 class RecursionError(OverflowError, ValueError): |
12 """ |
12 """ |
13 Unable to calculate result because of recursive structure. |
13 Unable to calculate result because of recursive structure. |
14 """ |
14 """ |
|
15 |
15 pass |
16 pass |
16 |
17 |
17 |
18 |
18 def sort(nodes, routes, noRecursion=False): |
19 def sort(nodes, routes, noRecursion=False): |
19 """ |
20 """ |
20 Function to sort widgets topographically. |
21 Function to sort widgets topographically. |
21 |
22 |
22 Passed a list of nodes and a list of source, dest routes, it attempts |
23 Passed a list of nodes and a list of source, dest routes, it attempts |
23 to create a list of stages, where each sub list is one stage in a process. |
24 to create a list of stages, where each sub list is one stage in a process. |
24 |
25 |
25 The algorithm was taken from Boa Constructor. |
26 The algorithm was taken from Boa Constructor. |
26 |
27 |
27 @param nodes list of nodes to be sorted |
28 @param nodes list of nodes to be sorted |
28 @type str |
29 @type str |
29 @param routes list of routes between the nodes |
30 @param routes list of routes between the nodes |
30 @type list of tuple of (str, str) |
31 @type list of tuple of (str, str) |
31 @param noRecursion flag indicating, if recursion errors should be raised |
32 @param noRecursion flag indicating, if recursion errors should be raised |
33 @return list of stages |
34 @return list of stages |
34 @rtype list of lists of str |
35 @rtype list of lists of str |
35 @exception RecursionError a recursion error was detected |
36 @exception RecursionError a recursion error was detected |
36 """ |
37 """ |
37 children, parents = _buildChildrenLists(routes) |
38 children, parents = _buildChildrenLists(routes) |
38 |
39 |
39 # first stage is those nodes having no incoming routes... |
40 # first stage is those nodes having no incoming routes... |
40 stage = [] |
41 stage = [] |
41 stages = [stage] |
42 stages = [stage] |
42 taken = [] |
43 taken = [] |
43 for node in nodes: |
44 for node in nodes: |
44 if not parents.get(node): |
45 if not parents.get(node): |
45 stage.append(node) |
46 stage.append(node) |
46 |
47 |
47 if nodes and not stage: |
48 if nodes and not stage: |
48 # there is no element, which does not depend on some other element! |
49 # there is no element, which does not depend on some other element! |
49 stage.append(nodes[0]) |
50 stage.append(nodes[0]) |
50 |
51 |
51 taken.extend(stage) |
52 taken.extend(stage) |
52 nodes = list(filter(lambda x, li=stage: x not in li, nodes)) |
53 nodes = list(filter(lambda x, li=stage: x not in li, nodes)) |
53 while nodes: |
54 while nodes: |
54 previousStageChildren = [] |
55 previousStageChildren = [] |
55 nodelen = len(nodes) |
56 nodelen = len(nodes) |
56 |
57 |
57 # second stage are those nodes, which are direct children of the |
58 # second stage are those nodes, which are direct children of the |
58 # first stage |
59 # first stage |
59 for node in stage: |
60 for node in stage: |
60 for child in children.get(node, []): |
61 for child in children.get(node, []): |
61 if child not in previousStageChildren and child not in taken: |
62 if child not in previousStageChildren and child not in taken: |
62 previousStageChildren.append(child) |
63 previousStageChildren.append(child) |
63 elif child in taken and noRecursion: |
64 elif child in taken and noRecursion: |
64 raise RecursionError((child, node)) |
65 raise RecursionError((child, node)) |
65 |
66 |
66 # unless they are children of other direct children... |
67 # unless they are children of other direct children... |
67 stage = previousStageChildren |
68 stage = previousStageChildren |
68 removes = [] |
69 removes = [] |
69 for current in stage: |
70 for current in stage: |
70 currentParents = parents.get(current, []) |
71 currentParents = parents.get(current, []) |
71 for parent in currentParents: |
72 for parent in currentParents: |
72 if ( |
73 if ( |
73 parent in stage and |
74 parent in stage |
74 parent != current and |
75 and parent != current |
75 current not in parents.get(parent, []) |
76 and current not in parents.get(parent, []) |
76 ): |
77 ): |
77 # is not mutually dependant |
78 # is not mutually dependant |
78 removes.append(current) |
79 removes.append(current) |
79 |
80 |
80 for remove in removes: |
81 for remove in removes: |
81 while remove in stage: |
82 while remove in stage: |
82 stage.remove(remove) |
83 stage.remove(remove) |
83 |
84 |
84 stages.append(stage) |
85 stages.append(stage) |
85 taken.extend(stage) |
86 taken.extend(stage) |
86 nodes = list(filter(lambda x, li=stage: x not in li, nodes)) |
87 nodes = list(filter(lambda x, li=stage: x not in li, nodes)) |
87 if nodelen == len(nodes): |
88 if nodelen == len(nodes): |
88 if noRecursion: |
89 if noRecursion: |
89 raise RecursionError(nodes) |
90 raise RecursionError(nodes) |
90 else: |
91 else: |
91 stages.append(nodes[:]) |
92 stages.append(nodes[:]) |
92 nodes = [] |
93 nodes = [] |
93 |
94 |
94 return stages |
95 return stages |
95 |
96 |
96 |
97 |
97 def _buildChildrenLists(routes): |
98 def _buildChildrenLists(routes): |
98 """ |
99 """ |
99 Function to build up parent - child relationships. |
100 Function to build up parent - child relationships. |
100 |
101 |
101 Taken from Boa Constructor. |
102 Taken from Boa Constructor. |
102 |
103 |
103 @param routes list of routes between nodes |
104 @param routes list of routes between nodes |
104 @type list of tuple of (str, str) |
105 @type list of tuple of (str, str) |
105 @return dictionary of child and dictionary of parent relationships |
106 @return dictionary of child and dictionary of parent relationships |
106 @rtype tuple of (dict, dict) |
107 @rtype tuple of (dict, dict) |
107 """ |
108 """ |