Spaces:
Running
Running
File size: 9,045 Bytes
b200bda |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
"""Unit tests for PyGraphviz interface."""
import os
import tempfile
import pytest
pygraphviz = pytest.importorskip("pygraphviz")
import networkx as nx
from networkx.utils import edges_equal, graphs_equal, nodes_equal
class TestAGraph:
def build_graph(self, G):
edges = [("A", "B"), ("A", "C"), ("A", "C"), ("B", "C"), ("A", "D")]
G.add_edges_from(edges)
G.add_node("E")
G.graph["metal"] = "bronze"
return G
def assert_equal(self, G1, G2):
assert nodes_equal(G1.nodes(), G2.nodes())
assert edges_equal(G1.edges(), G2.edges())
assert G1.graph["metal"] == G2.graph["metal"]
def agraph_checks(self, G):
G = self.build_graph(G)
A = nx.nx_agraph.to_agraph(G)
H = nx.nx_agraph.from_agraph(A)
self.assert_equal(G, H)
fd, fname = tempfile.mkstemp()
nx.drawing.nx_agraph.write_dot(H, fname)
Hin = nx.nx_agraph.read_dot(fname)
self.assert_equal(H, Hin)
os.close(fd)
os.unlink(fname)
(fd, fname) = tempfile.mkstemp()
with open(fname, "w") as fh:
nx.drawing.nx_agraph.write_dot(H, fh)
with open(fname) as fh:
Hin = nx.nx_agraph.read_dot(fh)
os.close(fd)
os.unlink(fname)
self.assert_equal(H, Hin)
def test_from_agraph_name(self):
G = nx.Graph(name="test")
A = nx.nx_agraph.to_agraph(G)
H = nx.nx_agraph.from_agraph(A)
assert G.name == "test"
@pytest.mark.parametrize(
"graph_class", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
)
def test_from_agraph_create_using(self, graph_class):
G = nx.path_graph(3)
A = nx.nx_agraph.to_agraph(G)
H = nx.nx_agraph.from_agraph(A, create_using=graph_class)
assert isinstance(H, graph_class)
def test_from_agraph_named_edges(self):
# Create an AGraph from an existing (non-multi) Graph
G = nx.Graph()
G.add_nodes_from([0, 1])
A = nx.nx_agraph.to_agraph(G)
# Add edge (+ name, given by key) to the AGraph
A.add_edge(0, 1, key="foo")
# Verify a.name roundtrips out to 'key' in from_agraph
H = nx.nx_agraph.from_agraph(A)
assert isinstance(H, nx.Graph)
assert ("0", "1", {"key": "foo"}) in H.edges(data=True)
def test_undirected(self):
self.agraph_checks(nx.Graph())
def test_directed(self):
self.agraph_checks(nx.DiGraph())
def test_multi_undirected(self):
self.agraph_checks(nx.MultiGraph())
def test_multi_directed(self):
self.agraph_checks(nx.MultiDiGraph())
def test_to_agraph_with_nodedata(self):
G = nx.Graph()
G.add_node(1, color="red")
A = nx.nx_agraph.to_agraph(G)
assert dict(A.nodes()[0].attr) == {"color": "red"}
@pytest.mark.parametrize("graph_class", (nx.Graph, nx.MultiGraph))
def test_to_agraph_with_edgedata(self, graph_class):
G = graph_class()
G.add_nodes_from([0, 1])
G.add_edge(0, 1, color="yellow")
A = nx.nx_agraph.to_agraph(G)
assert dict(A.edges()[0].attr) == {"color": "yellow"}
def test_view_pygraphviz_path(self, tmp_path):
G = nx.complete_graph(3)
input_path = str(tmp_path / "graph.png")
out_path, A = nx.nx_agraph.view_pygraphviz(G, path=input_path, show=False)
assert out_path == input_path
# Ensure file is not empty
with open(input_path, "rb") as fh:
data = fh.read()
assert len(data) > 0
def test_view_pygraphviz_file_suffix(self, tmp_path):
G = nx.complete_graph(3)
path, A = nx.nx_agraph.view_pygraphviz(G, suffix=1, show=False)
assert path[-6:] == "_1.png"
def test_view_pygraphviz(self):
G = nx.Graph() # "An empty graph cannot be drawn."
pytest.raises(nx.NetworkXException, nx.nx_agraph.view_pygraphviz, G)
G = nx.barbell_graph(4, 6)
nx.nx_agraph.view_pygraphviz(G, show=False)
def test_view_pygraphviz_edgelabel(self):
G = nx.Graph()
G.add_edge(1, 2, weight=7)
G.add_edge(2, 3, weight=8)
path, A = nx.nx_agraph.view_pygraphviz(G, edgelabel="weight", show=False)
for edge in A.edges():
assert edge.attr["weight"] in ("7", "8")
def test_view_pygraphviz_callable_edgelabel(self):
G = nx.complete_graph(3)
def foo_label(data):
return "foo"
path, A = nx.nx_agraph.view_pygraphviz(G, edgelabel=foo_label, show=False)
for edge in A.edges():
assert edge.attr["label"] == "foo"
def test_view_pygraphviz_multigraph_edgelabels(self):
G = nx.MultiGraph()
G.add_edge(0, 1, key=0, name="left_fork")
G.add_edge(0, 1, key=1, name="right_fork")
path, A = nx.nx_agraph.view_pygraphviz(G, edgelabel="name", show=False)
edges = A.edges()
assert len(edges) == 2
for edge in edges:
assert edge.attr["label"].strip() in ("left_fork", "right_fork")
def test_graph_with_reserved_keywords(self):
# test attribute/keyword clash case for #1582
# node: n
# edges: u,v
G = nx.Graph()
G = self.build_graph(G)
G.nodes["E"]["n"] = "keyword"
G.edges[("A", "B")]["u"] = "keyword"
G.edges[("A", "B")]["v"] = "keyword"
A = nx.nx_agraph.to_agraph(G)
def test_view_pygraphviz_no_added_attrs_to_input(self):
G = nx.complete_graph(2)
path, A = nx.nx_agraph.view_pygraphviz(G, show=False)
assert G.graph == {}
@pytest.mark.xfail(reason="known bug in clean_attrs")
def test_view_pygraphviz_leaves_input_graph_unmodified(self):
G = nx.complete_graph(2)
# Add entries to graph dict that to_agraph handles specially
G.graph["node"] = {"width": "0.80"}
G.graph["edge"] = {"fontsize": "14"}
path, A = nx.nx_agraph.view_pygraphviz(G, show=False)
assert G.graph == {"node": {"width": "0.80"}, "edge": {"fontsize": "14"}}
def test_graph_with_AGraph_attrs(self):
G = nx.complete_graph(2)
# Add entries to graph dict that to_agraph handles specially
G.graph["node"] = {"width": "0.80"}
G.graph["edge"] = {"fontsize": "14"}
path, A = nx.nx_agraph.view_pygraphviz(G, show=False)
# Ensure user-specified values are not lost
assert dict(A.node_attr)["width"] == "0.80"
assert dict(A.edge_attr)["fontsize"] == "14"
def test_round_trip_empty_graph(self):
G = nx.Graph()
A = nx.nx_agraph.to_agraph(G)
H = nx.nx_agraph.from_agraph(A)
# assert graphs_equal(G, H)
AA = nx.nx_agraph.to_agraph(H)
HH = nx.nx_agraph.from_agraph(AA)
assert graphs_equal(H, HH)
G.graph["graph"] = {}
G.graph["node"] = {}
G.graph["edge"] = {}
assert graphs_equal(G, HH)
@pytest.mark.xfail(reason="integer->string node conversion in round trip")
def test_round_trip_integer_nodes(self):
G = nx.complete_graph(3)
A = nx.nx_agraph.to_agraph(G)
H = nx.nx_agraph.from_agraph(A)
assert graphs_equal(G, H)
def test_graphviz_alias(self):
G = self.build_graph(nx.Graph())
pos_graphviz = nx.nx_agraph.graphviz_layout(G)
pos_pygraphviz = nx.nx_agraph.pygraphviz_layout(G)
assert pos_graphviz == pos_pygraphviz
@pytest.mark.parametrize("root", range(5))
def test_pygraphviz_layout_root(self, root):
# NOTE: test depends on layout prog being deterministic
G = nx.complete_graph(5)
A = nx.nx_agraph.to_agraph(G)
# Get layout with root arg is not None
pygv_layout = nx.nx_agraph.pygraphviz_layout(G, prog="circo", root=root)
# Equivalent layout directly on AGraph
A.layout(args=f"-Groot={root}", prog="circo")
# Parse AGraph layout
a1_pos = tuple(float(v) for v in dict(A.get_node("1").attr)["pos"].split(","))
assert pygv_layout[1] == a1_pos
def test_2d_layout(self):
G = nx.Graph()
G = self.build_graph(G)
G.graph["dimen"] = 2
pos = nx.nx_agraph.pygraphviz_layout(G, prog="neato")
pos = list(pos.values())
assert len(pos) == 5
assert len(pos[0]) == 2
def test_3d_layout(self):
G = nx.Graph()
G = self.build_graph(G)
G.graph["dimen"] = 3
pos = nx.nx_agraph.pygraphviz_layout(G, prog="neato")
pos = list(pos.values())
assert len(pos) == 5
assert len(pos[0]) == 3
def test_no_warnings_raised(self):
# Test that no warnings are raised when Networkx graph
# is converted to Pygraphviz graph and 'pos'
# attribute is given
G = nx.Graph()
G.add_node(0, pos=(0, 0))
G.add_node(1, pos=(1, 1))
A = nx.nx_agraph.to_agraph(G)
with pytest.warns(None) as record:
A.layout()
assert len(record) == 0
|