graphlib-backport
Backport of the Python 3.9 `graphlib` module for Python 3.6+. It provides the `TopologicalSorter` class for performing topological sorting on directed acyclic graphs (DAGs). The library is currently at version 1.1.0 and is actively maintained, with releases tied to updates on its GitHub repository.
Warnings
- gotcha When installed on Python versions 3.9 or higher, the native `graphlib` module (which includes `TopologicalSorter`) will take precedence if you try to import directly as `import graphlib`. It is generally recommended to limit installation of `graphlib-backport` to Python versions `<3.9` and use the standard library's `graphlib` for Python `>=3.9`.
- deprecated Explicit support for Python 3.6 and 3.7 is considered 'somewhat experimental' and is slated to be dropped, as these Python versions have reached their official end-of-life status.
- gotcha The PyPI package name for installation is `graphlib-backport` (with a hyphen), but the Python import name within your code is `graphlib_backport` (with an underscore). Attempting `import graphlib-backport` will result in a `ModuleNotFoundError`.
Install
-
pip install graphlib-backport
Imports
- TopologicalSorter
from graphlib import TopologicalSorter
from graphlib_backport import TopologicalSorter
Quickstart
from graphlib_backport import TopologicalSorter
# Example graph: keys are nodes, values are sets of predecessors
graph = {"D": {"B", "C"}, "C": {"A"}, "B": {"A"}, "A": set()}
ts = TopologicalSorter(graph)
# Get the nodes in topological order using static_order (convenience method)
order = list(ts.static_order())
print(f"Topological order (static): {order}")
# Example with dynamic processing (simulating parallel work)
print("\nProcessing nodes dynamically:")
ts_dynamic = TopologicalSorter(graph)
ts_dynamic.prepare() # Must be called before is_active, get_ready, or done
processed_nodes = []
while ts_dynamic.is_active():
ready_nodes = ts_dynamic.get_ready()
if ready_nodes:
print(f" Ready to process: {ready_nodes}")
# Simulate processing for each ready node
for node in ready_nodes:
processed_nodes.append(node)
ts_dynamic.done(*ready_nodes) # Mark nodes as done to unblock successors
else:
# This branch should not be reached in a valid DAG if is_active is true
# unless there's an unexpected state (e.g., cycle detected after prepare, or bug).
print(" No nodes ready, but sorter is active. Potential issue or cycle?")
break
print(f"Dynamic processing complete. Order: {processed_nodes}")