-
-
Notifications
You must be signed in to change notification settings - Fork 524
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add progress spinner to parallel and dependencies
- Loading branch information
1 parent
64983d4
commit 4660bef
Showing
8 changed files
with
327 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from collections import OrderedDict, defaultdict | ||
|
||
|
||
def stable_topological_sort(graph): | ||
to_order = set(graph.keys()) # keep a log of what we need to order | ||
|
||
# normalize graph - fill missing nodes (assume no dependency) | ||
for values in graph.values(): | ||
for value in values: | ||
if value not in graph: | ||
graph[value] = tuple() | ||
|
||
inverse_graph = defaultdict(set) | ||
for key, depends in graph.items(): | ||
for depend in depends: | ||
inverse_graph[depend].add(key) | ||
|
||
topology = [] | ||
degree = {k: len(v) for k, v in graph.items()} | ||
ready_to_visit = {n for n, d in degree.items() if not d} | ||
need_to_visit = OrderedDict((i, None) for i in graph.keys()) | ||
while need_to_visit: | ||
# to keep stable, pick the first node ready to visit in the original order | ||
for node in need_to_visit: | ||
if node in ready_to_visit: | ||
break | ||
else: | ||
break | ||
del need_to_visit[node] | ||
|
||
topology.append(node) | ||
|
||
# decrease degree for nodes we're going too | ||
for to_node in inverse_graph[node]: | ||
degree[to_node] -= 1 | ||
if not degree[to_node]: # if a node has no more incoming node it's ready to visit | ||
ready_to_visit.add(to_node) | ||
|
||
result = [n for n in topology if n in to_order] # filter out missing nodes we extended | ||
|
||
if len(result) < len(to_order): | ||
identify_cycle(graph) | ||
raise ValueError("could not order tox environments and failed to detect circle") | ||
return result | ||
|
||
|
||
def identify_cycle(graph): | ||
path = set() | ||
visited = set() | ||
|
||
def visit(vertex): | ||
if vertex in visited: | ||
return None | ||
visited.add(vertex) | ||
path.add(vertex) | ||
for neighbour in graph.get(vertex, ()): | ||
if neighbour in path or visit(neighbour): | ||
return path | ||
path.remove(vertex) | ||
return None | ||
|
||
for node in graph: | ||
result = visit(node) | ||
if result is not None: | ||
raise ValueError(" | ".join(result)) |
Oops, something went wrong.