rustworkx Python
Produce rustworkx code whose graph kind, index lifecycle, payload semantics,
parallel-edge policy, callback contract, and algorithm result mapping are
explicit and tested.
Core object model
| Object |
Meaning |
Use it when |
PyGraph |
Undirected indexed graph. |
Direction does not matter. |
PyDiGraph |
Directed indexed graph. |
Edge orientation matters. |
PyDAG |
Directed graph that checks/prevents cycles according to its contract. |
Acyclicity is an invariant, not merely an algorithm precondition. |
| node index |
Integer handle into graph storage. |
Address topology; never confuse it with payload identity. |
| edge index |
Integer handle for one edge. |
Preserve parallel-edge identity and update/remove exact edges. |
| node/edge payload |
Arbitrary Python object, often called “weight” in APIs. |
Store domain data; it is not automatically an algorithmic cost. |
Indices are stable for the lifetime of an item but are not guaranteed
contiguous; removals leave holes and later insertions may reuse an index. Keep a
domain-ID→node-index mapping when callers identify nodes by business keys. Do
not use list position or enumerate graph.nodes() as an index map. Open
indices, payloads, and ownership for the mapping rules.
Ordered workflow
- State direction, cycle, self-loop, and parallel-edge requirements.
- Define domain identity separately from integer graph indices.
- Choose payload shapes and the callback that converts edge payload to a
numeric cost when an algorithm needs one.
- Build topology while retaining returned indices/mappings.
- Select the exact
graph_* or digraph_* algorithm family and verify its
return type and unreachable-node behavior.
- Translate index-keyed results back to domain IDs only at the public boundary.
- Test removals/holes, parallel edges, direction, missing paths, callback
failures, and equal-cost ambiguity; benchmark only the real workload.
Decision map
- Use
multigraph=False only when at most one edge per endpoint pair is the
domain rule. Adding a duplicate then updates the existing edge payload rather
than preserving another relationship.
- Use edge indices when parallel edges require later provenance or mutation.
- Use
graph_* functions for PyGraph and digraph_* functions for directed
graphs when the API provides type-specific families. Do not guess symmetry.
- Map an arbitrary edge payload to the numeric cost the algorithm expects. For
digraph_dijkstra_shortest_path_lengths, pass edge_cost_fn as the third
positional argument: the documented signature makes it positional-only. A
payload named “weight” can still be a dict, object, or label. Inspect other
algorithm signatures instead of copying this call shape blindly.
- Use conversion only after listing what must survive: domain IDs, graph attrs,
parallel keys, isolated nodes, direction, and payload identity.
- Use rustworkx for measured performance-sensitive graph computation or an
existing rustworkx boundary. Prefer NetworkX when its broader API/ecosystem is
the actual requirement and no performance evidence justifies conversion.
Read operations and algorithms for construction,
result types, mappings, callbacks, conversion, and traversal-control details.
Canonical anchor
from dataclasses import dataclass
import rustworkx as rx
@dataclass(frozen=True)
class Arc:
cost: float
route_id: str
def build_routes(
route_ids: list[str],
arcs: list[tuple[str, str, Arc]],
) -> tuple[rx.PyDiGraph, dict[str, int]]:
graph = rx.PyDiGraph(multigraph=True)
index_by_id = {route_id: graph.add_node(route_id) for route_id in route_ids}
for source, target, arc in arcs:
graph.add_edge(index_by_id[source], index_by_id[target], arc)
return graph, index_by_id
The payload is a domain object; an algorithm must receive lambda arc: arc.cost. The map preserves business identity even if indices have holes.
High-risk rules
- Never serialize or persist node indices as permanent domain IDs unless graph
lifecycle and reuse are explicitly controlled.
- Do not assume
nodes() position equals an index. Use node_indices() and
get_node_data(index) or retained mappings.
- Do not assume removing a node compacts the graph. Test any code that iterates
a numeric range.
- Do not call an algorithm with the payload object where it expects a numeric
edge cost callback. Define missing, negative, and nonfinite cost policies.
- Keep directed predecessor/successor semantics distinct. Do not convert to
undirected just to make an algorithm call succeed.
- In a multigraph, endpoint lookup can return several edges. Preserve/select by
edge index under an explicit rule.
- Callback-heavy algorithms cross the Python boundary; validate callback return
types and benchmark rather than assuming every rustworkx call is faster.
- Conversion from NetworkX can change identity representation and multigraph
details. Assert a semantic round trip, not only node/edge counts.
- Traversal visitors can stop or prune traversal through control exceptions or
return contracts that are version-sensitive. Inspect installed docs.
Version grounding and completion
The official API index currently labels rustworkx 0.18.1. The package is not
installed in the foundry, so that is a documentation baseline only. Check the
installed version with rustworkx.__version__, then inspect graph constructors and the exact algorithm signature
before coding. Read verification.
Completion requires graph-class and index-lifecycle correctness; explicit
payload-to-cost semantics; safe result mapping; tests with holes, parallel
edges, no-path/direction cases, and callbacks; and measured evidence for any
performance claim.
References
- Indices, payloads, and ownership
- Operations and algorithms
- Verification and grounding
1---2name: rustworkx-python3description: Write, review, debug, test, or optimize Python code using the rustworkx graph library, with explicit handling of graph kind, index lifecycle, payload semantics, and algorithm result mapping.4---56# rustworkx Python78Produce rustworkx code whose graph kind, index lifecycle, payload semantics,9parallel-edge policy, callback contract, and algorithm result mapping are10explicit and tested.1112## Core object model1314| Object | Meaning | Use it when |15|---|---|---|16| `PyGraph` | Undirected indexed graph. | Direction does not matter. |17| `PyDiGraph` | Directed indexed graph. | Edge orientation matters. |18| `PyDAG` | Directed graph that checks/prevents cycles according to its contract. | Acyclicity is an invariant, not merely an algorithm precondition. |19| node index | Integer handle into graph storage. | Address topology; never confuse it with payload identity. |20| edge index | Integer handle for one edge. | Preserve parallel-edge identity and update/remove exact edges. |21| node/edge payload | Arbitrary Python object, often called “weight” in APIs. | Store domain data; it is not automatically an algorithmic cost. |2223Indices are stable for the lifetime of an item but are not guaranteed24contiguous; removals leave holes and later insertions may reuse an index. Keep a25domain-ID→node-index mapping when callers identify nodes by business keys. Do26not use list position or enumerate `graph.nodes()` as an index map. Open27[indices, payloads, and ownership](references/object-model.md) for the mapping rules.2829## Ordered workflow30311. State direction, cycle, self-loop, and parallel-edge requirements.322. Define domain identity separately from integer graph indices.333. Choose payload shapes and the callback that converts edge payload to a34 numeric cost when an algorithm needs one.354. Build topology while retaining returned indices/mappings.365. Select the exact `graph_*` or `digraph_*` algorithm family and verify its37 return type and unreachable-node behavior.386. Translate index-keyed results back to domain IDs only at the public boundary.397. Test removals/holes, parallel edges, direction, missing paths, callback40 failures, and equal-cost ambiguity; benchmark only the real workload.4142## Decision map4344- Use `multigraph=False` only when at most one edge per endpoint pair is the45 domain rule. Adding a duplicate then updates the existing edge payload rather46 than preserving another relationship.47- Use edge indices when parallel edges require later provenance or mutation.48- Use `graph_*` functions for `PyGraph` and `digraph_*` functions for directed49 graphs when the API provides type-specific families. Do not guess symmetry.50- Map an arbitrary edge payload to the numeric cost the algorithm expects. For51 `digraph_dijkstra_shortest_path_lengths`, pass `edge_cost_fn` as the third52 positional argument: the documented signature makes it positional-only. A53 payload named “weight” can still be a dict, object, or label. Inspect other54 algorithm signatures instead of copying this call shape blindly.55- Use conversion only after listing what must survive: domain IDs, graph attrs,56 parallel keys, isolated nodes, direction, and payload identity.57- Use rustworkx for measured performance-sensitive graph computation or an58 existing rustworkx boundary. Prefer NetworkX when its broader API/ecosystem is59 the actual requirement and no performance evidence justifies conversion.6061Read [operations and algorithms](references/operations.md) for construction,62result types, mappings, callbacks, conversion, and traversal-control details.6364## Canonical anchor6566```python67from dataclasses import dataclass6869import rustworkx as rx707172@dataclass(frozen=True)73class Arc:74 cost: float75 route_id: str767778def build_routes(79 route_ids: list[str],80 arcs: list[tuple[str, str, Arc]],81) -> tuple[rx.PyDiGraph, dict[str, int]]:82 graph = rx.PyDiGraph(multigraph=True)83 index_by_id = {route_id: graph.add_node(route_id) for route_id in route_ids}84 for source, target, arc in arcs:85 graph.add_edge(index_by_id[source], index_by_id[target], arc)86 return graph, index_by_id87```8889The payload is a domain object; an algorithm must receive `lambda arc:90arc.cost`. The map preserves business identity even if indices have holes.9192## High-risk rules9394- Never serialize or persist node indices as permanent domain IDs unless graph95 lifecycle and reuse are explicitly controlled.96- Do not assume `nodes()` position equals an index. Use `node_indices()` and97 `get_node_data(index)` or retained mappings.98- Do not assume removing a node compacts the graph. Test any code that iterates99 a numeric range.100- Do not call an algorithm with the payload object where it expects a numeric101 edge cost callback. Define missing, negative, and nonfinite cost policies.102- Keep directed predecessor/successor semantics distinct. Do not convert to103 undirected just to make an algorithm call succeed.104- In a multigraph, endpoint lookup can return several edges. Preserve/select by105 edge index under an explicit rule.106- Callback-heavy algorithms cross the Python boundary; validate callback return107 types and benchmark rather than assuming every rustworkx call is faster.108- Conversion from NetworkX can change identity representation and multigraph109 details. Assert a semantic round trip, not only node/edge counts.110- Traversal visitors can stop or prune traversal through control exceptions or111 return contracts that are version-sensitive. Inspect installed docs.112113## Version grounding and completion114115The official API index currently labels rustworkx 0.18.1. The package is not116installed in the foundry, so that is a documentation baseline only. Check the117installed version with `rustworkx.__version__`, then inspect graph constructors and the exact algorithm signature118before coding. Read [verification](references/verification.md).119120Completion requires graph-class and index-lifecycle correctness; explicit121payload-to-cost semantics; safe result mapping; tests with holes, parallel122edges, no-path/direction cases, and callbacks; and measured evidence for any123performance claim.124125## References126127- [Indices, payloads, and ownership](references/object-model.md)128- [Operations and algorithms](references/operations.md)129- [Verification and grounding](references/verification.md)