mirror of
https://github.com/safishamsi/graphify.git
synced 2026-11-01 11:37:25 +00:00
fix(export): export GraphML from a graph loaded as a MultiGraph
Since #4500, graph.json carries "multigraph": true whenever it holds parallel edges (imports and calls between the same pair, say), and graphify export loads it as a MultiGraph. to_graphml's attribute coercion indexed edges as H.edges[u, v], which needs a key on a MultiGraph, so graphify export graphml crashed with "not enough values to unpack" and wrote nothing. Iterate edges(data=True) instead, which works for both graph types and keeps every parallel edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8d39c75d02
commit
ffa5a6b051
2 files changed
+30
-3
No files matched your search
+6
-3
@@ -1346,9 +1346,12 @@ def to_graphml(
|
||||
for node_id in H.nodes():
|
||||
for key, val in list(H.nodes[node_id].items()):
|
||||
H.nodes[node_id][key] = _graphml_safe(val)
|
||||
for u, v in H.edges():
|
||||
for key, val in list(H.edges[u, v].items()):
|
||||
H.edges[u, v][key] = _graphml_safe(val)
|
||||
# edges(data=True) rather than H.edges[u, v]: graph.json is loaded as a
|
||||
# MultiGraph when it carries parallel edges (#4500), and a MultiGraph edge
|
||||
# view needs a key, so the (u, v) form crashed the whole export.
|
||||
for *_, attrs in H.edges(data=True):
|
||||
for key, val in list(attrs.items()):
|
||||
attrs[key] = _graphml_safe(val)
|
||||
|
||||
# Write atomically: a mid-serialization error otherwise leaves a 0-byte
|
||||
# .graphml on disk that downstream tooling mistakes for a completed export
|
||||
|
||||
@@ -282,6 +282,30 @@ def test_to_graphml_tolerates_dict_and_list_attribute_values():
|
||||
assert not (Path(tmp) / "graph.graphml.tmp").exists()
|
||||
|
||||
|
||||
def test_to_graphml_exports_multigraph_parallel_edges():
|
||||
"""graph.json is loaded as a MultiGraph when it carries parallel edges
|
||||
(#4500), e.g. `imports` and `calls` between the same two nodes. The edge
|
||||
coercion loop indexed H.edges[u, v], which needs a key on a MultiGraph, so
|
||||
the export crashed; every parallel edge must reach the file, coerced."""
|
||||
import networkx as nx
|
||||
G = nx.MultiGraph()
|
||||
G.add_node("a", label="A")
|
||||
G.add_node("b", label="B")
|
||||
G.add_edge("a", "b", relation="imports", confidence="EXTRACTED", note=None)
|
||||
G.add_edge("a", "b", relation="calls", confidence="INFERRED", ctx={"k": "v"})
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
out = Path(tmp) / "g.graphml"
|
||||
to_graphml(G, {0: ["a", "b"]}, str(out))
|
||||
H = nx.read_graphml(str(out))
|
||||
assert H.number_of_edges() == 2
|
||||
edges = [d for _, _, d in H.edges(data=True)]
|
||||
assert sorted(d["relation"] for d in edges) == ["calls", "imports"]
|
||||
calls = next(d for d in edges if d["relation"] == "calls")
|
||||
imports = next(d for d in edges if d["relation"] == "imports")
|
||||
assert json.loads(calls["ctx"]) == {"k": "v"}
|
||||
assert imports["note"] == ""
|
||||
|
||||
|
||||
def test_to_graphml_preserves_native_scalar_types():
|
||||
"""Coercion must leave GraphML-native scalars (int/float/bool/str) untouched,
|
||||
only stringifying non-scalars (#1831)."""
|
||||
|
||||
Reference in new issue
Block a user