Perform a topological sort on a dependency graph. Args: graph: A dependency graph represented as adjacency lists (node -> set of dependencies) Returns: A list of nodes in topological order (dependencies first)
(graph: Dict[str, Set[str]])
| 119 | return new_graph |
| 120 | |
| 121 | def topological_sort(graph: Dict[str, Set[str]]) -> List[str]: |
| 122 | """ |
| 123 | Perform a topological sort on a dependency graph. |
| 124 | |
| 125 | Args: |
| 126 | graph: A dependency graph represented as adjacency lists |
| 127 | (node -> set of dependencies) |
| 128 | |
| 129 | Returns: |
| 130 | A list of nodes in topological order (dependencies first) |
| 131 | """ |
| 132 | # First, check for and resolve cycles |
| 133 | acyclic_graph = resolve_cycles(graph) |
| 134 | |
| 135 | # Initialize in-degree counter for all nodes |
| 136 | in_degree = {node: 0 for node in acyclic_graph} |
| 137 | |
| 138 | # Count in-degrees |
| 139 | for node, dependencies in acyclic_graph.items(): |
| 140 | for dep in dependencies: |
| 141 | if dep in in_degree: |
| 142 | in_degree[dep] += 1 |
| 143 | |
| 144 | # Queue of nodes with no dependencies (in-degree of 0) |
| 145 | queue = deque([node for node, degree in in_degree.items() if degree == 0]) |
| 146 | |
| 147 | # Result list to store the topological order |
| 148 | result = [] |
| 149 | |
| 150 | # Process nodes in topological order |
| 151 | while queue: |
| 152 | node = queue.popleft() |
| 153 | result.append(node) |
| 154 | |
| 155 | # Reduce in-degree for each node that depends on the current node |
| 156 | for dependent, deps in acyclic_graph.items(): |
| 157 | if node in deps: |
| 158 | in_degree[dependent] -= 1 |
| 159 | if in_degree[dependent] == 0: |
| 160 | queue.append(dependent) |
| 161 | |
| 162 | # Check if the sort was successful (all nodes included) |
| 163 | if len(result) != len(acyclic_graph): |
| 164 | logger.warning("Topological sort failed: graph has cycles that weren't resolved") |
| 165 | # Return all nodes in some order to avoid breaking the process |
| 166 | return list(acyclic_graph.keys()) |
| 167 | |
| 168 | # Reverse the result to get dependencies first |
| 169 | return result[::-1] |
| 170 | |
| 171 | def dependency_first_dfs(graph: Dict[str, Set[str]]) -> List[str]: |
| 172 | """ |
nothing calls this directly
no test coverage detected