update
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,83 +0,0 @@
|
||||
# This file contains utilities for testing the dispatching feature
|
||||
|
||||
# A full test of all dispatchable algorithms is performed by
|
||||
# modifying the pytest invocation and setting an environment variable
|
||||
# NETWORKX_GRAPH_CONVERT=nx-loopback pytest
|
||||
# This is comprehensive, but only tests the `test_override_dispatch`
|
||||
# function in networkx.classes.backends.
|
||||
|
||||
# To test the `_dispatch` function directly, several tests scattered throughout
|
||||
# NetworkX have been augmented to test normal and dispatch mode.
|
||||
# Searching for `dispatch_interface` should locate the specific tests.
|
||||
|
||||
import networkx as nx
|
||||
from networkx import DiGraph, Graph, MultiDiGraph, MultiGraph, PlanarEmbedding
|
||||
|
||||
|
||||
class LoopbackGraph(Graph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackDiGraph(DiGraph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackMultiGraph(MultiGraph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackMultiDiGraph(MultiDiGraph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackPlanarEmbedding(PlanarEmbedding):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
def convert(graph):
|
||||
if isinstance(graph, PlanarEmbedding):
|
||||
return LoopbackPlanarEmbedding(graph)
|
||||
if isinstance(graph, MultiDiGraph):
|
||||
return LoopbackMultiDiGraph(graph)
|
||||
if isinstance(graph, MultiGraph):
|
||||
return LoopbackMultiGraph(graph)
|
||||
if isinstance(graph, DiGraph):
|
||||
return LoopbackDiGraph(graph)
|
||||
if isinstance(graph, Graph):
|
||||
return LoopbackGraph(graph)
|
||||
raise TypeError(f"Unsupported type of graph: {type(graph)}")
|
||||
|
||||
|
||||
class LoopbackDispatcher:
|
||||
non_toplevel = {
|
||||
"inter_community_edges": nx.community.quality.inter_community_edges,
|
||||
"is_tournament": nx.algorithms.tournament.is_tournament,
|
||||
"mutual_weight": nx.algorithms.structuralholes.mutual_weight,
|
||||
"score_sequence": nx.algorithms.tournament.score_sequence,
|
||||
"tournament_matrix": nx.algorithms.tournament.tournament_matrix,
|
||||
}
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Return the original, undecorated NetworkX algorithm
|
||||
if hasattr(nx, item):
|
||||
return getattr(nx, item)._orig_func
|
||||
if item in self.non_toplevel:
|
||||
return self.non_toplevel[item]._orig_func
|
||||
raise AttributeError(item)
|
||||
|
||||
@staticmethod
|
||||
def convert_from_nx(graph, weight=None, *, name=None):
|
||||
return graph
|
||||
|
||||
@staticmethod
|
||||
def convert_to_nx(obj, *, name=None):
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def on_start_tests(items):
|
||||
# Verify that items can be xfailed
|
||||
for item in items:
|
||||
assert hasattr(item, "add_marker")
|
||||
|
||||
|
||||
dispatcher = LoopbackDispatcher()
|
||||
@@ -1,474 +0,0 @@
|
||||
"""Original NetworkX graph tests"""
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx import convert_node_labels_to_integers as cnlti
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class HistoricalTests:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.null = nx.null_graph()
|
||||
cls.P1 = cnlti(nx.path_graph(1), first_label=1)
|
||||
cls.P3 = cnlti(nx.path_graph(3), first_label=1)
|
||||
cls.P10 = cnlti(nx.path_graph(10), first_label=1)
|
||||
cls.K1 = cnlti(nx.complete_graph(1), first_label=1)
|
||||
cls.K3 = cnlti(nx.complete_graph(3), first_label=1)
|
||||
cls.K4 = cnlti(nx.complete_graph(4), first_label=1)
|
||||
cls.K5 = cnlti(nx.complete_graph(5), first_label=1)
|
||||
cls.K10 = cnlti(nx.complete_graph(10), first_label=1)
|
||||
cls.G = nx.Graph
|
||||
|
||||
def test_name(self):
|
||||
G = self.G(name="test")
|
||||
assert G.name == "test"
|
||||
H = self.G()
|
||||
assert H.name == ""
|
||||
|
||||
# Nodes
|
||||
|
||||
def test_add_remove_node(self):
|
||||
G = self.G()
|
||||
G.add_node("A")
|
||||
assert G.has_node("A")
|
||||
G.remove_node("A")
|
||||
assert not G.has_node("A")
|
||||
|
||||
def test_nonhashable_node(self):
|
||||
# Test if a non-hashable object is in the Graph. A python dict will
|
||||
# raise a TypeError, but for a Graph class a simple False should be
|
||||
# returned (see Graph __contains__). If it cannot be a node then it is
|
||||
# not a node.
|
||||
G = self.G()
|
||||
assert not G.has_node(["A"])
|
||||
assert not G.has_node({"A": 1})
|
||||
|
||||
def test_add_nodes_from(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(list("ABCDEFGHIJKL"))
|
||||
assert G.has_node("L")
|
||||
G.remove_nodes_from(["H", "I", "J", "K", "L"])
|
||||
G.add_nodes_from([1, 2, 3, 4])
|
||||
assert sorted(G.nodes(), key=str) == [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
]
|
||||
# test __iter__
|
||||
assert sorted(G, key=str) == [1, 2, 3, 4, "A", "B", "C", "D", "E", "F", "G"]
|
||||
|
||||
def test_contains(self):
|
||||
G = self.G()
|
||||
G.add_node("A")
|
||||
assert "A" in G
|
||||
assert [] not in G # never raise a Key or TypeError in this test
|
||||
assert {1: 1} not in G
|
||||
|
||||
def test_add_remove(self):
|
||||
# Test add_node and remove_node acting for various nbunch
|
||||
G = self.G()
|
||||
G.add_node("m")
|
||||
assert G.has_node("m")
|
||||
G.add_node("m") # no complaints
|
||||
pytest.raises(nx.NetworkXError, G.remove_node, "j")
|
||||
G.remove_node("m")
|
||||
assert list(G) == []
|
||||
|
||||
def test_nbunch_is_list(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(list("ABCD"))
|
||||
G.add_nodes_from(self.P3) # add nbunch of nodes (nbunch=Graph)
|
||||
assert sorted(G.nodes(), key=str) == [1, 2, 3, "A", "B", "C", "D"]
|
||||
G.remove_nodes_from(self.P3) # remove nbunch of nodes (nbunch=Graph)
|
||||
assert sorted(G.nodes(), key=str) == ["A", "B", "C", "D"]
|
||||
|
||||
def test_nbunch_is_set(self):
|
||||
G = self.G()
|
||||
nbunch = set("ABCDEFGHIJKL")
|
||||
G.add_nodes_from(nbunch)
|
||||
assert G.has_node("L")
|
||||
|
||||
def test_nbunch_dict(self):
|
||||
# nbunch is a dict with nodes as keys
|
||||
G = self.G()
|
||||
nbunch = set("ABCDEFGHIJKL")
|
||||
G.add_nodes_from(nbunch)
|
||||
nbunch = {"I": "foo", "J": 2, "K": True, "L": "spam"}
|
||||
G.remove_nodes_from(nbunch)
|
||||
assert sorted(G.nodes(), key=str), ["A", "B", "C", "D", "E", "F", "G", "H"]
|
||||
|
||||
def test_nbunch_iterator(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"])
|
||||
n_iter = self.P3.nodes()
|
||||
G.add_nodes_from(n_iter)
|
||||
assert sorted(G.nodes(), key=str) == [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
]
|
||||
n_iter = self.P3.nodes() # rebuild same iterator
|
||||
G.remove_nodes_from(n_iter) # remove nbunch of nodes (nbunch=iterator)
|
||||
assert sorted(G.nodes(), key=str) == ["A", "B", "C", "D", "E", "F", "G", "H"]
|
||||
|
||||
def test_nbunch_graph(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"])
|
||||
nbunch = self.K3
|
||||
G.add_nodes_from(nbunch)
|
||||
assert sorted(G.nodes(), key=str), [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
]
|
||||
|
||||
# Edges
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.G()
|
||||
pytest.raises(TypeError, G.add_edge, "A")
|
||||
|
||||
G.add_edge("A", "B") # testing add_edge()
|
||||
G.add_edge("A", "B") # should fail silently
|
||||
assert G.has_edge("A", "B")
|
||||
assert not G.has_edge("A", "C")
|
||||
assert G.has_edge(*("A", "B"))
|
||||
if G.is_directed():
|
||||
assert not G.has_edge("B", "A")
|
||||
else:
|
||||
# G is undirected, so B->A is an edge
|
||||
assert G.has_edge("B", "A")
|
||||
|
||||
G.add_edge("A", "C") # test directedness
|
||||
G.add_edge("C", "A")
|
||||
G.remove_edge("C", "A")
|
||||
if G.is_directed():
|
||||
assert G.has_edge("A", "C")
|
||||
else:
|
||||
assert not G.has_edge("A", "C")
|
||||
assert not G.has_edge("C", "A")
|
||||
|
||||
def test_self_loop(self):
|
||||
G = self.G()
|
||||
G.add_edge("A", "A") # test self loops
|
||||
assert G.has_edge("A", "A")
|
||||
G.remove_edge("A", "A")
|
||||
G.add_edge("X", "X")
|
||||
assert G.has_node("X")
|
||||
G.remove_node("X")
|
||||
G.add_edge("A", "Z") # should add the node silently
|
||||
assert G.has_node("Z")
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("B", "C")]) # test add_edges_from()
|
||||
assert G.has_edge("B", "C")
|
||||
if G.is_directed():
|
||||
assert not G.has_edge("C", "B")
|
||||
else:
|
||||
assert G.has_edge("C", "B") # undirected
|
||||
|
||||
G.add_edges_from([("D", "F"), ("B", "D")])
|
||||
assert G.has_edge("D", "F")
|
||||
assert G.has_edge("B", "D")
|
||||
|
||||
if G.is_directed():
|
||||
assert not G.has_edge("D", "B")
|
||||
else:
|
||||
assert G.has_edge("D", "B") # undirected
|
||||
|
||||
def test_add_edges_from2(self):
|
||||
G = self.G()
|
||||
# after failing silently, should add 2nd edge
|
||||
G.add_edges_from([tuple("IJ"), list("KK"), tuple("JK")])
|
||||
assert G.has_edge(*("I", "J"))
|
||||
assert G.has_edge(*("K", "K"))
|
||||
assert G.has_edge(*("J", "K"))
|
||||
if G.is_directed():
|
||||
assert not G.has_edge(*("K", "J"))
|
||||
else:
|
||||
assert G.has_edge(*("K", "J"))
|
||||
|
||||
def test_add_edges_from3(self):
|
||||
G = self.G()
|
||||
G.add_edges_from(zip(list("ACD"), list("CDE")))
|
||||
assert G.has_edge("D", "E")
|
||||
assert not G.has_edge("E", "C")
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from([1, 2, 3, "A", "B", "C", "D", "E", "F", "G", "H"])
|
||||
|
||||
G.add_edges_from(zip(list("MNOP"), list("NOPM")))
|
||||
assert G.has_edge("O", "P")
|
||||
assert G.has_edge("P", "M")
|
||||
G.remove_node("P") # tests remove_node()'s handling of edges.
|
||||
assert not G.has_edge("P", "M")
|
||||
pytest.raises(TypeError, G.remove_edge, "M")
|
||||
|
||||
G.add_edge("N", "M")
|
||||
assert G.has_edge("M", "N")
|
||||
G.remove_edge("M", "N")
|
||||
assert not G.has_edge("M", "N")
|
||||
|
||||
# self loop fails silently
|
||||
G.remove_edges_from([list("HI"), list("DF"), tuple("KK"), tuple("JK")])
|
||||
assert not G.has_edge("H", "I")
|
||||
assert not G.has_edge("J", "K")
|
||||
G.remove_edges_from([list("IJ"), list("KK"), list("JK")])
|
||||
assert not G.has_edge("I", "J")
|
||||
G.remove_nodes_from(set("ZEFHIMNO"))
|
||||
G.add_edge("J", "K")
|
||||
|
||||
def test_edges_nbunch(self):
|
||||
# Test G.edges(nbunch) with various forms of nbunch
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
# node not in nbunch should be quietly ignored
|
||||
pytest.raises(nx.NetworkXError, G.edges, 6)
|
||||
assert list(G.edges("Z")) == [] # iterable non-node
|
||||
# nbunch can be an empty list
|
||||
assert list(G.edges([])) == []
|
||||
if G.is_directed():
|
||||
elist = [("A", "B"), ("A", "C"), ("B", "D")]
|
||||
else:
|
||||
elist = [("A", "B"), ("A", "C"), ("B", "C"), ("B", "D")]
|
||||
# nbunch can be a list
|
||||
assert edges_equal(list(G.edges(["A", "B"])), elist)
|
||||
# nbunch can be a set
|
||||
assert edges_equal(G.edges({"A", "B"}), elist)
|
||||
# nbunch can be a graph
|
||||
G1 = self.G()
|
||||
G1.add_nodes_from("AB")
|
||||
assert edges_equal(G.edges(G1), elist)
|
||||
# nbunch can be a dict with nodes as keys
|
||||
ndict = {"A": "thing1", "B": "thing2"}
|
||||
assert edges_equal(G.edges(ndict), elist)
|
||||
# nbunch can be a single node
|
||||
assert edges_equal(list(G.edges("A")), [("A", "B"), ("A", "C")])
|
||||
assert nodes_equal(sorted(G), ["A", "B", "C", "D"])
|
||||
|
||||
# nbunch can be nothing (whole graph)
|
||||
assert edges_equal(
|
||||
list(G.edges()),
|
||||
[("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")],
|
||||
)
|
||||
|
||||
def test_degree(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
assert G.degree("A") == 2
|
||||
|
||||
# degree of single node in iterable container must return dict
|
||||
assert list(G.degree(["A"])) == [("A", 2)]
|
||||
assert sorted(d for n, d in G.degree(["A", "B"])) == [2, 3]
|
||||
assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3]
|
||||
|
||||
def test_degree2(self):
|
||||
H = self.G()
|
||||
H.add_edges_from([(1, 24), (1, 2)])
|
||||
assert sorted(d for n, d in H.degree([1, 24])) == [1, 2]
|
||||
|
||||
def test_degree_graph(self):
|
||||
P3 = nx.path_graph(3)
|
||||
P5 = nx.path_graph(5)
|
||||
# silently ignore nodes not in P3
|
||||
assert dict(d for n, d in P3.degree(["A", "B"])) == {}
|
||||
# nbunch can be a graph
|
||||
assert sorted(d for n, d in P5.degree(P3)) == [1, 2, 2]
|
||||
# nbunch can be a graph that's way too big
|
||||
assert sorted(d for n, d in P3.degree(P5)) == [1, 1, 2]
|
||||
assert list(P5.degree([])) == []
|
||||
assert dict(P5.degree([])) == {}
|
||||
|
||||
def test_null(self):
|
||||
null = nx.null_graph()
|
||||
assert list(null.degree()) == []
|
||||
assert dict(null.degree()) == {}
|
||||
|
||||
def test_order_size(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
assert G.order() == 4
|
||||
assert G.size() == 5
|
||||
assert G.number_of_edges() == 5
|
||||
assert G.number_of_edges("A", "B") == 1
|
||||
assert G.number_of_edges("A", "D") == 0
|
||||
|
||||
def test_copy(self):
|
||||
G = self.G()
|
||||
H = G.copy() # copy
|
||||
assert H.adj == G.adj
|
||||
assert H.name == G.name
|
||||
assert H is not G
|
||||
|
||||
def test_subgraph(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
SG = G.subgraph(["A", "B", "D"])
|
||||
assert nodes_equal(list(SG), ["A", "B", "D"])
|
||||
assert edges_equal(list(SG.edges()), [("A", "B"), ("B", "D")])
|
||||
|
||||
def test_to_directed(self):
|
||||
G = self.G()
|
||||
if not G.is_directed():
|
||||
G.add_edges_from(
|
||||
[("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]
|
||||
)
|
||||
|
||||
DG = G.to_directed()
|
||||
assert DG is not G # directed copy or copy
|
||||
|
||||
assert DG.is_directed()
|
||||
assert DG.name == G.name
|
||||
assert DG.adj == G.adj
|
||||
assert sorted(DG.out_edges(list("AB"))) == [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "A"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
]
|
||||
DG.remove_edge("A", "B")
|
||||
assert DG.has_edge("B", "A") # this removes B-A but not A-B
|
||||
assert not DG.has_edge("A", "B")
|
||||
|
||||
def test_to_undirected(self):
|
||||
G = self.G()
|
||||
if G.is_directed():
|
||||
G.add_edges_from(
|
||||
[("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]
|
||||
)
|
||||
UG = G.to_undirected() # to_undirected
|
||||
assert UG is not G
|
||||
assert not UG.is_directed()
|
||||
assert G.is_directed()
|
||||
assert UG.name == G.name
|
||||
assert UG.adj != G.adj
|
||||
assert sorted(UG.edges(list("AB"))) == [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
]
|
||||
assert sorted(UG.edges(["A", "B"])) == [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
]
|
||||
UG.remove_edge("A", "B")
|
||||
assert not UG.has_edge("B", "A")
|
||||
assert not UG.has_edge("A", "B")
|
||||
|
||||
def test_neighbors(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
G.add_nodes_from("GJK")
|
||||
assert sorted(G["A"]) == ["B", "C"]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
assert sorted(G.neighbors("G")) == []
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "j")
|
||||
|
||||
def test_iterators(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
G.add_nodes_from("GJK")
|
||||
assert sorted(G.nodes()) == ["A", "B", "C", "D", "G", "J", "K"]
|
||||
assert edges_equal(
|
||||
G.edges(), [("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]
|
||||
)
|
||||
|
||||
assert sorted(v for k, v in G.degree()) == [0, 0, 0, 2, 2, 3, 3]
|
||||
assert sorted(G.degree(), key=str) == [
|
||||
("A", 2),
|
||||
("B", 3),
|
||||
("C", 3),
|
||||
("D", 2),
|
||||
("G", 0),
|
||||
("J", 0),
|
||||
("K", 0),
|
||||
]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "X")
|
||||
G.clear()
|
||||
assert nx.number_of_nodes(G) == 0
|
||||
assert nx.number_of_edges(G) == 0
|
||||
|
||||
def test_null_subgraph(self):
|
||||
# Subgraph of a null graph is a null graph
|
||||
nullgraph = nx.null_graph()
|
||||
G = nx.null_graph()
|
||||
H = G.subgraph([])
|
||||
assert nx.is_isomorphic(H, nullgraph)
|
||||
|
||||
def test_empty_subgraph(self):
|
||||
# Subgraph of an empty graph is an empty graph. test 1
|
||||
nullgraph = nx.null_graph()
|
||||
E5 = nx.empty_graph(5)
|
||||
E10 = nx.empty_graph(10)
|
||||
H = E10.subgraph([])
|
||||
assert nx.is_isomorphic(H, nullgraph)
|
||||
H = E10.subgraph([1, 2, 3, 4, 5])
|
||||
assert nx.is_isomorphic(H, E5)
|
||||
|
||||
def test_complete_subgraph(self):
|
||||
# Subgraph of a complete graph is a complete graph
|
||||
K1 = nx.complete_graph(1)
|
||||
K3 = nx.complete_graph(3)
|
||||
K5 = nx.complete_graph(5)
|
||||
H = K5.subgraph([1, 2, 3])
|
||||
assert nx.is_isomorphic(H, K3)
|
||||
|
||||
def test_subgraph_nbunch(self):
|
||||
nullgraph = nx.null_graph()
|
||||
K1 = nx.complete_graph(1)
|
||||
K3 = nx.complete_graph(3)
|
||||
K5 = nx.complete_graph(5)
|
||||
# Test G.subgraph(nbunch), where nbunch is a single node
|
||||
H = K5.subgraph(1)
|
||||
assert nx.is_isomorphic(H, K1)
|
||||
# Test G.subgraph(nbunch), where nbunch is a set
|
||||
H = K5.subgraph({1})
|
||||
assert nx.is_isomorphic(H, K1)
|
||||
# Test G.subgraph(nbunch), where nbunch is an iterator
|
||||
H = K5.subgraph(iter(K3))
|
||||
assert nx.is_isomorphic(H, K3)
|
||||
# Test G.subgraph(nbunch), where nbunch is another graph
|
||||
H = K5.subgraph(K3)
|
||||
assert nx.is_isomorphic(H, K3)
|
||||
H = K5.subgraph([9])
|
||||
assert nx.is_isomorphic(H, nullgraph)
|
||||
|
||||
def test_node_tuple_issue(self):
|
||||
H = self.G()
|
||||
# Test error handling of tuple as a node
|
||||
pytest.raises(nx.NetworkXError, H.remove_node, (1, 2))
|
||||
H.remove_nodes_from([(1, 2)]) # no error
|
||||
pytest.raises(nx.NetworkXError, H.neighbors, (1, 2))
|
||||
@@ -1,14 +0,0 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
pytest.importorskip("scipy")
|
||||
pytest.importorskip("numpy")
|
||||
|
||||
|
||||
def test_dispatch_kwds_vs_args():
|
||||
G = nx.path_graph(4)
|
||||
nx.pagerank(G)
|
||||
nx.pagerank(G=G)
|
||||
with pytest.raises(TypeError):
|
||||
nx.pagerank()
|
||||
@@ -1,362 +0,0 @@
|
||||
import pickle
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class TestAtlasView:
|
||||
# node->data
|
||||
def setup_method(self):
|
||||
self.d = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}}
|
||||
self.av = nx.classes.coreviews.AtlasView(self.d)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.av
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
pview = pickle.loads(pickle.dumps(view))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.av) == len(self.d)
|
||||
|
||||
def test_iter(self):
|
||||
assert list(self.av) == list(self.d)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.av[1] is self.d[1]
|
||||
assert self.av[2]["color"] == 1
|
||||
pytest.raises(KeyError, self.av.__getitem__, 3)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.av.copy()
|
||||
assert avcopy[0] == self.av[0]
|
||||
assert avcopy == self.av
|
||||
assert avcopy[0] is not self.av[0]
|
||||
assert avcopy is not self.av
|
||||
avcopy[5] = {}
|
||||
assert avcopy != self.av
|
||||
|
||||
avcopy[0]["ht"] = 4
|
||||
assert avcopy[0] != self.av[0]
|
||||
self.av[0]["ht"] = 4
|
||||
assert avcopy[0] == self.av[0]
|
||||
del self.av[0]["ht"]
|
||||
|
||||
assert not hasattr(self.av, "__setitem__")
|
||||
|
||||
def test_items(self):
|
||||
assert sorted(self.av.items()) == sorted(self.d.items())
|
||||
|
||||
def test_str(self):
|
||||
out = str(self.d)
|
||||
assert str(self.av) == out
|
||||
|
||||
def test_repr(self):
|
||||
out = "AtlasView(" + str(self.d) + ")"
|
||||
assert repr(self.av) == out
|
||||
|
||||
|
||||
class TestAdjacencyView:
|
||||
# node->nbr->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.nd = {0: dd, 1: {}, 2: {"color": 1}}
|
||||
self.adj = {3: self.nd, 0: {3: dd}, 1: {}, 2: {3: {"color": 1}}}
|
||||
self.adjview = nx.classes.coreviews.AdjacencyView(self.adj)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.adjview
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.adjview) == len(self.adj)
|
||||
|
||||
def test_iter(self):
|
||||
assert list(self.adjview) == list(self.adj)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.adj[1]
|
||||
assert self.adjview[3][0] is self.adjview[0][3]
|
||||
assert self.adjview[2][3]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
|
||||
def test_items(self):
|
||||
view_items = sorted((n, dict(d)) for n, d in self.adjview.items())
|
||||
assert view_items == sorted(self.adj.items())
|
||||
|
||||
def test_str(self):
|
||||
out = str(dict(self.adj))
|
||||
assert str(self.adjview) == out
|
||||
|
||||
def test_repr(self):
|
||||
out = self.adjview.__class__.__name__ + "(" + str(self.adj) + ")"
|
||||
assert repr(self.adjview) == out
|
||||
|
||||
|
||||
class TestMultiAdjacencyView(TestAdjacencyView):
|
||||
# node->nbr->key->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.kd = {0: dd, 1: {}, 2: {"color": 1}}
|
||||
self.nd = {3: self.kd, 0: {3: dd}, 1: {0: {}}, 2: {3: {"color": 1}}}
|
||||
self.adj = {3: self.nd, 0: {3: {3: dd}}, 1: {}, 2: {3: {8: {}}}}
|
||||
self.adjview = nx.classes.coreviews.MultiAdjacencyView(self.adj)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.adj[1]
|
||||
assert self.adjview[3][0][3] is self.adjview[0][3][3]
|
||||
assert self.adjview[3][2][3]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3][8]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
|
||||
|
||||
class TestUnionAtlas:
|
||||
# node->data
|
||||
def setup_method(self):
|
||||
self.s = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}}
|
||||
self.p = {3: {"color": "blue", "weight": 1.2}, 4: {}, 2: {"watch": 2}}
|
||||
self.av = nx.classes.coreviews.UnionAtlas(self.s, self.p)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.av
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.av) == len(self.s.keys() | self.p.keys()) == 5
|
||||
|
||||
def test_iter(self):
|
||||
assert set(self.av) == set(self.s) | set(self.p)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.av[0] is self.s[0]
|
||||
assert self.av[4] is self.p[4]
|
||||
assert self.av[2]["color"] == 1
|
||||
pytest.raises(KeyError, self.av[2].__getitem__, "watch")
|
||||
pytest.raises(KeyError, self.av.__getitem__, 8)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.av.copy()
|
||||
assert avcopy[0] == self.av[0]
|
||||
assert avcopy[0] is not self.av[0]
|
||||
assert avcopy is not self.av
|
||||
avcopy[5] = {}
|
||||
assert avcopy != self.av
|
||||
|
||||
avcopy[0]["ht"] = 4
|
||||
assert avcopy[0] != self.av[0]
|
||||
self.av[0]["ht"] = 4
|
||||
assert avcopy[0] == self.av[0]
|
||||
del self.av[0]["ht"]
|
||||
|
||||
assert not hasattr(self.av, "__setitem__")
|
||||
|
||||
def test_items(self):
|
||||
expected = dict(self.p.items())
|
||||
expected.update(self.s)
|
||||
assert sorted(self.av.items()) == sorted(expected.items())
|
||||
|
||||
def test_str(self):
|
||||
out = str(dict(self.av))
|
||||
assert str(self.av) == out
|
||||
|
||||
def test_repr(self):
|
||||
out = f"{self.av.__class__.__name__}({self.s}, {self.p})"
|
||||
assert repr(self.av) == out
|
||||
|
||||
|
||||
class TestUnionAdjacency:
|
||||
# node->nbr->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.nd = {0: dd, 1: {}, 2: {"color": 1}}
|
||||
self.s = {3: self.nd, 0: {}, 1: {}, 2: {3: {"color": 1}}}
|
||||
self.p = {3: {}, 0: {3: dd}, 1: {0: {}}, 2: {1: {"color": 1}}}
|
||||
self.adjview = nx.classes.coreviews.UnionAdjacency(self.s, self.p)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.adjview
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.adjview) == len(self.s)
|
||||
|
||||
def test_iter(self):
|
||||
assert sorted(self.adjview) == sorted(self.s)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.s[1]
|
||||
assert self.adjview[3][0] is self.adjview[0][3]
|
||||
assert self.adjview[2][3]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
|
||||
def test_str(self):
|
||||
out = str(dict(self.adjview))
|
||||
assert str(self.adjview) == out
|
||||
|
||||
def test_repr(self):
|
||||
clsname = self.adjview.__class__.__name__
|
||||
out = f"{clsname}({self.s}, {self.p})"
|
||||
assert repr(self.adjview) == out
|
||||
|
||||
|
||||
class TestUnionMultiInner(TestUnionAdjacency):
|
||||
# nbr->key->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.kd = {7: {}, "ekey": {}, 9: {"color": 1}}
|
||||
self.s = {3: self.kd, 0: {7: dd}, 1: {}, 2: {"key": {"color": 1}}}
|
||||
self.p = {3: {}, 0: {3: dd}, 1: {}, 2: {1: {"span": 2}}}
|
||||
self.adjview = nx.classes.coreviews.UnionMultiInner(self.s, self.p)
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.adjview) == len(self.s.keys() | self.p.keys()) == 4
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.s[1]
|
||||
assert self.adjview[0][7] is self.adjview[0][3]
|
||||
assert self.adjview[2]["key"]["color"] == 1
|
||||
assert self.adjview[2][1]["span"] == 2
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
pytest.raises(KeyError, self.adjview[1].__getitem__, "key")
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][1]["width"] = 8
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][1]["width"] = 8
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][1]["width"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
assert hasattr(avcopy, "__setitem__")
|
||||
|
||||
|
||||
class TestUnionMultiAdjacency(TestUnionAdjacency):
|
||||
# node->nbr->key->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.kd = {7: {}, 8: {}, 9: {"color": 1}}
|
||||
self.nd = {3: self.kd, 0: {9: dd}, 1: {8: {}}, 2: {9: {"color": 1}}}
|
||||
self.s = {3: self.nd, 0: {3: {7: dd}}, 1: {}, 2: {3: {8: {}}}}
|
||||
self.p = {3: {}, 0: {3: {9: dd}}, 1: {}, 2: {1: {8: {}}}}
|
||||
self.adjview = nx.classes.coreviews.UnionMultiAdjacency(self.s, self.p)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.s[1]
|
||||
assert self.adjview[3][0][9] is self.adjview[0][3][9]
|
||||
assert self.adjview[3][2][9]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3][8]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
assert hasattr(avcopy, "__setitem__")
|
||||
|
||||
|
||||
class TestFilteredGraphs:
|
||||
def setup_method(self):
|
||||
self.Graphs = [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
||||
|
||||
def test_hide_show_nodes(self):
|
||||
SubGraph = nx.graphviews.subgraph_view
|
||||
for Graph in self.Graphs:
|
||||
G = nx.path_graph(4, Graph)
|
||||
SG = G.subgraph([2, 3])
|
||||
RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
|
||||
assert SG.nodes == RG.nodes
|
||||
assert SG.edges == RG.edges
|
||||
SGC = SG.copy()
|
||||
RGC = RG.copy()
|
||||
assert SGC.nodes == RGC.nodes
|
||||
assert SGC.edges == RGC.edges
|
||||
|
||||
def test_str_repr(self):
|
||||
SubGraph = nx.graphviews.subgraph_view
|
||||
for Graph in self.Graphs:
|
||||
G = nx.path_graph(4, Graph)
|
||||
SG = G.subgraph([2, 3])
|
||||
RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
|
||||
str(SG.adj)
|
||||
str(RG.adj)
|
||||
repr(SG.adj)
|
||||
repr(RG.adj)
|
||||
str(SG.adj[2])
|
||||
str(RG.adj[2])
|
||||
repr(SG.adj[2])
|
||||
repr(RG.adj[2])
|
||||
|
||||
def test_copy(self):
|
||||
SubGraph = nx.graphviews.subgraph_view
|
||||
for Graph in self.Graphs:
|
||||
G = nx.path_graph(4, Graph)
|
||||
SG = G.subgraph([2, 3])
|
||||
RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
|
||||
RsG = SubGraph(G, nx.filters.show_nodes([2, 3]))
|
||||
assert G.adj.copy() == G.adj
|
||||
assert G.adj[2].copy() == G.adj[2]
|
||||
assert SG.adj.copy() == SG.adj
|
||||
assert SG.adj[2].copy() == SG.adj[2]
|
||||
assert RG.adj.copy() == RG.adj
|
||||
assert RG.adj[2].copy() == RG.adj[2]
|
||||
assert RsG.adj.copy() == RsG.adj
|
||||
assert RsG.adj[2].copy() == RsG.adj[2]
|
||||
@@ -1,331 +0,0 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import nodes_equal
|
||||
|
||||
from .test_graph import BaseAttrGraphTester, BaseGraphTester
|
||||
from .test_graph import TestEdgeSubgraph as _TestGraphEdgeSubgraph
|
||||
from .test_graph import TestGraph as _TestGraph
|
||||
|
||||
|
||||
class BaseDiGraphTester(BaseGraphTester):
|
||||
def test_has_successor(self):
|
||||
G = self.K3
|
||||
assert G.has_successor(0, 1)
|
||||
assert not G.has_successor(0, -1)
|
||||
|
||||
def test_successors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.successors(0)) == [1, 2]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.successors(-1)
|
||||
|
||||
def test_has_predecessor(self):
|
||||
G = self.K3
|
||||
assert G.has_predecessor(0, 1)
|
||||
assert not G.has_predecessor(0, -1)
|
||||
|
||||
def test_predecessors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.predecessors(0)) == [1, 2]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.predecessors(-1)
|
||||
|
||||
def test_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
|
||||
assert sorted(G.edges([0, 1])) == [(0, 1), (0, 2), (1, 0), (1, 2)]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1)
|
||||
|
||||
def test_out_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.out_edges(-1)
|
||||
|
||||
def test_out_edges_dir(self):
|
||||
G = self.P3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (1, 2)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1)]
|
||||
assert sorted(G.out_edges(2)) == []
|
||||
|
||||
def test_out_edges_data(self):
|
||||
G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})])
|
||||
assert sorted(G.out_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})]
|
||||
assert sorted(G.out_edges(0, data=True)) == [(0, 1, {"data": 0})]
|
||||
assert sorted(G.out_edges(data="data")) == [(0, 1, 0), (1, 0, None)]
|
||||
assert sorted(G.out_edges(0, data="data")) == [(0, 1, 0)]
|
||||
|
||||
def test_in_edges_dir(self):
|
||||
G = self.P3
|
||||
assert sorted(G.in_edges()) == [(0, 1), (1, 2)]
|
||||
assert sorted(G.in_edges(0)) == []
|
||||
assert sorted(G.in_edges(2)) == [(1, 2)]
|
||||
|
||||
def test_in_edges_data(self):
|
||||
G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})])
|
||||
assert sorted(G.in_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})]
|
||||
assert sorted(G.in_edges(1, data=True)) == [(0, 1, {"data": 0})]
|
||||
assert sorted(G.in_edges(data="data")) == [(0, 1, 0), (1, 0, None)]
|
||||
assert sorted(G.in_edges(1, data="data")) == [(0, 1, 0)]
|
||||
|
||||
def test_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)]
|
||||
assert dict(G.degree()) == {0: 4, 1: 4, 2: 4}
|
||||
assert G.degree(0) == 4
|
||||
assert list(G.degree(iter([0]))) == [(0, 4)] # run through iterator
|
||||
|
||||
def test_in_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.in_degree(0) == 2
|
||||
assert list(G.in_degree(iter([0]))) == [(0, 2)] # run through iterator
|
||||
|
||||
def test_out_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.out_degree(0) == 2
|
||||
assert list(G.out_degree(iter([0]))) == [(0, 2)]
|
||||
|
||||
def test_size(self):
|
||||
G = self.K3
|
||||
assert G.size() == 6
|
||||
assert G.number_of_edges() == 6
|
||||
|
||||
def test_to_undirected_reciprocal(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2)
|
||||
assert G.to_undirected().has_edge(1, 2)
|
||||
assert not G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
G.add_edge(2, 1)
|
||||
assert G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
|
||||
def test_reverse_copy(self):
|
||||
G = nx.DiGraph([(0, 1), (1, 2)])
|
||||
R = G.reverse()
|
||||
assert sorted(R.edges()) == [(1, 0), (2, 1)]
|
||||
R.remove_edge(1, 0)
|
||||
assert sorted(R.edges()) == [(2, 1)]
|
||||
assert sorted(G.edges()) == [(0, 1), (1, 2)]
|
||||
|
||||
def test_reverse_nocopy(self):
|
||||
G = nx.DiGraph([(0, 1), (1, 2)])
|
||||
R = G.reverse(copy=False)
|
||||
assert sorted(R.edges()) == [(1, 0), (2, 1)]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
R.remove_edge(1, 0)
|
||||
|
||||
def test_reverse_hashable(self):
|
||||
class Foo:
|
||||
pass
|
||||
|
||||
x = Foo()
|
||||
y = Foo()
|
||||
G = nx.DiGraph()
|
||||
G.add_edge(x, y)
|
||||
assert nodes_equal(G.nodes(), G.reverse().nodes())
|
||||
assert [(y, x)] == list(G.reverse().edges())
|
||||
|
||||
def test_di_cache_reset(self):
|
||||
G = self.K3.copy()
|
||||
old_succ = G.succ
|
||||
assert id(G.succ) == id(old_succ)
|
||||
old_adj = G.adj
|
||||
assert id(G.adj) == id(old_adj)
|
||||
|
||||
G._succ = {}
|
||||
assert id(G.succ) != id(old_succ)
|
||||
assert id(G.adj) != id(old_adj)
|
||||
|
||||
old_pred = G.pred
|
||||
assert id(G.pred) == id(old_pred)
|
||||
G._pred = {}
|
||||
assert id(G.pred) != id(old_pred)
|
||||
|
||||
def test_di_attributes_cached(self):
|
||||
G = self.K3.copy()
|
||||
assert id(G.in_edges) == id(G.in_edges)
|
||||
assert id(G.out_edges) == id(G.out_edges)
|
||||
assert id(G.in_degree) == id(G.in_degree)
|
||||
assert id(G.out_degree) == id(G.out_degree)
|
||||
assert id(G.succ) == id(G.succ)
|
||||
assert id(G.pred) == id(G.pred)
|
||||
|
||||
|
||||
class BaseAttrDiGraphTester(BaseDiGraphTester, BaseAttrGraphTester):
|
||||
def test_edges_data(self):
|
||||
G = self.K3
|
||||
all_edges = [
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 0, {}),
|
||||
(1, 2, {}),
|
||||
(2, 0, {}),
|
||||
(2, 1, {}),
|
||||
]
|
||||
assert sorted(G.edges(data=True)) == all_edges
|
||||
assert sorted(G.edges(0, data=True)) == all_edges[:2]
|
||||
assert sorted(G.edges([0, 1], data=True)) == all_edges[:4]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1, True)
|
||||
|
||||
def test_in_degree_weighted(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert sorted(G.in_degree(weight="weight")) == [(0, 2), (1, 1.3), (2, 2)]
|
||||
assert dict(G.in_degree(weight="weight")) == {0: 2, 1: 1.3, 2: 2}
|
||||
assert G.in_degree(1, weight="weight") == 1.3
|
||||
assert sorted(G.in_degree(weight="other")) == [(0, 2), (1, 2.2), (2, 2)]
|
||||
assert dict(G.in_degree(weight="other")) == {0: 2, 1: 2.2, 2: 2}
|
||||
assert G.in_degree(1, weight="other") == 2.2
|
||||
assert list(G.in_degree(iter([1]), weight="other")) == [(1, 2.2)]
|
||||
|
||||
def test_out_degree_weighted(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert sorted(G.out_degree(weight="weight")) == [(0, 1.3), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree(weight="weight")) == {0: 1.3, 1: 2, 2: 2}
|
||||
assert G.out_degree(0, weight="weight") == 1.3
|
||||
assert sorted(G.out_degree(weight="other")) == [(0, 2.2), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree(weight="other")) == {0: 2.2, 1: 2, 2: 2}
|
||||
assert G.out_degree(0, weight="other") == 2.2
|
||||
assert list(G.out_degree(iter([0]), weight="other")) == [(0, 2.2)]
|
||||
|
||||
|
||||
class TestDiGraph(BaseAttrDiGraphTester, _TestGraph):
|
||||
"""Tests specific to dict-of-dict-of-dict digraph data structure"""
|
||||
|
||||
def setup_method(self):
|
||||
self.Graph = nx.DiGraph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3, ed4, ed5, ed6 = ({}, {}, {}, {}, {}, {})
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = self.k3adj # K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}}
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
ed1, ed2 = ({}, {})
|
||||
self.P3 = self.Graph()
|
||||
self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}}
|
||||
self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}}
|
||||
# P3._adj is synced with P3._succ
|
||||
self.P3._node = {}
|
||||
self.P3._node[0] = {}
|
||||
self.P3._node[1] = {}
|
||||
self.P3._node[2] = {}
|
||||
|
||||
def test_data_input(self):
|
||||
G = self.Graph({1: [2], 2: [1]}, name="test")
|
||||
assert G.name == "test"
|
||||
assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
assert sorted(G.succ.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
assert sorted(G.pred.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G.adj == {0: {1: {}}, 1: {}}
|
||||
assert G.succ == {0: {1: {}}, 1: {}}
|
||||
assert G.pred == {0: {}, 1: {0: {}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G.adj == {0: {1: {}}, 1: {}}
|
||||
assert G.succ == {0: {1: {}}, 1: {}}
|
||||
assert G.pred == {0: {}, 1: {0: {}}}
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edge(None, 3)
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 2, {"data": 3})], data=2)
|
||||
assert G.adj == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}}
|
||||
assert G.succ == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}}
|
||||
assert G.pred == {0: {}, 1: {0: {"data": 2}}, 2: {0: {"data": 3}}}
|
||||
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0,)]) # too few in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple
|
||||
with pytest.raises(TypeError):
|
||||
G.add_edges_from([0]) # not a tuple
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edges_from([(None, 3), (3, 2)])
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edge(0, 1)
|
||||
assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}
|
||||
assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1)])
|
||||
assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}
|
||||
assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
|
||||
def test_clear(self):
|
||||
G = self.K3
|
||||
G.graph["name"] = "K3"
|
||||
G.clear()
|
||||
assert list(G.nodes) == []
|
||||
assert G.succ == {}
|
||||
assert G.pred == {}
|
||||
assert G.graph == {}
|
||||
|
||||
def test_clear_edges(self):
|
||||
G = self.K3
|
||||
G.graph["name"] = "K3"
|
||||
nodes = list(G.nodes)
|
||||
G.clear_edges()
|
||||
assert list(G.nodes) == nodes
|
||||
expected = {0: {}, 1: {}, 2: {}}
|
||||
assert G.succ == expected
|
||||
assert G.pred == expected
|
||||
assert list(G.edges) == []
|
||||
assert G.graph["name"] == "K3"
|
||||
|
||||
|
||||
class TestEdgeSubgraph(_TestGraphEdgeSubgraph):
|
||||
"""Unit tests for the :meth:`DiGraph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a doubly-linked path graph on five nodes.
|
||||
G = nx.DiGraph(nx.path_graph(5))
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.edges[0, 1]["name"] = "edge01"
|
||||
G.edges[3, 4]["name"] = "edge34"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by the first and last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1), (3, 4)])
|
||||
|
||||
def test_pred_succ(self):
|
||||
"""Test that nodes are added to predecessors and successors.
|
||||
|
||||
For more information, see GitHub issue #2370.
|
||||
|
||||
"""
|
||||
G = nx.DiGraph()
|
||||
G.add_edge(0, 1)
|
||||
H = G.edge_subgraph([(0, 1)])
|
||||
assert list(H.predecessors(0)) == []
|
||||
assert list(H.successors(0)) == [1]
|
||||
assert list(H.predecessors(1)) == [0]
|
||||
assert list(H.successors(1)) == []
|
||||
@@ -1,110 +0,0 @@
|
||||
"""Original NetworkX graph tests"""
|
||||
import pytest
|
||||
|
||||
import networkx
|
||||
import networkx as nx
|
||||
|
||||
from .historical_tests import HistoricalTests
|
||||
|
||||
|
||||
class TestDiGraphHistorical(HistoricalTests):
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
HistoricalTests.setup_class()
|
||||
cls.G = nx.DiGraph
|
||||
|
||||
def test_in_degree(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
|
||||
assert sorted(d for n, d in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2]
|
||||
assert dict(G.in_degree()) == {
|
||||
"A": 0,
|
||||
"C": 2,
|
||||
"B": 1,
|
||||
"D": 2,
|
||||
"G": 0,
|
||||
"K": 0,
|
||||
"J": 0,
|
||||
}
|
||||
|
||||
def test_out_degree(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
assert sorted(v for k, v in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2]
|
||||
assert dict(G.out_degree()) == {
|
||||
"A": 2,
|
||||
"C": 1,
|
||||
"B": 2,
|
||||
"D": 0,
|
||||
"G": 0,
|
||||
"K": 0,
|
||||
"J": 0,
|
||||
}
|
||||
|
||||
def test_degree_digraph(self):
|
||||
H = nx.DiGraph()
|
||||
H.add_edges_from([(1, 24), (1, 2)])
|
||||
assert sorted(d for n, d in H.in_degree([1, 24])) == [0, 1]
|
||||
assert sorted(d for n, d in H.out_degree([1, 24])) == [0, 2]
|
||||
assert sorted(d for n, d in H.degree([1, 24])) == [1, 2]
|
||||
|
||||
def test_neighbors(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
|
||||
assert sorted(G.neighbors("C")) == ["D"]
|
||||
assert sorted(G["C"]) == ["D"]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "j")
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "j")
|
||||
|
||||
def test_successors(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
assert sorted(G.successors("A")) == ["B", "C"]
|
||||
assert sorted(G.successors("A")) == ["B", "C"]
|
||||
assert sorted(G.successors("G")) == []
|
||||
assert sorted(G.successors("D")) == []
|
||||
assert sorted(G.successors("G")) == []
|
||||
pytest.raises(nx.NetworkXError, G.successors, "j")
|
||||
pytest.raises(nx.NetworkXError, G.successors, "j")
|
||||
|
||||
def test_predecessors(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
assert sorted(G.predecessors("C")) == ["A", "B"]
|
||||
assert sorted(G.predecessors("C")) == ["A", "B"]
|
||||
assert sorted(G.predecessors("G")) == []
|
||||
assert sorted(G.predecessors("A")) == []
|
||||
assert sorted(G.predecessors("G")) == []
|
||||
assert sorted(G.predecessors("A")) == []
|
||||
assert sorted(G.successors("D")) == []
|
||||
|
||||
pytest.raises(nx.NetworkXError, G.predecessors, "j")
|
||||
pytest.raises(nx.NetworkXError, G.predecessors, "j")
|
||||
|
||||
def test_reverse(self):
|
||||
G = nx.complete_graph(10)
|
||||
H = G.to_directed()
|
||||
HR = H.reverse()
|
||||
assert nx.is_isomorphic(H, HR)
|
||||
assert sorted(H.edges()) == sorted(HR.edges())
|
||||
|
||||
def test_reverse2(self):
|
||||
H = nx.DiGraph()
|
||||
foo = [H.add_edge(u, u + 1) for u in range(0, 5)]
|
||||
HR = H.reverse()
|
||||
for u in range(0, 5):
|
||||
assert HR.has_edge(u + 1, u)
|
||||
|
||||
def test_reverse3(self):
|
||||
H = nx.DiGraph()
|
||||
H.add_nodes_from([1, 2, 3, 4])
|
||||
HR = H.reverse()
|
||||
assert sorted(HR.nodes()) == [1, 2, 3, 4]
|
||||
@@ -1,177 +0,0 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class TestFilterFactory:
|
||||
def test_no_filter(self):
|
||||
nf = nx.filters.no_filter
|
||||
assert nf()
|
||||
assert nf(1)
|
||||
assert nf(2, 1)
|
||||
|
||||
def test_hide_nodes(self):
|
||||
f = nx.classes.filters.hide_nodes([1, 2, 3])
|
||||
assert not f(1)
|
||||
assert not f(2)
|
||||
assert not f(3)
|
||||
assert f(4)
|
||||
assert f(0)
|
||||
assert f("a")
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f)
|
||||
|
||||
def test_show_nodes(self):
|
||||
f = nx.classes.filters.show_nodes([1, 2, 3])
|
||||
assert f(1)
|
||||
assert f(2)
|
||||
assert f(3)
|
||||
assert not f(4)
|
||||
assert not f(0)
|
||||
assert not f("a")
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f)
|
||||
|
||||
def test_hide_edges(self):
|
||||
factory = nx.classes.filters.hide_edges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert not f(1, 2)
|
||||
assert not f(3, 4)
|
||||
assert not f(4, 3)
|
||||
assert f(2, 3)
|
||||
assert f(0, -1)
|
||||
assert f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_show_edges(self):
|
||||
factory = nx.classes.filters.show_edges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert f(1, 2)
|
||||
assert f(3, 4)
|
||||
assert f(4, 3)
|
||||
assert not f(2, 3)
|
||||
assert not f(0, -1)
|
||||
assert not f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_hide_diedges(self):
|
||||
factory = nx.classes.filters.hide_diedges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert not f(1, 2)
|
||||
assert not f(3, 4)
|
||||
assert f(4, 3)
|
||||
assert f(2, 3)
|
||||
assert f(0, -1)
|
||||
assert f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_show_diedges(self):
|
||||
factory = nx.classes.filters.show_diedges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert f(1, 2)
|
||||
assert f(3, 4)
|
||||
assert not f(4, 3)
|
||||
assert not f(2, 3)
|
||||
assert not f(0, -1)
|
||||
assert not f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_hide_multiedges(self):
|
||||
factory = nx.classes.filters.hide_multiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert not f(1, 2, 0)
|
||||
assert not f(1, 2, 1)
|
||||
assert f(1, 2, 2)
|
||||
assert f(3, 4, 0)
|
||||
assert not f(3, 4, 1)
|
||||
assert not f(4, 3, 1)
|
||||
assert f(4, 3, 0)
|
||||
assert f(2, 3, 0)
|
||||
assert f(0, -1, 0)
|
||||
assert f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
|
||||
def test_show_multiedges(self):
|
||||
factory = nx.classes.filters.show_multiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert f(1, 2, 0)
|
||||
assert f(1, 2, 1)
|
||||
assert not f(1, 2, 2)
|
||||
assert not f(3, 4, 0)
|
||||
assert f(3, 4, 1)
|
||||
assert f(4, 3, 1)
|
||||
assert not f(4, 3, 0)
|
||||
assert not f(2, 3, 0)
|
||||
assert not f(0, -1, 0)
|
||||
assert not f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
|
||||
def test_hide_multidiedges(self):
|
||||
factory = nx.classes.filters.hide_multidiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert not f(1, 2, 0)
|
||||
assert not f(1, 2, 1)
|
||||
assert f(1, 2, 2)
|
||||
assert f(3, 4, 0)
|
||||
assert not f(3, 4, 1)
|
||||
assert f(4, 3, 1)
|
||||
assert f(4, 3, 0)
|
||||
assert f(2, 3, 0)
|
||||
assert f(0, -1, 0)
|
||||
assert f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
|
||||
def test_show_multidiedges(self):
|
||||
factory = nx.classes.filters.show_multidiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert f(1, 2, 0)
|
||||
assert f(1, 2, 1)
|
||||
assert not f(1, 2, 2)
|
||||
assert not f(3, 4, 0)
|
||||
assert f(3, 4, 1)
|
||||
assert not f(4, 3, 1)
|
||||
assert not f(4, 3, 0)
|
||||
assert not f(2, 3, 0)
|
||||
assert not f(0, -1, 0)
|
||||
assert not f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
@@ -1,782 +0,0 @@
|
||||
import random
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class TestFunction:
|
||||
def setup_method(self):
|
||||
self.G = nx.Graph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}, name="Test")
|
||||
self.Gdegree = {0: 3, 1: 2, 2: 2, 3: 1, 4: 0}
|
||||
self.Gnodes = list(range(5))
|
||||
self.Gedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
|
||||
self.DG = nx.DiGraph({0: [1, 2, 3], 1: [1, 2, 0], 4: []})
|
||||
self.DGin_degree = {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}
|
||||
self.DGout_degree = {0: 3, 1: 3, 2: 0, 3: 0, 4: 0}
|
||||
self.DGnodes = list(range(5))
|
||||
self.DGedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
|
||||
|
||||
def test_nodes(self):
|
||||
assert nodes_equal(self.G.nodes(), list(nx.nodes(self.G)))
|
||||
assert nodes_equal(self.DG.nodes(), list(nx.nodes(self.DG)))
|
||||
|
||||
def test_edges(self):
|
||||
assert edges_equal(self.G.edges(), list(nx.edges(self.G)))
|
||||
assert sorted(self.DG.edges()) == sorted(nx.edges(self.DG))
|
||||
assert edges_equal(
|
||||
self.G.edges(nbunch=[0, 1, 3]), list(nx.edges(self.G, nbunch=[0, 1, 3]))
|
||||
)
|
||||
assert sorted(self.DG.edges(nbunch=[0, 1, 3])) == sorted(
|
||||
nx.edges(self.DG, nbunch=[0, 1, 3])
|
||||
)
|
||||
|
||||
def test_degree(self):
|
||||
assert edges_equal(self.G.degree(), list(nx.degree(self.G)))
|
||||
assert sorted(self.DG.degree()) == sorted(nx.degree(self.DG))
|
||||
assert edges_equal(
|
||||
self.G.degree(nbunch=[0, 1]), list(nx.degree(self.G, nbunch=[0, 1]))
|
||||
)
|
||||
assert sorted(self.DG.degree(nbunch=[0, 1])) == sorted(
|
||||
nx.degree(self.DG, nbunch=[0, 1])
|
||||
)
|
||||
assert edges_equal(
|
||||
self.G.degree(weight="weight"), list(nx.degree(self.G, weight="weight"))
|
||||
)
|
||||
assert sorted(self.DG.degree(weight="weight")) == sorted(
|
||||
nx.degree(self.DG, weight="weight")
|
||||
)
|
||||
|
||||
def test_neighbors(self):
|
||||
assert list(self.G.neighbors(1)) == list(nx.neighbors(self.G, 1))
|
||||
assert list(self.DG.neighbors(1)) == list(nx.neighbors(self.DG, 1))
|
||||
|
||||
def test_number_of_nodes(self):
|
||||
assert self.G.number_of_nodes() == nx.number_of_nodes(self.G)
|
||||
assert self.DG.number_of_nodes() == nx.number_of_nodes(self.DG)
|
||||
|
||||
def test_number_of_edges(self):
|
||||
assert self.G.number_of_edges() == nx.number_of_edges(self.G)
|
||||
assert self.DG.number_of_edges() == nx.number_of_edges(self.DG)
|
||||
|
||||
def test_is_directed(self):
|
||||
assert self.G.is_directed() == nx.is_directed(self.G)
|
||||
assert self.DG.is_directed() == nx.is_directed(self.DG)
|
||||
|
||||
def test_add_star(self):
|
||||
G = self.G.copy()
|
||||
nlist = [12, 13, 14, 15]
|
||||
nx.add_star(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [(12, 13), (12, 14), (12, 15)])
|
||||
|
||||
G = self.G.copy()
|
||||
nx.add_star(G, nlist, weight=2.0)
|
||||
assert edges_equal(
|
||||
G.edges(nlist, data=True),
|
||||
[
|
||||
(12, 13, {"weight": 2.0}),
|
||||
(12, 14, {"weight": 2.0}),
|
||||
(12, 15, {"weight": 2.0}),
|
||||
],
|
||||
)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = [12]
|
||||
nx.add_star(G, nlist)
|
||||
assert nodes_equal(G, list(self.G) + nlist)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = []
|
||||
nx.add_star(G, nlist)
|
||||
assert nodes_equal(G.nodes, self.Gnodes)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
|
||||
def test_add_path(self):
|
||||
G = self.G.copy()
|
||||
nlist = [12, 13, 14, 15]
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [(12, 13), (13, 14), (14, 15)])
|
||||
G = self.G.copy()
|
||||
nx.add_path(G, nlist, weight=2.0)
|
||||
assert edges_equal(
|
||||
G.edges(nlist, data=True),
|
||||
[
|
||||
(12, 13, {"weight": 2.0}),
|
||||
(13, 14, {"weight": 2.0}),
|
||||
(14, 15, {"weight": 2.0}),
|
||||
],
|
||||
)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = ["node"]
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [])
|
||||
assert nodes_equal(G, list(self.G) + ["node"])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = iter(["node"])
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(["node"]), [])
|
||||
assert nodes_equal(G, list(self.G) + ["node"])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = [12]
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [])
|
||||
assert nodes_equal(G, list(self.G) + [12])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = iter([12])
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges([12]), [])
|
||||
assert nodes_equal(G, list(self.G) + [12])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = []
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = iter([])
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
|
||||
def test_add_cycle(self):
|
||||
G = self.G.copy()
|
||||
nlist = [12, 13, 14, 15]
|
||||
oklists = [
|
||||
[(12, 13), (12, 15), (13, 14), (14, 15)],
|
||||
[(12, 13), (13, 14), (14, 15), (15, 12)],
|
||||
]
|
||||
nx.add_cycle(G, nlist)
|
||||
assert sorted(G.edges(nlist)) in oklists
|
||||
G = self.G.copy()
|
||||
oklists = [
|
||||
[
|
||||
(12, 13, {"weight": 1.0}),
|
||||
(12, 15, {"weight": 1.0}),
|
||||
(13, 14, {"weight": 1.0}),
|
||||
(14, 15, {"weight": 1.0}),
|
||||
],
|
||||
[
|
||||
(12, 13, {"weight": 1.0}),
|
||||
(13, 14, {"weight": 1.0}),
|
||||
(14, 15, {"weight": 1.0}),
|
||||
(15, 12, {"weight": 1.0}),
|
||||
],
|
||||
]
|
||||
nx.add_cycle(G, nlist, weight=1.0)
|
||||
assert sorted(G.edges(nlist, data=True)) in oklists
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = [12]
|
||||
nx.add_cycle(G, nlist)
|
||||
assert nodes_equal(G, list(self.G) + nlist)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = []
|
||||
nx.add_cycle(G, nlist)
|
||||
assert nodes_equal(G.nodes, self.Gnodes)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
|
||||
def test_subgraph(self):
|
||||
assert (
|
||||
self.G.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.G, [0, 1, 2, 4]).adj
|
||||
)
|
||||
assert (
|
||||
self.DG.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.DG, [0, 1, 2, 4]).adj
|
||||
)
|
||||
assert (
|
||||
self.G.subgraph([0, 1, 2, 4]).adj
|
||||
== nx.induced_subgraph(self.G, [0, 1, 2, 4]).adj
|
||||
)
|
||||
assert (
|
||||
self.DG.subgraph([0, 1, 2, 4]).adj
|
||||
== nx.induced_subgraph(self.DG, [0, 1, 2, 4]).adj
|
||||
)
|
||||
# subgraph-subgraph chain is allowed in function interface
|
||||
H = nx.induced_subgraph(self.G.subgraph([0, 1, 2, 4]), [0, 1, 4])
|
||||
assert H._graph is not self.G
|
||||
assert H.adj == self.G.subgraph([0, 1, 4]).adj
|
||||
|
||||
def test_edge_subgraph(self):
|
||||
assert (
|
||||
self.G.edge_subgraph([(1, 2), (0, 3)]).adj
|
||||
== nx.edge_subgraph(self.G, [(1, 2), (0, 3)]).adj
|
||||
)
|
||||
assert (
|
||||
self.DG.edge_subgraph([(1, 2), (0, 3)]).adj
|
||||
== nx.edge_subgraph(self.DG, [(1, 2), (0, 3)]).adj
|
||||
)
|
||||
|
||||
def test_create_empty_copy(self):
|
||||
G = nx.create_empty_copy(self.G, with_data=False)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
assert G.graph == {}
|
||||
assert G._node == {}.fromkeys(self.G.nodes(), {})
|
||||
assert G._adj == {}.fromkeys(self.G.nodes(), {})
|
||||
G = nx.create_empty_copy(self.G)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
assert G.graph == self.G.graph
|
||||
assert G._node == self.G._node
|
||||
assert G._adj == {}.fromkeys(self.G.nodes(), {})
|
||||
|
||||
def test_degree_histogram(self):
|
||||
assert nx.degree_histogram(self.G) == [1, 1, 1, 1, 1]
|
||||
|
||||
def test_density(self):
|
||||
assert nx.density(self.G) == 0.5
|
||||
assert nx.density(self.DG) == 0.3
|
||||
G = nx.Graph()
|
||||
G.add_node(1)
|
||||
assert nx.density(G) == 0.0
|
||||
|
||||
def test_density_selfloop(self):
|
||||
G = nx.Graph()
|
||||
G.add_edge(1, 1)
|
||||
assert nx.density(G) == 0.0
|
||||
G.add_edge(1, 2)
|
||||
assert nx.density(G) == 2.0
|
||||
|
||||
def test_freeze(self):
|
||||
G = nx.freeze(self.G)
|
||||
assert G.frozen
|
||||
pytest.raises(nx.NetworkXError, G.add_node, 1)
|
||||
pytest.raises(nx.NetworkXError, G.add_nodes_from, [1])
|
||||
pytest.raises(nx.NetworkXError, G.remove_node, 1)
|
||||
pytest.raises(nx.NetworkXError, G.remove_nodes_from, [1])
|
||||
pytest.raises(nx.NetworkXError, G.add_edge, 1, 2)
|
||||
pytest.raises(nx.NetworkXError, G.add_edges_from, [(1, 2)])
|
||||
pytest.raises(nx.NetworkXError, G.remove_edge, 1, 2)
|
||||
pytest.raises(nx.NetworkXError, G.remove_edges_from, [(1, 2)])
|
||||
pytest.raises(nx.NetworkXError, G.clear_edges)
|
||||
pytest.raises(nx.NetworkXError, G.clear)
|
||||
|
||||
def test_is_frozen(self):
|
||||
assert not nx.is_frozen(self.G)
|
||||
G = nx.freeze(self.G)
|
||||
assert G.frozen == nx.is_frozen(self.G)
|
||||
assert G.frozen
|
||||
|
||||
def test_node_attributes_are_still_mutable_on_frozen_graph(self):
|
||||
G = nx.freeze(nx.path_graph(3))
|
||||
node = G.nodes[0]
|
||||
node["node_attribute"] = True
|
||||
assert node["node_attribute"] == True
|
||||
|
||||
def test_edge_attributes_are_still_mutable_on_frozen_graph(self):
|
||||
G = nx.freeze(nx.path_graph(3))
|
||||
edge = G.edges[(0, 1)]
|
||||
edge["edge_attribute"] = True
|
||||
assert edge["edge_attribute"] == True
|
||||
|
||||
def test_neighbors_complete_graph(self):
|
||||
graph = nx.complete_graph(100)
|
||||
pop = random.sample(list(graph), 1)
|
||||
nbors = list(nx.neighbors(graph, pop[0]))
|
||||
# should be all the other vertices in the graph
|
||||
assert len(nbors) == len(graph) - 1
|
||||
|
||||
graph = nx.path_graph(100)
|
||||
node = random.sample(list(graph), 1)[0]
|
||||
nbors = list(nx.neighbors(graph, node))
|
||||
# should be all the other vertices in the graph
|
||||
if node != 0 and node != 99:
|
||||
assert len(nbors) == 2
|
||||
else:
|
||||
assert len(nbors) == 1
|
||||
|
||||
# create a star graph with 99 outer nodes
|
||||
graph = nx.star_graph(99)
|
||||
nbors = list(nx.neighbors(graph, 0))
|
||||
assert len(nbors) == 99
|
||||
|
||||
def test_non_neighbors(self):
|
||||
graph = nx.complete_graph(100)
|
||||
pop = random.sample(list(graph), 1)
|
||||
nbors = list(nx.non_neighbors(graph, pop[0]))
|
||||
# should be all the other vertices in the graph
|
||||
assert len(nbors) == 0
|
||||
|
||||
graph = nx.path_graph(100)
|
||||
node = random.sample(list(graph), 1)[0]
|
||||
nbors = list(nx.non_neighbors(graph, node))
|
||||
# should be all the other vertices in the graph
|
||||
if node != 0 and node != 99:
|
||||
assert len(nbors) == 97
|
||||
else:
|
||||
assert len(nbors) == 98
|
||||
|
||||
# create a star graph with 99 outer nodes
|
||||
graph = nx.star_graph(99)
|
||||
nbors = list(nx.non_neighbors(graph, 0))
|
||||
assert len(nbors) == 0
|
||||
|
||||
# disconnected graph
|
||||
graph = nx.Graph()
|
||||
graph.add_nodes_from(range(10))
|
||||
nbors = list(nx.non_neighbors(graph, 0))
|
||||
assert len(nbors) == 9
|
||||
|
||||
def test_non_edges(self):
|
||||
# All possible edges exist
|
||||
graph = nx.complete_graph(5)
|
||||
nedges = list(nx.non_edges(graph))
|
||||
assert len(nedges) == 0
|
||||
|
||||
graph = nx.path_graph(4)
|
||||
expected = [(0, 2), (0, 3), (1, 3)]
|
||||
nedges = list(nx.non_edges(graph))
|
||||
for u, v in expected:
|
||||
assert (u, v) in nedges or (v, u) in nedges
|
||||
|
||||
graph = nx.star_graph(4)
|
||||
expected = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
|
||||
nedges = list(nx.non_edges(graph))
|
||||
for u, v in expected:
|
||||
assert (u, v) in nedges or (v, u) in nedges
|
||||
|
||||
# Directed graphs
|
||||
graph = nx.DiGraph()
|
||||
graph.add_edges_from([(0, 2), (2, 0), (2, 1)])
|
||||
expected = [(0, 1), (1, 0), (1, 2)]
|
||||
nedges = list(nx.non_edges(graph))
|
||||
for e in expected:
|
||||
assert e in nedges
|
||||
|
||||
def test_is_weighted(self):
|
||||
G = nx.Graph()
|
||||
assert not nx.is_weighted(G)
|
||||
|
||||
G = nx.path_graph(4)
|
||||
assert not nx.is_weighted(G)
|
||||
assert not nx.is_weighted(G, (2, 3))
|
||||
|
||||
G.add_node(4)
|
||||
G.add_edge(3, 4, weight=4)
|
||||
assert not nx.is_weighted(G)
|
||||
assert nx.is_weighted(G, (3, 4))
|
||||
|
||||
G = nx.DiGraph()
|
||||
G.add_weighted_edges_from(
|
||||
[
|
||||
("0", "3", 3),
|
||||
("0", "1", -5),
|
||||
("1", "0", -5),
|
||||
("0", "2", 2),
|
||||
("1", "2", 4),
|
||||
("2", "3", 1),
|
||||
]
|
||||
)
|
||||
assert nx.is_weighted(G)
|
||||
assert nx.is_weighted(G, ("1", "0"))
|
||||
|
||||
G = G.to_undirected()
|
||||
assert nx.is_weighted(G)
|
||||
assert nx.is_weighted(G, ("1", "0"))
|
||||
|
||||
pytest.raises(nx.NetworkXError, nx.is_weighted, G, (1, 2))
|
||||
|
||||
def test_is_negatively_weighted(self):
|
||||
G = nx.Graph()
|
||||
assert not nx.is_negatively_weighted(G)
|
||||
|
||||
G.add_node(1)
|
||||
G.add_nodes_from([2, 3, 4, 5])
|
||||
assert not nx.is_negatively_weighted(G)
|
||||
|
||||
G.add_edge(1, 2, weight=4)
|
||||
assert not nx.is_negatively_weighted(G, (1, 2))
|
||||
|
||||
G.add_edges_from([(1, 3), (2, 4), (2, 6)])
|
||||
G[1][3]["color"] = "blue"
|
||||
assert not nx.is_negatively_weighted(G)
|
||||
assert not nx.is_negatively_weighted(G, (1, 3))
|
||||
|
||||
G[2][4]["weight"] = -2
|
||||
assert nx.is_negatively_weighted(G, (2, 4))
|
||||
assert nx.is_negatively_weighted(G)
|
||||
|
||||
G = nx.DiGraph()
|
||||
G.add_weighted_edges_from(
|
||||
[
|
||||
("0", "3", 3),
|
||||
("0", "1", -5),
|
||||
("1", "0", -2),
|
||||
("0", "2", 2),
|
||||
("1", "2", -3),
|
||||
("2", "3", 1),
|
||||
]
|
||||
)
|
||||
assert nx.is_negatively_weighted(G)
|
||||
assert not nx.is_negatively_weighted(G, ("0", "3"))
|
||||
assert nx.is_negatively_weighted(G, ("1", "0"))
|
||||
|
||||
pytest.raises(nx.NetworkXError, nx.is_negatively_weighted, G, (1, 4))
|
||||
|
||||
|
||||
class TestCommonNeighbors:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.func = staticmethod(nx.common_neighbors)
|
||||
|
||||
def test_func(G, u, v, expected):
|
||||
result = sorted(cls.func(G, u, v))
|
||||
assert result == expected
|
||||
|
||||
cls.test = staticmethod(test_func)
|
||||
|
||||
def test_K5(self):
|
||||
G = nx.complete_graph(5)
|
||||
self.test(G, 0, 1, [2, 3, 4])
|
||||
|
||||
def test_P3(self):
|
||||
G = nx.path_graph(3)
|
||||
self.test(G, 0, 2, [1])
|
||||
|
||||
def test_S4(self):
|
||||
G = nx.star_graph(4)
|
||||
self.test(G, 1, 2, [0])
|
||||
|
||||
def test_digraph(self):
|
||||
with pytest.raises(nx.NetworkXNotImplemented):
|
||||
G = nx.DiGraph()
|
||||
G.add_edges_from([(0, 1), (1, 2)])
|
||||
self.func(G, 0, 2)
|
||||
|
||||
def test_nonexistent_nodes(self):
|
||||
G = nx.complete_graph(5)
|
||||
pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 4)
|
||||
pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 4, 5)
|
||||
pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 6)
|
||||
|
||||
def test_custom1(self):
|
||||
"""Case of no common neighbors."""
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from([0, 1])
|
||||
self.test(G, 0, 1, [])
|
||||
|
||||
def test_custom2(self):
|
||||
"""Case of equal nodes."""
|
||||
G = nx.complete_graph(4)
|
||||
self.test(G, 0, 0, [1, 2, 3])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
|
||||
)
|
||||
def test_set_node_attributes(graph_type):
|
||||
# Test single value
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
vals = 100
|
||||
attr = "hello"
|
||||
nx.set_node_attributes(G, vals, attr)
|
||||
assert G.nodes[0][attr] == vals
|
||||
assert G.nodes[1][attr] == vals
|
||||
assert G.nodes[2][attr] == vals
|
||||
|
||||
# Test dictionary
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
vals = dict(zip(sorted(G.nodes()), range(len(G))))
|
||||
attr = "hi"
|
||||
nx.set_node_attributes(G, vals, attr)
|
||||
assert G.nodes[0][attr] == 0
|
||||
assert G.nodes[1][attr] == 1
|
||||
assert G.nodes[2][attr] == 2
|
||||
|
||||
# Test dictionary of dictionaries
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
d = {"hi": 0, "hello": 200}
|
||||
vals = dict.fromkeys(G.nodes(), d)
|
||||
vals.pop(0)
|
||||
nx.set_node_attributes(G, vals)
|
||||
assert G.nodes[0] == {}
|
||||
assert G.nodes[1]["hi"] == 0
|
||||
assert G.nodes[2]["hello"] == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("values", "name"),
|
||||
(
|
||||
({0: "red", 1: "blue"}, "color"), # values dictionary
|
||||
({0: {"color": "red"}, 1: {"color": "blue"}}, None), # dict-of-dict
|
||||
),
|
||||
)
|
||||
def test_set_node_attributes_ignores_extra_nodes(values, name):
|
||||
"""
|
||||
When `values` is a dict or dict-of-dict keyed by nodes, ensure that keys
|
||||
that correspond to nodes not in G are ignored.
|
||||
"""
|
||||
G = nx.Graph()
|
||||
G.add_node(0)
|
||||
nx.set_node_attributes(G, values, name)
|
||||
assert G.nodes[0]["color"] == "red"
|
||||
assert 1 not in G.nodes
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
||||
def test_set_edge_attributes(graph_type):
|
||||
# Test single value
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hello"
|
||||
vals = 3
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][attr] == vals
|
||||
assert G[1][2][attr] == vals
|
||||
|
||||
# Test multiple values
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hi"
|
||||
edges = [(0, 1), (1, 2)]
|
||||
vals = dict(zip(edges, range(len(edges))))
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][attr] == 0
|
||||
assert G[1][2][attr] == 1
|
||||
|
||||
# Test dictionary of dictionaries
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
d = {"hi": 0, "hello": 200}
|
||||
edges = [(0, 1)]
|
||||
vals = dict.fromkeys(edges, d)
|
||||
nx.set_edge_attributes(G, vals)
|
||||
assert G[0][1]["hi"] == 0
|
||||
assert G[0][1]["hello"] == 200
|
||||
assert G[1][2] == {}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("values", "name"),
|
||||
(
|
||||
({(0, 1): 1.0, (0, 2): 2.0}, "weight"), # values dict
|
||||
({(0, 1): {"weight": 1.0}, (0, 2): {"weight": 2.0}}, None), # values dod
|
||||
),
|
||||
)
|
||||
def test_set_edge_attributes_ignores_extra_edges(values, name):
|
||||
"""If `values` is a dict or dict-of-dicts containing edges that are not in
|
||||
G, data associate with these edges should be ignored.
|
||||
"""
|
||||
G = nx.Graph([(0, 1)])
|
||||
nx.set_edge_attributes(G, values, name)
|
||||
assert G[0][1]["weight"] == 1.0
|
||||
assert (0, 2) not in G.edges
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph))
|
||||
def test_set_edge_attributes_multi(graph_type):
|
||||
# Test single value
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hello"
|
||||
vals = 3
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][0][attr] == vals
|
||||
assert G[1][2][0][attr] == vals
|
||||
|
||||
# Test multiple values
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hi"
|
||||
edges = [(0, 1, 0), (1, 2, 0)]
|
||||
vals = dict(zip(edges, range(len(edges))))
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][0][attr] == 0
|
||||
assert G[1][2][0][attr] == 1
|
||||
|
||||
# Test dictionary of dictionaries
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
d = {"hi": 0, "hello": 200}
|
||||
edges = [(0, 1, 0)]
|
||||
vals = dict.fromkeys(edges, d)
|
||||
nx.set_edge_attributes(G, vals)
|
||||
assert G[0][1][0]["hi"] == 0
|
||||
assert G[0][1][0]["hello"] == 200
|
||||
assert G[1][2][0] == {}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("values", "name"),
|
||||
(
|
||||
({(0, 1, 0): 1.0, (0, 2, 0): 2.0}, "weight"), # values dict
|
||||
({(0, 1, 0): {"weight": 1.0}, (0, 2, 0): {"weight": 2.0}}, None), # values dod
|
||||
),
|
||||
)
|
||||
def test_set_edge_attributes_multi_ignores_extra_edges(values, name):
|
||||
"""If `values` is a dict or dict-of-dicts containing edges that are not in
|
||||
G, data associate with these edges should be ignored.
|
||||
"""
|
||||
G = nx.MultiGraph([(0, 1, 0), (0, 1, 1)])
|
||||
nx.set_edge_attributes(G, values, name)
|
||||
assert G[0][1][0]["weight"] == 1.0
|
||||
assert G[0][1][1] == {}
|
||||
assert (0, 2) not in G.edges()
|
||||
|
||||
|
||||
def test_get_node_attributes():
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
for G in graphs:
|
||||
G = nx.path_graph(3, create_using=G)
|
||||
attr = "hello"
|
||||
vals = 100
|
||||
nx.set_node_attributes(G, vals, attr)
|
||||
attrs = nx.get_node_attributes(G, attr)
|
||||
assert attrs[0] == vals
|
||||
assert attrs[1] == vals
|
||||
assert attrs[2] == vals
|
||||
|
||||
|
||||
def test_get_edge_attributes():
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
for G in graphs:
|
||||
G = nx.path_graph(3, create_using=G)
|
||||
attr = "hello"
|
||||
vals = 100
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
attrs = nx.get_edge_attributes(G, attr)
|
||||
|
||||
assert len(attrs) == 2
|
||||
if G.is_multigraph():
|
||||
keys = [(0, 1, 0), (1, 2, 0)]
|
||||
for u, v, k in keys:
|
||||
try:
|
||||
assert attrs[(u, v, k)] == 100
|
||||
except KeyError:
|
||||
assert attrs[(v, u, k)] == 100
|
||||
else:
|
||||
keys = [(0, 1), (1, 2)]
|
||||
for u, v in keys:
|
||||
try:
|
||||
assert attrs[(u, v)] == 100
|
||||
except KeyError:
|
||||
assert attrs[(v, u)] == 100
|
||||
|
||||
|
||||
def test_is_empty():
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
for G in graphs:
|
||||
assert nx.is_empty(G)
|
||||
G.add_nodes_from(range(5))
|
||||
assert nx.is_empty(G)
|
||||
G.add_edges_from([(1, 2), (3, 4)])
|
||||
assert not nx.is_empty(G)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
||||
)
|
||||
def test_selfloops(graph_type):
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
G.add_edge(0, 0)
|
||||
assert nodes_equal(nx.nodes_with_selfloops(G), [0])
|
||||
assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
|
||||
assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})])
|
||||
assert nx.number_of_selfloops(G) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
||||
)
|
||||
def test_selfloop_edges_attr(graph_type):
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(1, 1, weight=2)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
|
||||
)
|
||||
assert edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)])
|
||||
|
||||
|
||||
def test_selfloop_edges_multi_with_data_and_keys():
|
||||
G = nx.complete_graph(3, create_using=nx.MultiGraph)
|
||||
G.add_edge(0, 0, weight=10)
|
||||
G.add_edge(0, 0, weight=100)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data="weight", keys=True), [(0, 0, 0, 10), (0, 0, 1, 100)]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", [nx.Graph, nx.DiGraph])
|
||||
def test_selfloops_removal(graph_type):
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G, keys=True))
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G, data=True))
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", [nx.MultiGraph, nx.MultiDiGraph])
|
||||
def test_selfloops_removal_multi(graph_type):
|
||||
"""test removing selfloops behavior vis-a-vis altering a dict while iterating.
|
||||
cf. gh-4068"""
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
# Defaults - see gh-4080
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G))
|
||||
assert (0, 0) not in G.edges()
|
||||
# With keys
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
with pytest.raises(RuntimeError):
|
||||
G.remove_edges_from(nx.selfloop_edges(G, keys=True))
|
||||
# With data
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
with pytest.raises(TypeError):
|
||||
G.remove_edges_from(nx.selfloop_edges(G, data=True))
|
||||
# With keys and data
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
with pytest.raises(RuntimeError):
|
||||
G.remove_edges_from(nx.selfloop_edges(G, data=True, keys=True))
|
||||
|
||||
|
||||
def test_pathweight():
|
||||
valid_path = [1, 2, 3]
|
||||
invalid_path = [1, 3, 2]
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
edges = [
|
||||
(1, 2, {"cost": 5, "dist": 6}),
|
||||
(2, 3, {"cost": 3, "dist": 4}),
|
||||
(1, 2, {"cost": 1, "dist": 2}),
|
||||
]
|
||||
for graph in graphs:
|
||||
graph.add_edges_from(edges)
|
||||
assert nx.path_weight(graph, valid_path, "cost") == 4
|
||||
assert nx.path_weight(graph, valid_path, "dist") == 6
|
||||
pytest.raises(nx.NetworkXNoPath, nx.path_weight, graph, invalid_path, "cost")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"G", (nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph())
|
||||
)
|
||||
def test_ispath(G):
|
||||
G.add_edges_from([(1, 2), (2, 3), (1, 2), (3, 4)])
|
||||
valid_path = [1, 2, 3, 4]
|
||||
invalid_path = [1, 2, 4, 3] # wrong node order
|
||||
another_invalid_path = [1, 2, 3, 4, 5] # contains node not in G
|
||||
assert nx.is_path(G, valid_path)
|
||||
assert not nx.is_path(G, invalid_path)
|
||||
assert not nx.is_path(G, another_invalid_path)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
|
||||
def test_restricted_view(G):
|
||||
G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)])
|
||||
G.add_node(4)
|
||||
H = nx.restricted_view(G, [0, 2, 5], [(1, 2), (3, 4)])
|
||||
assert set(H.nodes()) == {1, 3, 4}
|
||||
assert set(H.edges()) == {(1, 1)}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.MultiGraph(), nx.MultiDiGraph()))
|
||||
def test_restricted_view_multi(G):
|
||||
G.add_edges_from(
|
||||
[(0, 1, 0), (0, 2, 0), (0, 3, 0), (0, 1, 1), (1, 0, 0), (1, 1, 0), (1, 2, 0)]
|
||||
)
|
||||
G.add_node(4)
|
||||
H = nx.restricted_view(G, [0, 2, 5], [(1, 2, 0), (3, 4, 0)])
|
||||
assert set(H.nodes()) == {1, 3, 4}
|
||||
assert set(H.edges()) == {(1, 1)}
|
||||
@@ -1,920 +0,0 @@
|
||||
import gc
|
||||
import pickle
|
||||
import platform
|
||||
import weakref
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
||||
|
||||
|
||||
class BaseGraphTester:
|
||||
"""Tests for data-structure independent graph class features."""
|
||||
|
||||
def test_contains(self):
|
||||
G = self.K3
|
||||
assert 1 in G
|
||||
assert 4 not in G
|
||||
assert "b" not in G
|
||||
assert [] not in G # no exception for nonhashable
|
||||
assert {1: 1} not in G # no exception for nonhashable
|
||||
|
||||
def test_order(self):
|
||||
G = self.K3
|
||||
assert len(G) == 3
|
||||
assert G.order() == 3
|
||||
assert G.number_of_nodes() == 3
|
||||
|
||||
def test_nodes(self):
|
||||
G = self.K3
|
||||
assert isinstance(G._node, G.node_dict_factory)
|
||||
assert isinstance(G._adj, G.adjlist_outer_dict_factory)
|
||||
assert all(
|
||||
isinstance(adj, G.adjlist_inner_dict_factory) for adj in G._adj.values()
|
||||
)
|
||||
assert sorted(G.nodes()) == self.k3nodes
|
||||
assert sorted(G.nodes(data=True)) == [(0, {}), (1, {}), (2, {})]
|
||||
|
||||
def test_none_node(self):
|
||||
G = self.Graph()
|
||||
with pytest.raises(ValueError):
|
||||
G.add_node(None)
|
||||
with pytest.raises(ValueError):
|
||||
G.add_nodes_from([None])
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edge(0, None)
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edges_from([(0, None)])
|
||||
|
||||
def test_has_node(self):
|
||||
G = self.K3
|
||||
assert G.has_node(1)
|
||||
assert not G.has_node(4)
|
||||
assert not G.has_node([]) # no exception for nonhashable
|
||||
assert not G.has_node({1: 1}) # no exception for nonhashable
|
||||
|
||||
def test_has_edge(self):
|
||||
G = self.K3
|
||||
assert G.has_edge(0, 1)
|
||||
assert not G.has_edge(0, -1)
|
||||
|
||||
def test_neighbors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.neighbors(0)) == [1, 2]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.neighbors(-1)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
platform.python_implementation() == "PyPy", reason="PyPy gc is different"
|
||||
)
|
||||
def test_memory_leak(self):
|
||||
G = self.Graph()
|
||||
|
||||
def count_objects_of_type(_type):
|
||||
# Iterating over all objects tracked by gc can include weak references
|
||||
# whose weakly-referenced objects may no longer exist. Calling `isinstance`
|
||||
# on such a weak reference will raise ReferenceError. There are at least
|
||||
# three workarounds for this: one is to compare type names instead of using
|
||||
# `isinstance` such as `type(obj).__name__ == typename`, another is to use
|
||||
# `type(obj) == _type`, and the last is to ignore ProxyTypes as we do below.
|
||||
# NOTE: even if this safeguard is deemed unnecessary to pass NetworkX tests,
|
||||
# we should still keep it for maximum safety for other NetworkX backends.
|
||||
return sum(
|
||||
1
|
||||
for obj in gc.get_objects()
|
||||
if not isinstance(obj, weakref.ProxyTypes) and isinstance(obj, _type)
|
||||
)
|
||||
|
||||
gc.collect()
|
||||
before = count_objects_of_type(self.Graph)
|
||||
G.copy()
|
||||
gc.collect()
|
||||
after = count_objects_of_type(self.Graph)
|
||||
assert before == after
|
||||
|
||||
# test a subgraph of the base class
|
||||
class MyGraph(self.Graph):
|
||||
pass
|
||||
|
||||
gc.collect()
|
||||
G = MyGraph()
|
||||
before = count_objects_of_type(MyGraph)
|
||||
G.copy()
|
||||
gc.collect()
|
||||
after = count_objects_of_type(MyGraph)
|
||||
assert before == after
|
||||
|
||||
def test_edges(self):
|
||||
G = self.K3
|
||||
assert isinstance(G._adj, G.adjlist_outer_dict_factory)
|
||||
assert edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)])
|
||||
assert edges_equal(G.edges(0), [(0, 1), (0, 2)])
|
||||
assert edges_equal(G.edges([0, 1]), [(0, 1), (0, 2), (1, 2)])
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1)
|
||||
|
||||
def test_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.degree(0) == 2
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.degree(-1) # node not in graph
|
||||
|
||||
def test_size(self):
|
||||
G = self.K3
|
||||
assert G.size() == 3
|
||||
assert G.number_of_edges() == 3
|
||||
|
||||
def test_nbunch_iter(self):
|
||||
G = self.K3
|
||||
assert nodes_equal(G.nbunch_iter(), self.k3nodes) # all nodes
|
||||
assert nodes_equal(G.nbunch_iter(0), [0]) # single node
|
||||
assert nodes_equal(G.nbunch_iter([0, 1]), [0, 1]) # sequence
|
||||
# sequence with none in graph
|
||||
assert nodes_equal(G.nbunch_iter([-1]), [])
|
||||
# string sequence with none in graph
|
||||
assert nodes_equal(G.nbunch_iter("foo"), [])
|
||||
# node not in graph doesn't get caught upon creation of iterator
|
||||
bunch = G.nbunch_iter(-1)
|
||||
# but gets caught when iterator used
|
||||
with pytest.raises(nx.NetworkXError, match="is not a node or a sequence"):
|
||||
list(bunch)
|
||||
# unhashable doesn't get caught upon creation of iterator
|
||||
bunch = G.nbunch_iter([0, 1, 2, {}])
|
||||
# but gets caught when iterator hits the unhashable
|
||||
with pytest.raises(
|
||||
nx.NetworkXError, match="in sequence nbunch is not a valid node"
|
||||
):
|
||||
list(bunch)
|
||||
|
||||
def test_nbunch_iter_node_format_raise(self):
|
||||
# Tests that a node that would have failed string formatting
|
||||
# doesn't cause an error when attempting to raise a
|
||||
# :exc:`nx.NetworkXError`.
|
||||
|
||||
# For more information, see pull request #1813.
|
||||
G = self.Graph()
|
||||
nbunch = [("x", set())]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
list(G.nbunch_iter(nbunch))
|
||||
|
||||
def test_selfloop_degree(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 1)
|
||||
assert sorted(G.degree()) == [(1, 2)]
|
||||
assert dict(G.degree()) == {1: 2}
|
||||
assert G.degree(1) == 2
|
||||
assert sorted(G.degree([1])) == [(1, 2)]
|
||||
assert G.degree(1, weight="weight") == 2
|
||||
|
||||
def test_selfloops(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 0)
|
||||
assert nodes_equal(nx.nodes_with_selfloops(G), [0])
|
||||
assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
|
||||
assert nx.number_of_selfloops(G) == 1
|
||||
G.remove_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from([(0, 0)])
|
||||
G.add_edge(1, 1)
|
||||
G.remove_node(1)
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(1, 1)
|
||||
G.remove_nodes_from([0, 1])
|
||||
|
||||
def test_cache_reset(self):
|
||||
G = self.K3.copy()
|
||||
old_adj = G.adj
|
||||
assert id(G.adj) == id(old_adj)
|
||||
G._adj = {}
|
||||
assert id(G.adj) != id(old_adj)
|
||||
|
||||
old_nodes = G.nodes
|
||||
assert id(G.nodes) == id(old_nodes)
|
||||
G._node = {}
|
||||
assert id(G.nodes) != id(old_nodes)
|
||||
|
||||
def test_attributes_cached(self):
|
||||
G = self.K3.copy()
|
||||
assert id(G.nodes) == id(G.nodes)
|
||||
assert id(G.edges) == id(G.edges)
|
||||
assert id(G.degree) == id(G.degree)
|
||||
assert id(G.adj) == id(G.adj)
|
||||
|
||||
|
||||
class BaseAttrGraphTester(BaseGraphTester):
|
||||
"""Tests of graph class attribute features."""
|
||||
|
||||
def test_weighted_degree(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, weight=2, other=3)
|
||||
G.add_edge(2, 3, weight=3, other=4)
|
||||
assert sorted(d for n, d in G.degree(weight="weight")) == [2, 3, 5]
|
||||
assert dict(G.degree(weight="weight")) == {1: 2, 2: 5, 3: 3}
|
||||
assert G.degree(1, weight="weight") == 2
|
||||
assert nodes_equal((G.degree([1], weight="weight")), [(1, 2)])
|
||||
|
||||
assert nodes_equal((d for n, d in G.degree(weight="other")), [3, 7, 4])
|
||||
assert dict(G.degree(weight="other")) == {1: 3, 2: 7, 3: 4}
|
||||
assert G.degree(1, weight="other") == 3
|
||||
assert edges_equal((G.degree([1], weight="other")), [(1, 3)])
|
||||
|
||||
def add_attributes(self, G):
|
||||
G.graph["foo"] = []
|
||||
G.nodes[0]["foo"] = []
|
||||
G.remove_edge(1, 2)
|
||||
ll = []
|
||||
G.add_edge(1, 2, foo=ll)
|
||||
G.add_edge(2, 1, foo=ll)
|
||||
|
||||
def test_name(self):
|
||||
G = self.Graph(name="")
|
||||
assert G.name == ""
|
||||
G = self.Graph(name="test")
|
||||
assert G.name == "test"
|
||||
|
||||
def test_str_unnamed(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
assert str(G) == f"{type(G).__name__} with 3 nodes and 2 edges"
|
||||
|
||||
def test_str_named(self):
|
||||
G = self.Graph(name="foo")
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
assert str(G) == f"{type(G).__name__} named 'foo' with 3 nodes and 2 edges"
|
||||
|
||||
def test_graph_chain(self):
|
||||
G = self.Graph([(0, 1), (1, 2)])
|
||||
DG = G.to_directed(as_view=True)
|
||||
SDG = DG.subgraph([0, 1])
|
||||
RSDG = SDG.reverse(copy=False)
|
||||
assert G is DG._graph
|
||||
assert DG is SDG._graph
|
||||
assert SDG is RSDG._graph
|
||||
|
||||
def test_copy(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
G.add_edge(1, 2)
|
||||
self.add_attributes(G)
|
||||
# copy edge datadict but any container attr are same
|
||||
H = G.copy()
|
||||
self.graphs_equal(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
def test_class_copy(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
G.add_edge(1, 2)
|
||||
self.add_attributes(G)
|
||||
# copy edge datadict but any container attr are same
|
||||
H = G.__class__(G)
|
||||
self.graphs_equal(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
def test_fresh_copy(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
G.add_edge(1, 2)
|
||||
self.add_attributes(G)
|
||||
# copy graph structure but use fresh datadict
|
||||
H = G.__class__()
|
||||
H.add_nodes_from(G)
|
||||
H.add_edges_from(G.edges())
|
||||
assert len(G.nodes[0]) == 1
|
||||
ddict = G.adj[1][2][0] if G.is_multigraph() else G.adj[1][2]
|
||||
assert len(ddict) == 1
|
||||
assert len(H.nodes[0]) == 0
|
||||
ddict = H.adj[1][2][0] if H.is_multigraph() else H.adj[1][2]
|
||||
assert len(ddict) == 0
|
||||
|
||||
def is_deepcopy(self, H, G):
|
||||
self.graphs_equal(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
self.deep_copy_attrdict(H, G)
|
||||
|
||||
def deep_copy_attrdict(self, H, G):
|
||||
self.deepcopy_graph_attr(H, G)
|
||||
self.deepcopy_node_attr(H, G)
|
||||
self.deepcopy_edge_attr(H, G)
|
||||
|
||||
def deepcopy_graph_attr(self, H, G):
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] != H.graph["foo"]
|
||||
|
||||
def deepcopy_node_attr(self, H, G):
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] != H.nodes[0]["foo"]
|
||||
|
||||
def deepcopy_edge_attr(self, H, G):
|
||||
assert G[1][2]["foo"] == H[1][2]["foo"]
|
||||
G[1][2]["foo"].append(1)
|
||||
assert G[1][2]["foo"] != H[1][2]["foo"]
|
||||
|
||||
def is_shallow_copy(self, H, G):
|
||||
self.graphs_equal(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
def shallow_copy_attrdict(self, H, G):
|
||||
self.shallow_copy_graph_attr(H, G)
|
||||
self.shallow_copy_node_attr(H, G)
|
||||
self.shallow_copy_edge_attr(H, G)
|
||||
|
||||
def shallow_copy_graph_attr(self, H, G):
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
|
||||
def shallow_copy_node_attr(self, H, G):
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
|
||||
def shallow_copy_edge_attr(self, H, G):
|
||||
assert G[1][2]["foo"] == H[1][2]["foo"]
|
||||
G[1][2]["foo"].append(1)
|
||||
assert G[1][2]["foo"] == H[1][2]["foo"]
|
||||
|
||||
def same_attrdict(self, H, G):
|
||||
old_foo = H[1][2]["foo"]
|
||||
H.adj[1][2]["foo"] = "baz"
|
||||
assert G.edges == H.edges
|
||||
H.adj[1][2]["foo"] = old_foo
|
||||
assert G.edges == H.edges
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G.nodes == H.nodes
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G.nodes == H.nodes
|
||||
|
||||
def different_attrdict(self, H, G):
|
||||
old_foo = H[1][2]["foo"]
|
||||
H.adj[1][2]["foo"] = "baz"
|
||||
assert G._adj != H._adj
|
||||
H.adj[1][2]["foo"] = old_foo
|
||||
assert G._adj == H._adj
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G._node != H._node
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G._node == H._node
|
||||
|
||||
def graphs_equal(self, H, G):
|
||||
assert G._adj == H._adj
|
||||
assert G._node == H._node
|
||||
assert G.graph == H.graph
|
||||
assert G.name == H.name
|
||||
if not G.is_directed() and not H.is_directed():
|
||||
assert H._adj[1][2] is H._adj[2][1]
|
||||
assert G._adj[1][2] is G._adj[2][1]
|
||||
else: # at least one is directed
|
||||
if not G.is_directed():
|
||||
G._pred = G._adj
|
||||
G._succ = G._adj
|
||||
if not H.is_directed():
|
||||
H._pred = H._adj
|
||||
H._succ = H._adj
|
||||
assert G._pred == H._pred
|
||||
assert G._succ == H._succ
|
||||
assert H._succ[1][2] is H._pred[2][1]
|
||||
assert G._succ[1][2] is G._pred[2][1]
|
||||
|
||||
def test_graph_attr(self):
|
||||
G = self.K3.copy()
|
||||
G.graph["foo"] = "bar"
|
||||
assert isinstance(G.graph, G.graph_attr_dict_factory)
|
||||
assert G.graph["foo"] == "bar"
|
||||
del G.graph["foo"]
|
||||
assert G.graph == {}
|
||||
H = self.Graph(foo="bar")
|
||||
assert H.graph["foo"] == "bar"
|
||||
|
||||
def test_node_attr(self):
|
||||
G = self.K3.copy()
|
||||
G.add_node(1, foo="bar")
|
||||
assert all(
|
||||
isinstance(d, G.node_attr_dict_factory) for u, d in G.nodes(data=True)
|
||||
)
|
||||
assert nodes_equal(G.nodes(), [0, 1, 2])
|
||||
assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "bar"}), (2, {})])
|
||||
G.nodes[1]["foo"] = "baz"
|
||||
assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "baz"}), (2, {})])
|
||||
assert nodes_equal(G.nodes(data="foo"), [(0, None), (1, "baz"), (2, None)])
|
||||
assert nodes_equal(
|
||||
G.nodes(data="foo", default="bar"), [(0, "bar"), (1, "baz"), (2, "bar")]
|
||||
)
|
||||
|
||||
def test_node_attr2(self):
|
||||
G = self.K3.copy()
|
||||
a = {"foo": "bar"}
|
||||
G.add_node(3, **a)
|
||||
assert nodes_equal(G.nodes(), [0, 1, 2, 3])
|
||||
assert nodes_equal(
|
||||
G.nodes(data=True), [(0, {}), (1, {}), (2, {}), (3, {"foo": "bar"})]
|
||||
)
|
||||
|
||||
def test_edge_lookup(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, foo="bar")
|
||||
assert edges_equal(G.edges[1, 2], {"foo": "bar"})
|
||||
|
||||
def test_edge_attr(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, foo="bar")
|
||||
assert all(
|
||||
isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True)
|
||||
)
|
||||
assert edges_equal(G.edges(data=True), [(1, 2, {"foo": "bar"})])
|
||||
assert edges_equal(G.edges(data="foo"), [(1, 2, "bar")])
|
||||
|
||||
def test_edge_attr2(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(1, 2), (3, 4)], foo="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"foo": "foo"}), (3, 4, {"foo": "foo"})]
|
||||
)
|
||||
assert edges_equal(G.edges(data="foo"), [(1, 2, "foo"), (3, 4, "foo")])
|
||||
|
||||
def test_edge_attr3(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(1, 2, {"weight": 32}), (3, 4, {"weight": 64})], foo="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True),
|
||||
[
|
||||
(1, 2, {"foo": "foo", "weight": 32}),
|
||||
(3, 4, {"foo": "foo", "weight": 64}),
|
||||
],
|
||||
)
|
||||
|
||||
G.remove_edges_from([(1, 2), (3, 4)])
|
||||
G.add_edge(1, 2, data=7, spam="bar", bar="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
|
||||
def test_edge_attr4(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, data=7, spam="bar", bar="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G[1][2]["data"] = 10 # OK to set data like this
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
|
||||
G.adj[1][2]["data"] = 20
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.edges[1, 2]["data"] = 21 # another spelling, "edge"
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.adj[1][2]["listdata"] = [20, 200]
|
||||
G.adj[1][2]["weight"] = 20
|
||||
dd = {
|
||||
"data": 21,
|
||||
"spam": "bar",
|
||||
"bar": "foo",
|
||||
"listdata": [20, 200],
|
||||
"weight": 20,
|
||||
}
|
||||
assert edges_equal(G.edges(data=True), [(1, 2, dd)])
|
||||
|
||||
def test_to_undirected(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.Graph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
H = G.to_undirected()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_to_directed_as_view(self):
|
||||
H = nx.path_graph(2, create_using=self.Graph)
|
||||
H2 = H.to_directed(as_view=True)
|
||||
assert H is H2._graph
|
||||
assert H2.has_edge(0, 1)
|
||||
assert H2.has_edge(1, 0) or H.is_directed()
|
||||
pytest.raises(nx.NetworkXError, H2.add_node, -1)
|
||||
pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2)
|
||||
H.add_edge(1, 2)
|
||||
assert H2.has_edge(1, 2)
|
||||
assert H2.has_edge(2, 1) or H.is_directed()
|
||||
|
||||
def test_to_undirected_as_view(self):
|
||||
H = nx.path_graph(2, create_using=self.Graph)
|
||||
H2 = H.to_undirected(as_view=True)
|
||||
assert H is H2._graph
|
||||
assert H2.has_edge(0, 1)
|
||||
assert H2.has_edge(1, 0)
|
||||
pytest.raises(nx.NetworkXError, H2.add_node, -1)
|
||||
pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2)
|
||||
H.add_edge(1, 2)
|
||||
assert H2.has_edge(1, 2)
|
||||
assert H2.has_edge(2, 1)
|
||||
|
||||
def test_directed_class(self):
|
||||
G = self.Graph()
|
||||
|
||||
class newGraph(G.to_undirected_class()):
|
||||
def to_directed_class(self):
|
||||
return newDiGraph
|
||||
|
||||
def to_undirected_class(self):
|
||||
return newGraph
|
||||
|
||||
class newDiGraph(G.to_directed_class()):
|
||||
def to_directed_class(self):
|
||||
return newDiGraph
|
||||
|
||||
def to_undirected_class(self):
|
||||
return newGraph
|
||||
|
||||
G = newDiGraph() if G.is_directed() else newGraph()
|
||||
H = G.to_directed()
|
||||
assert isinstance(H, newDiGraph)
|
||||
H = G.to_undirected()
|
||||
assert isinstance(H, newGraph)
|
||||
|
||||
def test_to_directed(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.DiGraph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
H = G.to_directed()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_subgraph(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = G.subgraph([0, 1, 2, 5])
|
||||
self.graphs_equal(H, G)
|
||||
self.same_attrdict(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
H = G.subgraph(0)
|
||||
assert H.adj == {0: {}}
|
||||
H = G.subgraph([])
|
||||
assert H.adj == {}
|
||||
assert G.adj != {}
|
||||
|
||||
def test_selfloops_attr(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(1, 1, weight=2)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
|
||||
)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)]
|
||||
)
|
||||
|
||||
|
||||
class TestGraph(BaseAttrGraphTester):
|
||||
"""Tests specific to dict-of-dict-of-dict graph data structure"""
|
||||
|
||||
def setup_method(self):
|
||||
self.Graph = nx.Graph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3 = ({}, {}, {})
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.k3adj
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
def test_pickle(self):
|
||||
G = self.K3
|
||||
pg = pickle.loads(pickle.dumps(G, -1))
|
||||
self.graphs_equal(pg, G)
|
||||
pg = pickle.loads(pickle.dumps(G))
|
||||
self.graphs_equal(pg, G)
|
||||
|
||||
def test_data_input(self):
|
||||
G = self.Graph({1: [2], 2: [1]}, name="test")
|
||||
assert G.name == "test"
|
||||
assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
|
||||
def test_adjacency(self):
|
||||
G = self.K3
|
||||
assert dict(G.adjacency()) == {
|
||||
0: {1: {}, 2: {}},
|
||||
1: {0: {}, 2: {}},
|
||||
2: {0: {}, 1: {}},
|
||||
}
|
||||
|
||||
def test_getitem(self):
|
||||
G = self.K3
|
||||
assert G.adj[0] == {1: {}, 2: {}}
|
||||
assert G[0] == {1: {}, 2: {}}
|
||||
with pytest.raises(KeyError):
|
||||
G.__getitem__("j")
|
||||
with pytest.raises(TypeError):
|
||||
G.__getitem__(["A"])
|
||||
|
||||
def test_add_node(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
assert G.adj == {0: {}}
|
||||
# test add attributes
|
||||
G.add_node(1, c="red")
|
||||
G.add_node(2, c="blue")
|
||||
G.add_node(3, c="red")
|
||||
assert G.nodes[1]["c"] == "red"
|
||||
assert G.nodes[2]["c"] == "blue"
|
||||
assert G.nodes[3]["c"] == "red"
|
||||
# test updating attributes
|
||||
G.add_node(1, c="blue")
|
||||
G.add_node(2, c="red")
|
||||
G.add_node(3, c="blue")
|
||||
assert G.nodes[1]["c"] == "blue"
|
||||
assert G.nodes[2]["c"] == "red"
|
||||
assert G.nodes[3]["c"] == "blue"
|
||||
|
||||
def test_add_nodes_from(self):
|
||||
G = self.Graph()
|
||||
G.add_nodes_from([0, 1, 2])
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
# test add attributes
|
||||
G.add_nodes_from([0, 1, 2], c="red")
|
||||
assert G.nodes[0]["c"] == "red"
|
||||
assert G.nodes[2]["c"] == "red"
|
||||
# test that attribute dicts are not the same
|
||||
assert G.nodes[0] is not G.nodes[1]
|
||||
# test updating attributes
|
||||
G.add_nodes_from([0, 1, 2], c="blue")
|
||||
assert G.nodes[0]["c"] == "blue"
|
||||
assert G.nodes[2]["c"] == "blue"
|
||||
assert G.nodes[0] is not G.nodes[1]
|
||||
# test tuple input
|
||||
H = self.Graph()
|
||||
H.add_nodes_from(G.nodes(data=True))
|
||||
assert H.nodes[0]["c"] == "blue"
|
||||
assert H.nodes[2]["c"] == "blue"
|
||||
assert H.nodes[0] is not H.nodes[1]
|
||||
# specific overrides general
|
||||
H.add_nodes_from([0, (1, {"c": "green"}), (3, {"c": "cyan"})], c="red")
|
||||
assert H.nodes[0]["c"] == "red"
|
||||
assert H.nodes[1]["c"] == "green"
|
||||
assert H.nodes[2]["c"] == "blue"
|
||||
assert H.nodes[3]["c"] == "cyan"
|
||||
|
||||
def test_remove_node(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_node(0)
|
||||
assert G.adj == {1: {2: {}}, 2: {1: {}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_node(-1)
|
||||
|
||||
# generator here to implement list,set,string...
|
||||
|
||||
def test_remove_nodes_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_nodes_from([0, 1])
|
||||
assert G.adj == {2: {}}
|
||||
G.remove_nodes_from([-1]) # silent fail
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G.adj == {0: {1: {}}, 1: {0: {}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G.adj == {0: {1: {}}, 1: {0: {}}}
|
||||
G = self.Graph()
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edge(None, "anything")
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 2, {"weight": 3})])
|
||||
assert G.adj == {
|
||||
0: {1: {}, 2: {"weight": 3}},
|
||||
1: {0: {}},
|
||||
2: {0: {"weight": 3}},
|
||||
}
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 2, {"weight": 3}), (1, 2, {"data": 4})], data=2)
|
||||
assert G.adj == {
|
||||
0: {1: {"data": 2}, 2: {"weight": 3, "data": 2}},
|
||||
1: {0: {"data": 2}, 2: {"data": 4}},
|
||||
2: {0: {"weight": 3, "data": 2}, 1: {"data": 4}},
|
||||
}
|
||||
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0,)]) # too few in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple
|
||||
with pytest.raises(TypeError):
|
||||
G.add_edges_from([0]) # not a tuple
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edges_from([(None, 3), (3, 2)]) # None cannot be a node
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edge(0, 1)
|
||||
assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1)])
|
||||
assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
|
||||
def test_clear(self):
|
||||
G = self.K3.copy()
|
||||
G.graph["name"] = "K3"
|
||||
G.clear()
|
||||
assert list(G.nodes) == []
|
||||
assert G.adj == {}
|
||||
assert G.graph == {}
|
||||
|
||||
def test_clear_edges(self):
|
||||
G = self.K3.copy()
|
||||
G.graph["name"] = "K3"
|
||||
nodes = list(G.nodes)
|
||||
G.clear_edges()
|
||||
assert list(G.nodes) == nodes
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
assert list(G.edges) == []
|
||||
assert G.graph["name"] == "K3"
|
||||
|
||||
def test_edges_data(self):
|
||||
G = self.K3
|
||||
all_edges = [(0, 1, {}), (0, 2, {}), (1, 2, {})]
|
||||
assert edges_equal(G.edges(data=True), all_edges)
|
||||
assert edges_equal(G.edges(0, data=True), [(0, 1, {}), (0, 2, {})])
|
||||
assert edges_equal(G.edges([0, 1], data=True), all_edges)
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1, True)
|
||||
|
||||
def test_get_edge_data(self):
|
||||
G = self.K3.copy()
|
||||
assert G.get_edge_data(0, 1) == {}
|
||||
assert G[0][1] == {}
|
||||
assert G.get_edge_data(10, 20) is None
|
||||
assert G.get_edge_data(-1, 0) is None
|
||||
assert G.get_edge_data(-1, 0, default=1) == 1
|
||||
|
||||
def test_update(self):
|
||||
# specify both edgees and nodes
|
||||
G = self.K3.copy()
|
||||
G.update(nodes=[3, (4, {"size": 2})], edges=[(4, 5), (6, 7, {"weight": 2})])
|
||||
nlist = [
|
||||
(0, {}),
|
||||
(1, {}),
|
||||
(2, {}),
|
||||
(3, {}),
|
||||
(4, {"size": 2}),
|
||||
(5, {}),
|
||||
(6, {}),
|
||||
(7, {}),
|
||||
]
|
||||
assert sorted(G.nodes.data()) == nlist
|
||||
if G.is_directed():
|
||||
elist = [
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 0, {}),
|
||||
(1, 2, {}),
|
||||
(2, 0, {}),
|
||||
(2, 1, {}),
|
||||
(4, 5, {}),
|
||||
(6, 7, {"weight": 2}),
|
||||
]
|
||||
else:
|
||||
elist = [
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 2, {}),
|
||||
(4, 5, {}),
|
||||
(6, 7, {"weight": 2}),
|
||||
]
|
||||
assert sorted(G.edges.data()) == elist
|
||||
assert G.graph == {}
|
||||
|
||||
# no keywords -- order is edges, nodes
|
||||
G = self.K3.copy()
|
||||
G.update([(4, 5), (6, 7, {"weight": 2})], [3, (4, {"size": 2})])
|
||||
assert sorted(G.nodes.data()) == nlist
|
||||
assert sorted(G.edges.data()) == elist
|
||||
assert G.graph == {}
|
||||
|
||||
# update using only a graph
|
||||
G = self.Graph()
|
||||
G.graph["foo"] = "bar"
|
||||
G.add_node(2, data=4)
|
||||
G.add_edge(0, 1, weight=0.5)
|
||||
GG = G.copy()
|
||||
H = self.Graph()
|
||||
GG.update(H)
|
||||
assert graphs_equal(G, GG)
|
||||
H.update(G)
|
||||
assert graphs_equal(H, G)
|
||||
|
||||
# update nodes only
|
||||
H = self.Graph()
|
||||
H.update(nodes=[3, 4])
|
||||
assert H.nodes ^ {3, 4} == set()
|
||||
assert H.size() == 0
|
||||
|
||||
# update edges only
|
||||
H = self.Graph()
|
||||
H.update(edges=[(3, 4)])
|
||||
assert sorted(H.edges.data()) == [(3, 4, {})]
|
||||
assert H.size() == 1
|
||||
|
||||
# No inputs -> exception
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nx.Graph().update()
|
||||
|
||||
|
||||
class TestEdgeSubgraph:
|
||||
"""Unit tests for the :meth:`Graph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a path graph on five nodes.
|
||||
G = nx.path_graph(5)
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.edges[0, 1]["name"] = "edge01"
|
||||
G.edges[3, 4]["name"] = "edge34"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by the first and last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1), (3, 4)])
|
||||
|
||||
def test_correct_nodes(self):
|
||||
"""Tests that the subgraph has the correct nodes."""
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_correct_edges(self):
|
||||
"""Tests that the subgraph has the correct edges."""
|
||||
assert [(0, 1, "edge01"), (3, 4, "edge34")] == sorted(self.H.edges(data="name"))
|
||||
|
||||
def test_add_node(self):
|
||||
"""Tests that adding a node to the original graph does not
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.add_node(5)
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_remove_node(self):
|
||||
"""Tests that removing a node in the original graph does
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.remove_node(0)
|
||||
assert [1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_node_attr_dict(self):
|
||||
"""Tests that the node attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for v in self.H:
|
||||
assert self.G.nodes[v] == self.H.nodes[v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.nodes[0]["name"] = "foo"
|
||||
assert self.G.nodes[0] == self.H.nodes[0]
|
||||
self.H.nodes[1]["name"] = "bar"
|
||||
assert self.G.nodes[1] == self.H.nodes[1]
|
||||
|
||||
def test_edge_attr_dict(self):
|
||||
"""Tests that the edge attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for u, v in self.H.edges():
|
||||
assert self.G.edges[u, v] == self.H.edges[u, v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.edges[0, 1]["name"] = "foo"
|
||||
assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"]
|
||||
self.H.edges[3, 4]["name"] = "bar"
|
||||
assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"]
|
||||
|
||||
def test_graph_attr_dict(self):
|
||||
"""Tests that the graph attribute dictionary of the two graphs
|
||||
is the same object.
|
||||
|
||||
"""
|
||||
assert self.G.graph is self.H.graph
|
||||
@@ -1,12 +0,0 @@
|
||||
"""Original NetworkX graph tests"""
|
||||
import networkx
|
||||
import networkx as nx
|
||||
|
||||
from .historical_tests import HistoricalTests
|
||||
|
||||
|
||||
class TestGraphHistorical(HistoricalTests):
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
HistoricalTests.setup_class()
|
||||
cls.G = nx.Graph
|
||||
@@ -1,352 +0,0 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
# Note: SubGraph views are not tested here. They have their own testing file
|
||||
|
||||
|
||||
class TestReverseView:
|
||||
def setup_method(self):
|
||||
self.G = nx.path_graph(9, create_using=nx.DiGraph())
|
||||
self.rv = nx.reverse_view(self.G)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
rv = self.rv
|
||||
prv = pickle.loads(pickle.dumps(rv, -1))
|
||||
assert rv._node == prv._node
|
||||
assert rv._adj == prv._adj
|
||||
assert rv.graph == prv.graph
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3) in self.G.edges
|
||||
assert (3, 2) not in self.G.edges
|
||||
assert (2, 3) not in self.rv.edges
|
||||
assert (3, 2) in self.rv.edges
|
||||
|
||||
def test_iter(self):
|
||||
expected = sorted(tuple(reversed(e)) for e in self.G.edges)
|
||||
assert sorted(self.rv.edges) == expected
|
||||
|
||||
def test_exceptions(self):
|
||||
nxg = nx.graphviews
|
||||
G = nx.Graph()
|
||||
pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, G)
|
||||
|
||||
def test_subclass(self):
|
||||
class MyGraph(nx.DiGraph):
|
||||
def my_method(self):
|
||||
return "me"
|
||||
|
||||
def to_directed_class(self):
|
||||
return MyGraph()
|
||||
|
||||
M = MyGraph()
|
||||
M.add_edge(1, 2)
|
||||
RM = nx.reverse_view(M)
|
||||
print("RM class", RM.__class__)
|
||||
RMC = RM.copy()
|
||||
print("RMC class", RMC.__class__)
|
||||
print(RMC.edges)
|
||||
assert RMC.has_edge(2, 1)
|
||||
assert RMC.my_method() == "me"
|
||||
|
||||
|
||||
class TestMultiReverseView:
|
||||
def setup_method(self):
|
||||
self.G = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||||
self.G.add_edge(4, 5)
|
||||
self.rv = nx.reverse_view(self.G)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
rv = self.rv
|
||||
prv = pickle.loads(pickle.dumps(rv, -1))
|
||||
assert rv._node == prv._node
|
||||
assert rv._adj == prv._adj
|
||||
assert rv.graph == prv.graph
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3, 0) in self.G.edges
|
||||
assert (3, 2, 0) not in self.G.edges
|
||||
assert (2, 3, 0) not in self.rv.edges
|
||||
assert (3, 2, 0) in self.rv.edges
|
||||
assert (5, 4, 1) in self.rv.edges
|
||||
assert (4, 5, 1) not in self.rv.edges
|
||||
|
||||
def test_iter(self):
|
||||
expected = sorted((v, u, k) for u, v, k in self.G.edges)
|
||||
assert sorted(self.rv.edges) == expected
|
||||
|
||||
def test_exceptions(self):
|
||||
nxg = nx.graphviews
|
||||
MG = nx.MultiGraph(self.G)
|
||||
pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, MG)
|
||||
|
||||
|
||||
def test_generic_multitype():
|
||||
nxg = nx.graphviews
|
||||
G = nx.DiGraph([(1, 2)])
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nxg.generic_graph_view(G, create_using=nx.MultiGraph)
|
||||
G = nx.MultiDiGraph([(1, 2)])
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nxg.generic_graph_view(G, create_using=nx.DiGraph)
|
||||
|
||||
|
||||
class TestToDirected:
|
||||
def setup_method(self):
|
||||
self.G = nx.path_graph(9)
|
||||
self.dv = nx.to_directed(self.G)
|
||||
self.MG = nx.path_graph(9, create_using=nx.MultiGraph())
|
||||
self.Mdv = nx.to_directed(self.MG)
|
||||
|
||||
def test_directed(self):
|
||||
assert not self.G.is_directed()
|
||||
assert self.dv.is_directed()
|
||||
|
||||
def test_already_directed(self):
|
||||
dd = nx.to_directed(self.dv)
|
||||
Mdd = nx.to_directed(self.Mdv)
|
||||
assert edges_equal(dd.edges, self.dv.edges)
|
||||
assert edges_equal(Mdd.edges, self.Mdv.edges)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
dv = self.dv
|
||||
pdv = pickle.loads(pickle.dumps(dv, -1))
|
||||
assert dv._node == pdv._node
|
||||
assert dv._succ == pdv._succ
|
||||
assert dv._pred == pdv._pred
|
||||
assert dv.graph == pdv.graph
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3) in self.G.edges
|
||||
assert (3, 2) in self.G.edges
|
||||
assert (2, 3) in self.dv.edges
|
||||
assert (3, 2) in self.dv.edges
|
||||
|
||||
def test_iter(self):
|
||||
revd = [tuple(reversed(e)) for e in self.G.edges]
|
||||
expected = sorted(list(self.G.edges) + revd)
|
||||
assert sorted(self.dv.edges) == expected
|
||||
|
||||
|
||||
class TestToUndirected:
|
||||
def setup_method(self):
|
||||
self.DG = nx.path_graph(9, create_using=nx.DiGraph())
|
||||
self.uv = nx.to_undirected(self.DG)
|
||||
self.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||||
self.Muv = nx.to_undirected(self.MDG)
|
||||
|
||||
def test_directed(self):
|
||||
assert self.DG.is_directed()
|
||||
assert not self.uv.is_directed()
|
||||
|
||||
def test_already_directed(self):
|
||||
uu = nx.to_undirected(self.uv)
|
||||
Muu = nx.to_undirected(self.Muv)
|
||||
assert edges_equal(uu.edges, self.uv.edges)
|
||||
assert edges_equal(Muu.edges, self.Muv.edges)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
uv = self.uv
|
||||
puv = pickle.loads(pickle.dumps(uv, -1))
|
||||
assert uv._node == puv._node
|
||||
assert uv._adj == puv._adj
|
||||
assert uv.graph == puv.graph
|
||||
assert hasattr(uv, "_graph")
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3) in self.DG.edges
|
||||
assert (3, 2) not in self.DG.edges
|
||||
assert (2, 3) in self.uv.edges
|
||||
assert (3, 2) in self.uv.edges
|
||||
|
||||
def test_iter(self):
|
||||
expected = sorted(self.DG.edges)
|
||||
assert sorted(self.uv.edges) == expected
|
||||
|
||||
|
||||
class TestChainsOfViews:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.path_graph(9)
|
||||
cls.DG = nx.path_graph(9, create_using=nx.DiGraph())
|
||||
cls.MG = nx.path_graph(9, create_using=nx.MultiGraph())
|
||||
cls.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||||
cls.Gv = nx.to_undirected(cls.DG)
|
||||
cls.DGv = nx.to_directed(cls.G)
|
||||
cls.MGv = nx.to_undirected(cls.MDG)
|
||||
cls.MDGv = nx.to_directed(cls.MG)
|
||||
cls.Rv = cls.DG.reverse()
|
||||
cls.MRv = cls.MDG.reverse()
|
||||
cls.graphs = [
|
||||
cls.G,
|
||||
cls.DG,
|
||||
cls.MG,
|
||||
cls.MDG,
|
||||
cls.Gv,
|
||||
cls.DGv,
|
||||
cls.MGv,
|
||||
cls.MDGv,
|
||||
cls.Rv,
|
||||
cls.MRv,
|
||||
]
|
||||
for G in cls.graphs:
|
||||
G.edges, G.nodes, G.degree
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
for G in self.graphs:
|
||||
H = pickle.loads(pickle.dumps(G, -1))
|
||||
assert edges_equal(H.edges, G.edges)
|
||||
assert nodes_equal(H.nodes, G.nodes)
|
||||
|
||||
def test_subgraph_of_subgraph(self):
|
||||
SGv = nx.subgraph(self.G, range(3, 7))
|
||||
SDGv = nx.subgraph(self.DG, range(3, 7))
|
||||
SMGv = nx.subgraph(self.MG, range(3, 7))
|
||||
SMDGv = nx.subgraph(self.MDG, range(3, 7))
|
||||
for G in self.graphs + [SGv, SDGv, SMGv, SMDGv]:
|
||||
SG = nx.induced_subgraph(G, [4, 5, 6])
|
||||
assert list(SG) == [4, 5, 6]
|
||||
SSG = SG.subgraph([6, 7])
|
||||
assert list(SSG) == [6]
|
||||
# subgraph-subgraph chain is short-cut in base class method
|
||||
assert SSG._graph is G
|
||||
|
||||
def test_restricted_induced_subgraph_chains(self):
|
||||
"""Test subgraph chains that both restrict and show nodes/edges.
|
||||
|
||||
A restricted_view subgraph should allow induced subgraphs using
|
||||
G.subgraph that automagically without a chain (meaning the result
|
||||
is a subgraph view of the original graph not a subgraph-of-subgraph.
|
||||
"""
|
||||
hide_nodes = [3, 4, 5]
|
||||
hide_edges = [(6, 7)]
|
||||
RG = nx.restricted_view(self.G, hide_nodes, hide_edges)
|
||||
nodes = [4, 5, 6, 7, 8]
|
||||
SG = nx.induced_subgraph(RG, nodes)
|
||||
SSG = RG.subgraph(nodes)
|
||||
assert RG._graph is self.G
|
||||
assert SSG._graph is self.G
|
||||
assert SG._graph is RG
|
||||
assert edges_equal(SG.edges, SSG.edges)
|
||||
# should be same as morphing the graph
|
||||
CG = self.G.copy()
|
||||
CG.remove_nodes_from(hide_nodes)
|
||||
CG.remove_edges_from(hide_edges)
|
||||
assert edges_equal(CG.edges(nodes), SSG.edges)
|
||||
CG.remove_nodes_from([0, 1, 2, 3])
|
||||
assert edges_equal(CG.edges, SSG.edges)
|
||||
# switch order: subgraph first, then restricted view
|
||||
SSSG = self.G.subgraph(nodes)
|
||||
RSG = nx.restricted_view(SSSG, hide_nodes, hide_edges)
|
||||
assert RSG._graph is not self.G
|
||||
assert edges_equal(RSG.edges, CG.edges)
|
||||
|
||||
def test_subgraph_copy(self):
|
||||
for origG in self.graphs:
|
||||
G = nx.Graph(origG)
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
H = SG.copy()
|
||||
assert type(G) == type(H)
|
||||
|
||||
def test_subgraph_todirected(self):
|
||||
SG = nx.induced_subgraph(self.G, [4, 5, 6])
|
||||
SSG = SG.to_directed()
|
||||
assert sorted(SSG) == [4, 5, 6]
|
||||
assert sorted(SSG.edges) == [(4, 5), (5, 4), (5, 6), (6, 5)]
|
||||
|
||||
def test_subgraph_toundirected(self):
|
||||
SG = nx.induced_subgraph(self.G, [4, 5, 6])
|
||||
SSG = SG.to_undirected()
|
||||
assert list(SSG) == [4, 5, 6]
|
||||
assert sorted(SSG.edges) == [(4, 5), (5, 6)]
|
||||
|
||||
def test_reverse_subgraph_toundirected(self):
|
||||
G = self.DG.reverse(copy=False)
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
SSG = SG.to_undirected()
|
||||
assert list(SSG) == [4, 5, 6]
|
||||
assert sorted(SSG.edges) == [(4, 5), (5, 6)]
|
||||
|
||||
def test_reverse_reverse_copy(self):
|
||||
G = self.DG.reverse(copy=False)
|
||||
H = G.reverse(copy=True)
|
||||
assert H.nodes == self.DG.nodes
|
||||
assert H.edges == self.DG.edges
|
||||
G = self.MDG.reverse(copy=False)
|
||||
H = G.reverse(copy=True)
|
||||
assert H.nodes == self.MDG.nodes
|
||||
assert H.edges == self.MDG.edges
|
||||
|
||||
def test_subgraph_edgesubgraph_toundirected(self):
|
||||
G = self.G.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
SSG = SG.edge_subgraph([(4, 5), (5, 4)])
|
||||
USSG = SSG.to_undirected()
|
||||
assert list(USSG) == [4, 5]
|
||||
assert sorted(USSG.edges) == [(4, 5)]
|
||||
|
||||
def test_copy_subgraph(self):
|
||||
G = self.G.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_disubgraph(self):
|
||||
G = self.DG.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_multidisubgraph(self):
|
||||
G = self.MDG.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_multisubgraph(self):
|
||||
G = self.MG.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_of_view(self):
|
||||
G = nx.MultiGraph(self.MGv)
|
||||
assert G.__class__.__name__ == "MultiGraph"
|
||||
G = G.copy(as_view=True)
|
||||
assert G.__class__.__name__ == "MultiGraph"
|
||||
|
||||
def test_subclass(self):
|
||||
class MyGraph(nx.DiGraph):
|
||||
def my_method(self):
|
||||
return "me"
|
||||
|
||||
def to_directed_class(self):
|
||||
return MyGraph()
|
||||
|
||||
for origG in self.graphs:
|
||||
G = MyGraph(origG)
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
H = SG.copy()
|
||||
assert SG.my_method() == "me"
|
||||
assert H.my_method() == "me"
|
||||
assert 3 not in H or 3 in SG
|
||||
@@ -1,459 +0,0 @@
|
||||
from collections import UserDict
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
from .test_multigraph import BaseMultiGraphTester
|
||||
from .test_multigraph import TestEdgeSubgraph as _TestMultiGraphEdgeSubgraph
|
||||
from .test_multigraph import TestMultiGraph as _TestMultiGraph
|
||||
|
||||
|
||||
class BaseMultiDiGraphTester(BaseMultiGraphTester):
|
||||
def test_edges(self):
|
||||
G = self.K3
|
||||
edges = [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.edges()) == edges
|
||||
assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.edges, -1)
|
||||
|
||||
def test_edges_data(self):
|
||||
G = self.K3
|
||||
edges = [(0, 1, {}), (0, 2, {}), (1, 0, {}), (1, 2, {}), (2, 0, {}), (2, 1, {})]
|
||||
assert sorted(G.edges(data=True)) == edges
|
||||
assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.neighbors, -1)
|
||||
|
||||
def test_edges_multi(self):
|
||||
G = self.K3
|
||||
assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
|
||||
G.add_edge(0, 1)
|
||||
assert sorted(G.edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
|
||||
def test_out_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.out_edges, -1)
|
||||
assert sorted(G.out_edges(0, keys=True)) == [(0, 1, 0), (0, 2, 0)]
|
||||
|
||||
def test_out_edges_multi(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
|
||||
G.add_edge(0, 1, 2)
|
||||
assert sorted(G.out_edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
|
||||
def test_out_edges_data(self):
|
||||
G = self.K3
|
||||
assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})]
|
||||
G.remove_edge(0, 1)
|
||||
G.add_edge(0, 1, data=1)
|
||||
assert sorted(G.edges(0, data=True)) == [(0, 1, {"data": 1}), (0, 2, {})]
|
||||
assert sorted(G.edges(0, data="data")) == [(0, 1, 1), (0, 2, None)]
|
||||
assert sorted(G.edges(0, data="data", default=-1)) == [(0, 1, 1), (0, 2, -1)]
|
||||
|
||||
def test_in_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.in_edges, -1)
|
||||
G.add_edge(0, 1, 2)
|
||||
assert sorted(G.in_edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
assert sorted(G.in_edges(0, keys=True)) == [(1, 0, 0), (2, 0, 0)]
|
||||
|
||||
def test_in_edges_no_keys(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)]
|
||||
G.add_edge(0, 1, 2)
|
||||
assert sorted(G.in_edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
|
||||
assert sorted(G.in_edges(data=True, keys=False)) == [
|
||||
(0, 1, {}),
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 0, {}),
|
||||
(1, 2, {}),
|
||||
(2, 0, {}),
|
||||
(2, 1, {}),
|
||||
]
|
||||
|
||||
def test_in_edges_data(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_edges(0, data=True)) == [(1, 0, {}), (2, 0, {})]
|
||||
G.remove_edge(1, 0)
|
||||
G.add_edge(1, 0, data=1)
|
||||
assert sorted(G.in_edges(0, data=True)) == [(1, 0, {"data": 1}), (2, 0, {})]
|
||||
assert sorted(G.in_edges(0, data="data")) == [(1, 0, 1), (2, 0, None)]
|
||||
assert sorted(G.in_edges(0, data="data", default=-1)) == [(1, 0, 1), (2, 0, -1)]
|
||||
|
||||
def is_shallow(self, H, G):
|
||||
# graph
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
# node
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
# edge
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
|
||||
def is_deep(self, H, G):
|
||||
# graph
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] != H.graph["foo"]
|
||||
# node
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] != H.nodes[0]["foo"]
|
||||
# edge
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] != H[1][2][0]["foo"]
|
||||
|
||||
def test_to_undirected(self):
|
||||
# MultiDiGraph -> MultiGraph changes number of edges so it is
|
||||
# not a copy operation... use is_shallow, not is_shallow_copy
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.MultiGraph(G)
|
||||
# self.is_shallow(H,G)
|
||||
# the result is traversal order dependent so we
|
||||
# can't use the is_shallow() test here.
|
||||
try:
|
||||
assert edges_equal(H.edges(), [(0, 1), (1, 2), (2, 0)])
|
||||
except AssertionError:
|
||||
assert edges_equal(H.edges(), [(0, 1), (1, 2), (1, 2), (2, 0)])
|
||||
H = G.to_undirected()
|
||||
self.is_deep(H, G)
|
||||
|
||||
def test_has_successor(self):
|
||||
G = self.K3
|
||||
assert G.has_successor(0, 1)
|
||||
assert not G.has_successor(0, -1)
|
||||
|
||||
def test_successors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.successors(0)) == [1, 2]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.successors, -1)
|
||||
|
||||
def test_has_predecessor(self):
|
||||
G = self.K3
|
||||
assert G.has_predecessor(0, 1)
|
||||
assert not G.has_predecessor(0, -1)
|
||||
|
||||
def test_predecessors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.predecessors(0)) == [1, 2]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.predecessors, -1)
|
||||
|
||||
def test_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)]
|
||||
assert dict(G.degree()) == {0: 4, 1: 4, 2: 4}
|
||||
assert G.degree(0) == 4
|
||||
assert list(G.degree(iter([0]))) == [(0, 4)]
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert sorted(G.degree(weight="weight")) == [(0, 4.3), (1, 4.3), (2, 4)]
|
||||
assert sorted(G.degree(weight="other")) == [(0, 5.2), (1, 5.2), (2, 4)]
|
||||
|
||||
def test_in_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.in_degree(0) == 2
|
||||
assert list(G.in_degree(iter([0]))) == [(0, 2)]
|
||||
assert G.in_degree(0, weight="weight") == 2
|
||||
|
||||
def test_out_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.out_degree(0) == 2
|
||||
assert list(G.out_degree(iter([0]))) == [(0, 2)]
|
||||
assert G.out_degree(0, weight="weight") == 2
|
||||
|
||||
def test_size(self):
|
||||
G = self.K3
|
||||
assert G.size() == 6
|
||||
assert G.number_of_edges() == 6
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert round(G.size(weight="weight"), 2) == 6.3
|
||||
assert round(G.size(weight="other"), 2) == 7.2
|
||||
|
||||
def test_to_undirected_reciprocal(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2)
|
||||
assert G.to_undirected().has_edge(1, 2)
|
||||
assert not G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
G.add_edge(2, 1)
|
||||
assert G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
|
||||
def test_reverse_copy(self):
|
||||
G = nx.MultiDiGraph([(0, 1), (0, 1)])
|
||||
R = G.reverse()
|
||||
assert sorted(R.edges()) == [(1, 0), (1, 0)]
|
||||
R.remove_edge(1, 0)
|
||||
assert sorted(R.edges()) == [(1, 0)]
|
||||
assert sorted(G.edges()) == [(0, 1), (0, 1)]
|
||||
|
||||
def test_reverse_nocopy(self):
|
||||
G = nx.MultiDiGraph([(0, 1), (0, 1)])
|
||||
R = G.reverse(copy=False)
|
||||
assert sorted(R.edges()) == [(1, 0), (1, 0)]
|
||||
pytest.raises(nx.NetworkXError, R.remove_edge, 1, 0)
|
||||
|
||||
def test_di_attributes_cached(self):
|
||||
G = self.K3.copy()
|
||||
assert id(G.in_edges) == id(G.in_edges)
|
||||
assert id(G.out_edges) == id(G.out_edges)
|
||||
assert id(G.in_degree) == id(G.in_degree)
|
||||
assert id(G.out_degree) == id(G.out_degree)
|
||||
assert id(G.succ) == id(G.succ)
|
||||
assert id(G.pred) == id(G.pred)
|
||||
|
||||
|
||||
class TestMultiDiGraph(BaseMultiDiGraphTester, _TestMultiGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = nx.MultiDiGraph
|
||||
# build K3
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = {0: {}, 1: {}, 2: {}}
|
||||
# K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {}, 1: {}, 2: {}}
|
||||
for u in self.k3nodes:
|
||||
for v in self.k3nodes:
|
||||
if u == v:
|
||||
continue
|
||||
d = {0: {}}
|
||||
self.K3._succ[u][v] = d
|
||||
self.K3._pred[v][u] = d
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G._adj == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._succ == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._pred == {0: {}, 1: {0: {0: {}}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G._adj == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._succ == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._pred == {0: {}, 1: {0: {0: {}}}}
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edge(None, 3)
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})])
|
||||
assert G._adj == {0: {1: {0: {}, 1: {"weight": 3}}}, 1: {}}
|
||||
assert G._succ == {0: {1: {0: {}, 1: {"weight": 3}}}, 1: {}}
|
||||
assert G._pred == {0: {}, 1: {0: {0: {}, 1: {"weight": 3}}}}
|
||||
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})], weight=2)
|
||||
assert G._succ == {
|
||||
0: {1: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
1: {},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {},
|
||||
1: {0: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
}
|
||||
|
||||
G = self.Graph()
|
||||
edges = [
|
||||
(0, 1, {"weight": 3}),
|
||||
(0, 1, (("weight", 2),)),
|
||||
(0, 1, 5),
|
||||
(0, 1, "s"),
|
||||
]
|
||||
G.add_edges_from(edges)
|
||||
keydict = {0: {"weight": 3}, 1: {"weight": 2}, 5: {}, "s": {}}
|
||||
assert G._succ == {0: {1: keydict}, 1: {}}
|
||||
assert G._pred == {1: {0: keydict}, 0: {}}
|
||||
|
||||
# too few in tuple
|
||||
pytest.raises(nx.NetworkXError, G.add_edges_from, [(0,)])
|
||||
# too many in tuple
|
||||
pytest.raises(nx.NetworkXError, G.add_edges_from, [(0, 1, 2, 3, 4)])
|
||||
# not a tuple
|
||||
pytest.raises(TypeError, G.add_edges_from, [0])
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edges_from([(None, 3), (3, 2)])
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3
|
||||
G.remove_edge(0, 1)
|
||||
assert G._succ == {
|
||||
0: {2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0)
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, 0, 2, key=1)
|
||||
|
||||
def test_remove_multiedge(self):
|
||||
G = self.K3
|
||||
G.add_edge(0, 1, key="parallel edge")
|
||||
G.remove_edge(0, 1, key="parallel edge")
|
||||
assert G._adj == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
|
||||
assert G._succ == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
G.remove_edge(0, 1)
|
||||
assert G._succ == {
|
||||
0: {2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3
|
||||
G.remove_edges_from([(0, 1)])
|
||||
assert G._succ == {
|
||||
0: {2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
|
||||
|
||||
class TestEdgeSubgraph(_TestMultiGraphEdgeSubgraph):
|
||||
"""Unit tests for the :meth:`MultiDiGraph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a quadruply-linked path graph on five nodes.
|
||||
G = nx.MultiDiGraph()
|
||||
nx.add_path(G, range(5))
|
||||
nx.add_path(G, range(5))
|
||||
nx.add_path(G, reversed(range(5)))
|
||||
nx.add_path(G, reversed(range(5)))
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.adj[0][1][0]["name"] = "edge010"
|
||||
G.adj[0][1][1]["name"] = "edge011"
|
||||
G.adj[3][4][0]["name"] = "edge340"
|
||||
G.adj[3][4][1]["name"] = "edge341"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by one of the first edges and one of
|
||||
# the last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)])
|
||||
|
||||
|
||||
class CustomDictClass(UserDict):
|
||||
pass
|
||||
|
||||
|
||||
class MultiDiGraphSubClass(nx.MultiDiGraph):
|
||||
node_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
node_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_outer_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_inner_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_key_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
graph_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
|
||||
|
||||
class TestMultiDiGraphSubclass(TestMultiDiGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = MultiDiGraphSubClass
|
||||
# build K3
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = self.K3.adjlist_outer_dict_factory(
|
||||
{
|
||||
0: self.K3.adjlist_inner_dict_factory(),
|
||||
1: self.K3.adjlist_inner_dict_factory(),
|
||||
2: self.K3.adjlist_inner_dict_factory(),
|
||||
}
|
||||
)
|
||||
# K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {}, 1: {}, 2: {}}
|
||||
for u in self.k3nodes:
|
||||
for v in self.k3nodes:
|
||||
if u == v:
|
||||
continue
|
||||
d = {0: {}}
|
||||
self.K3._succ[u][v] = d
|
||||
self.K3._pred[v][u] = d
|
||||
self.K3._node = self.K3.node_dict_factory()
|
||||
self.K3._node[0] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[1] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[2] = self.K3.node_attr_dict_factory()
|
||||
@@ -1,528 +0,0 @@
|
||||
from collections import UserDict
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
from .test_graph import BaseAttrGraphTester
|
||||
from .test_graph import TestGraph as _TestGraph
|
||||
|
||||
|
||||
class BaseMultiGraphTester(BaseAttrGraphTester):
|
||||
def test_has_edge(self):
|
||||
G = self.K3
|
||||
assert G.has_edge(0, 1)
|
||||
assert not G.has_edge(0, -1)
|
||||
assert G.has_edge(0, 1, 0)
|
||||
assert not G.has_edge(0, 1, 1)
|
||||
|
||||
def test_get_edge_data(self):
|
||||
G = self.K3
|
||||
assert G.get_edge_data(0, 1) == {0: {}}
|
||||
assert G[0][1] == {0: {}}
|
||||
assert G[0][1][0] == {}
|
||||
assert G.get_edge_data(10, 20) is None
|
||||
assert G.get_edge_data(0, 1, 0) == {}
|
||||
|
||||
def test_adjacency(self):
|
||||
G = self.K3
|
||||
assert dict(G.adjacency()) == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
|
||||
def deepcopy_edge_attr(self, H, G):
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] != H[1][2][0]["foo"]
|
||||
|
||||
def shallow_copy_edge_attr(self, H, G):
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
|
||||
def graphs_equal(self, H, G):
|
||||
assert G._adj == H._adj
|
||||
assert G._node == H._node
|
||||
assert G.graph == H.graph
|
||||
assert G.name == H.name
|
||||
if not G.is_directed() and not H.is_directed():
|
||||
assert H._adj[1][2][0] is H._adj[2][1][0]
|
||||
assert G._adj[1][2][0] is G._adj[2][1][0]
|
||||
else: # at least one is directed
|
||||
if not G.is_directed():
|
||||
G._pred = G._adj
|
||||
G._succ = G._adj
|
||||
if not H.is_directed():
|
||||
H._pred = H._adj
|
||||
H._succ = H._adj
|
||||
assert G._pred == H._pred
|
||||
assert G._succ == H._succ
|
||||
assert H._succ[1][2][0] is H._pred[2][1][0]
|
||||
assert G._succ[1][2][0] is G._pred[2][1][0]
|
||||
|
||||
def same_attrdict(self, H, G):
|
||||
# same attrdict in the edgedata
|
||||
old_foo = H[1][2][0]["foo"]
|
||||
H.adj[1][2][0]["foo"] = "baz"
|
||||
assert G._adj == H._adj
|
||||
H.adj[1][2][0]["foo"] = old_foo
|
||||
assert G._adj == H._adj
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G._node == H._node
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G._node == H._node
|
||||
|
||||
def different_attrdict(self, H, G):
|
||||
# used by graph_equal_but_different
|
||||
old_foo = H[1][2][0]["foo"]
|
||||
H.adj[1][2][0]["foo"] = "baz"
|
||||
assert G._adj != H._adj
|
||||
H.adj[1][2][0]["foo"] = old_foo
|
||||
assert G._adj == H._adj
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G._node != H._node
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G._node == H._node
|
||||
|
||||
def test_to_undirected(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.MultiGraph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
H = G.to_undirected()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_to_directed(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.MultiDiGraph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
H = G.to_directed()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_number_of_edges_selfloops(self):
|
||||
G = self.K3
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0, key="parallel edge")
|
||||
G.remove_edge(0, 0, key="parallel edge")
|
||||
assert G.number_of_edges(0, 0) == 2
|
||||
G.remove_edge(0, 0)
|
||||
assert G.number_of_edges(0, 0) == 1
|
||||
|
||||
def test_edge_lookup(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, foo="bar")
|
||||
G.add_edge(1, 2, "key", foo="biz")
|
||||
assert edges_equal(G.edges[1, 2, 0], {"foo": "bar"})
|
||||
assert edges_equal(G.edges[1, 2, "key"], {"foo": "biz"})
|
||||
|
||||
def test_edge_attr(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, key="k1", foo="bar")
|
||||
G.add_edge(1, 2, key="k2", foo="baz")
|
||||
assert isinstance(G.get_edge_data(1, 2), G.edge_key_dict_factory)
|
||||
assert all(
|
||||
isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True)
|
||||
)
|
||||
assert edges_equal(
|
||||
G.edges(keys=True, data=True),
|
||||
[(1, 2, "k1", {"foo": "bar"}), (1, 2, "k2", {"foo": "baz"})],
|
||||
)
|
||||
assert edges_equal(
|
||||
G.edges(keys=True, data="foo"), [(1, 2, "k1", "bar"), (1, 2, "k2", "baz")]
|
||||
)
|
||||
|
||||
def test_edge_attr4(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, key=0, data=7, spam="bar", bar="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G[1][2][0]["data"] = 10 # OK to set data like this
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
|
||||
G.adj[1][2][0]["data"] = 20
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.edges[1, 2, 0]["data"] = 21 # another spelling, "edge"
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.adj[1][2][0]["listdata"] = [20, 200]
|
||||
G.adj[1][2][0]["weight"] = 20
|
||||
assert edges_equal(
|
||||
G.edges(data=True),
|
||||
[
|
||||
(
|
||||
1,
|
||||
2,
|
||||
{
|
||||
"data": 21,
|
||||
"spam": "bar",
|
||||
"bar": "foo",
|
||||
"listdata": [20, 200],
|
||||
"weight": 20,
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class TestMultiGraph(BaseMultiGraphTester, _TestGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = nx.MultiGraph
|
||||
# build K3
|
||||
ed1, ed2, ed3 = ({0: {}}, {0: {}}, {0: {}})
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.k3adj
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
def test_data_input(self):
|
||||
G = self.Graph({1: [2], 2: [1]}, name="test")
|
||||
assert G.name == "test"
|
||||
expected = [(1, {2: {0: {}}}), (2, {1: {0: {}}})]
|
||||
assert sorted(G.adj.items()) == expected
|
||||
|
||||
def test_data_multigraph_input(self):
|
||||
# standard case with edge keys and edge data
|
||||
edata0 = {"w": 200, "s": "foo"}
|
||||
edata1 = {"w": 201, "s": "bar"}
|
||||
keydict = {0: edata0, 1: edata1}
|
||||
dododod = {"a": {"b": keydict}}
|
||||
|
||||
multiple_edge = [("a", "b", 0, edata0), ("a", "b", 1, edata1)]
|
||||
single_edge = [("a", "b", 0, keydict)]
|
||||
|
||||
G = self.Graph(dododod, multigraph_input=True)
|
||||
assert list(G.edges(keys=True, data=True)) == multiple_edge
|
||||
G = self.Graph(dododod, multigraph_input=None)
|
||||
assert list(G.edges(keys=True, data=True)) == multiple_edge
|
||||
G = self.Graph(dododod, multigraph_input=False)
|
||||
assert list(G.edges(keys=True, data=True)) == single_edge
|
||||
|
||||
# test round-trip to_dict_of_dict and MultiGraph constructor
|
||||
G = self.Graph(dododod, multigraph_input=True)
|
||||
H = self.Graph(nx.to_dict_of_dicts(G))
|
||||
assert nx.is_isomorphic(G, H) is True # test that default is True
|
||||
for mgi in [True, False]:
|
||||
H = self.Graph(nx.to_dict_of_dicts(G), multigraph_input=mgi)
|
||||
assert nx.is_isomorphic(G, H) == mgi
|
||||
|
||||
# Set up cases for when incoming_graph_data is not multigraph_input
|
||||
etraits = {"w": 200, "s": "foo"}
|
||||
egraphics = {"color": "blue", "shape": "box"}
|
||||
edata = {"traits": etraits, "graphics": egraphics}
|
||||
dodod1 = {"a": {"b": edata}}
|
||||
dodod2 = {"a": {"b": etraits}}
|
||||
dodod3 = {"a": {"b": {"traits": etraits, "s": "foo"}}}
|
||||
dol = {"a": ["b"]}
|
||||
|
||||
multiple_edge = [("a", "b", "traits", etraits), ("a", "b", "graphics", egraphics)]
|
||||
single_edge = [("a", "b", 0, {})] # type: ignore[var-annotated]
|
||||
single_edge1 = [("a", "b", 0, edata)]
|
||||
single_edge2 = [("a", "b", 0, etraits)]
|
||||
single_edge3 = [("a", "b", 0, {"traits": etraits, "s": "foo"})]
|
||||
|
||||
cases = [ # (dod, mgi, edges)
|
||||
(dodod1, True, multiple_edge),
|
||||
(dodod1, False, single_edge1),
|
||||
(dodod2, False, single_edge2),
|
||||
(dodod3, False, single_edge3),
|
||||
(dol, False, single_edge),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("dod, mgi, edges", cases)
|
||||
def test_non_multigraph_input(self, dod, mgi, edges):
|
||||
G = self.Graph(dod, multigraph_input=mgi)
|
||||
assert list(G.edges(keys=True, data=True)) == edges
|
||||
G = nx.to_networkx_graph(dod, create_using=self.Graph, multigraph_input=mgi)
|
||||
assert list(G.edges(keys=True, data=True)) == edges
|
||||
|
||||
mgi_none_cases = [
|
||||
(dodod1, multiple_edge),
|
||||
(dodod2, single_edge2),
|
||||
(dodod3, single_edge3),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("dod, edges", mgi_none_cases)
|
||||
def test_non_multigraph_input_mgi_none(self, dod, edges):
|
||||
# test constructor without to_networkx_graph for mgi=None
|
||||
G = self.Graph(dod)
|
||||
assert list(G.edges(keys=True, data=True)) == edges
|
||||
|
||||
raise_cases = [dodod2, dodod3, dol]
|
||||
|
||||
@pytest.mark.parametrize("dod", raise_cases)
|
||||
def test_non_multigraph_input_raise(self, dod):
|
||||
# cases where NetworkXError is raised
|
||||
pytest.raises(nx.NetworkXError, self.Graph, dod, multigraph_input=True)
|
||||
pytest.raises(
|
||||
nx.NetworkXError,
|
||||
nx.to_networkx_graph,
|
||||
dod,
|
||||
create_using=self.Graph,
|
||||
multigraph_input=True,
|
||||
)
|
||||
|
||||
def test_getitem(self):
|
||||
G = self.K3
|
||||
assert G[0] == {1: {0: {}}, 2: {0: {}}}
|
||||
with pytest.raises(KeyError):
|
||||
G.__getitem__("j")
|
||||
with pytest.raises(TypeError):
|
||||
G.__getitem__(["A"])
|
||||
|
||||
def test_remove_node(self):
|
||||
G = self.K3
|
||||
G.remove_node(0)
|
||||
assert G.adj == {1: {2: {0: {}}}, 2: {1: {0: {}}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_node(-1)
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}}
|
||||
G = self.Graph()
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edge(None, "anything")
|
||||
|
||||
def test_add_edge_conflicting_key(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1, key=1)
|
||||
G.add_edge(0, 1)
|
||||
assert G.number_of_edges() == 2
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1, 1, {})])
|
||||
G.add_edges_from([(0, 1)])
|
||||
assert G.number_of_edges() == 2
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})])
|
||||
assert G.adj == {
|
||||
0: {1: {0: {}, 1: {"weight": 3}}},
|
||||
1: {0: {0: {}, 1: {"weight": 3}}},
|
||||
}
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})], weight=2)
|
||||
assert G.adj == {
|
||||
0: {1: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
1: {0: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
}
|
||||
G = self.Graph()
|
||||
edges = [
|
||||
(0, 1, {"weight": 3}),
|
||||
(0, 1, (("weight", 2),)),
|
||||
(0, 1, 5),
|
||||
(0, 1, "s"),
|
||||
]
|
||||
G.add_edges_from(edges)
|
||||
keydict = {0: {"weight": 3}, 1: {"weight": 2}, 5: {}, "s": {}}
|
||||
assert G._adj == {0: {1: keydict}, 1: {0: keydict}}
|
||||
|
||||
# too few in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0,)])
|
||||
# too many in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0, 1, 2, 3, 4)])
|
||||
# not a tuple
|
||||
with pytest.raises(TypeError):
|
||||
G.add_edges_from([0])
|
||||
|
||||
def test_multigraph_add_edges_from_four_tuple_misordered(self):
|
||||
"""add_edges_from expects 4-tuples of the format (u, v, key, data_dict).
|
||||
|
||||
Ensure 4-tuples of form (u, v, data_dict, key) raise exception.
|
||||
"""
|
||||
G = nx.MultiGraph()
|
||||
with pytest.raises(TypeError):
|
||||
# key/data values flipped in 4-tuple
|
||||
G.add_edges_from([(0, 1, {"color": "red"}, 0)])
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3
|
||||
G.remove_edge(0, 1)
|
||||
assert G.adj == {0: {2: {0: {}}}, 1: {2: {0: {}}}, 2: {0: {0: {}}, 1: {0: {}}}}
|
||||
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(0, 2, key=1)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1)])
|
||||
kd = {0: {}}
|
||||
assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
self.K3.add_edge(0, 1)
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from(list(G.edges(data=True, keys=True)))
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from(list(G.edges(data=False, keys=True)))
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from(list(G.edges(data=False, keys=False)))
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1, 0), (0, 2, 0, {}), (1, 2)])
|
||||
assert G.adj == {0: {1: {1: {}}}, 1: {0: {1: {}}}, 2: {}}
|
||||
|
||||
def test_remove_multiedge(self):
|
||||
G = self.K3
|
||||
G.add_edge(0, 1, key="parallel edge")
|
||||
G.remove_edge(0, 1, key="parallel edge")
|
||||
assert G.adj == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
G.remove_edge(0, 1)
|
||||
kd = {0: {}}
|
||||
assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
|
||||
|
||||
class TestEdgeSubgraph:
|
||||
"""Unit tests for the :meth:`MultiGraph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a doubly-linked path graph on five nodes.
|
||||
G = nx.MultiGraph()
|
||||
nx.add_path(G, range(5))
|
||||
nx.add_path(G, range(5))
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.adj[0][1][0]["name"] = "edge010"
|
||||
G.adj[0][1][1]["name"] = "edge011"
|
||||
G.adj[3][4][0]["name"] = "edge340"
|
||||
G.adj[3][4][1]["name"] = "edge341"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by one of the first edges and one of
|
||||
# the last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)])
|
||||
|
||||
def test_correct_nodes(self):
|
||||
"""Tests that the subgraph has the correct nodes."""
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_correct_edges(self):
|
||||
"""Tests that the subgraph has the correct edges."""
|
||||
assert [(0, 1, 0, "edge010"), (3, 4, 1, "edge341")] == sorted(
|
||||
self.H.edges(keys=True, data="name")
|
||||
)
|
||||
|
||||
def test_add_node(self):
|
||||
"""Tests that adding a node to the original graph does not
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.add_node(5)
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_remove_node(self):
|
||||
"""Tests that removing a node in the original graph does
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.remove_node(0)
|
||||
assert [1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_node_attr_dict(self):
|
||||
"""Tests that the node attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for v in self.H:
|
||||
assert self.G.nodes[v] == self.H.nodes[v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.nodes[0]["name"] = "foo"
|
||||
assert self.G.nodes[0] == self.H.nodes[0]
|
||||
self.H.nodes[1]["name"] = "bar"
|
||||
assert self.G.nodes[1] == self.H.nodes[1]
|
||||
|
||||
def test_edge_attr_dict(self):
|
||||
"""Tests that the edge attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for u, v, k in self.H.edges(keys=True):
|
||||
assert self.G._adj[u][v][k] == self.H._adj[u][v][k]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G._adj[0][1][0]["name"] = "foo"
|
||||
assert self.G._adj[0][1][0]["name"] == self.H._adj[0][1][0]["name"]
|
||||
self.H._adj[3][4][1]["name"] = "bar"
|
||||
assert self.G._adj[3][4][1]["name"] == self.H._adj[3][4][1]["name"]
|
||||
|
||||
def test_graph_attr_dict(self):
|
||||
"""Tests that the graph attribute dictionary of the two graphs
|
||||
is the same object.
|
||||
|
||||
"""
|
||||
assert self.G.graph is self.H.graph
|
||||
|
||||
|
||||
class CustomDictClass(UserDict):
|
||||
pass
|
||||
|
||||
|
||||
class MultiGraphSubClass(nx.MultiGraph):
|
||||
node_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
node_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_outer_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_inner_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_key_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
graph_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
|
||||
|
||||
class TestMultiGraphSubclass(TestMultiGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = MultiGraphSubClass
|
||||
# build K3
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.K3.adjlist_outer_dict_factory(
|
||||
{
|
||||
0: self.K3.adjlist_inner_dict_factory(),
|
||||
1: self.K3.adjlist_inner_dict_factory(),
|
||||
2: self.K3.adjlist_inner_dict_factory(),
|
||||
}
|
||||
)
|
||||
self.K3._pred = {0: {}, 1: {}, 2: {}}
|
||||
for u in self.k3nodes:
|
||||
for v in self.k3nodes:
|
||||
if u != v:
|
||||
d = {0: {}}
|
||||
self.K3._adj[u][v] = d
|
||||
self.K3._adj[v][u] = d
|
||||
self.K3._node = self.K3.node_dict_factory()
|
||||
self.K3._node[0] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[1] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[2] = self.K3.node_attr_dict_factory()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,131 +0,0 @@
|
||||
import networkx as nx
|
||||
|
||||
from .test_digraph import BaseDiGraphTester
|
||||
from .test_digraph import TestDiGraph as _TestDiGraph
|
||||
from .test_graph import BaseGraphTester
|
||||
from .test_graph import TestGraph as _TestGraph
|
||||
from .test_multidigraph import TestMultiDiGraph as _TestMultiDiGraph
|
||||
from .test_multigraph import TestMultiGraph as _TestMultiGraph
|
||||
|
||||
|
||||
def test_factories():
|
||||
class mydict1(dict):
|
||||
pass
|
||||
|
||||
class mydict2(dict):
|
||||
pass
|
||||
|
||||
class mydict3(dict):
|
||||
pass
|
||||
|
||||
class mydict4(dict):
|
||||
pass
|
||||
|
||||
class mydict5(dict):
|
||||
pass
|
||||
|
||||
for Graph in (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph):
|
||||
# print("testing class: ", Graph.__name__)
|
||||
class MyGraph(Graph):
|
||||
node_dict_factory = mydict1
|
||||
adjlist_outer_dict_factory = mydict2
|
||||
adjlist_inner_dict_factory = mydict3
|
||||
edge_key_dict_factory = mydict4
|
||||
edge_attr_dict_factory = mydict5
|
||||
|
||||
G = MyGraph()
|
||||
assert isinstance(G._node, mydict1)
|
||||
assert isinstance(G._adj, mydict2)
|
||||
G.add_node(1)
|
||||
assert isinstance(G._adj[1], mydict3)
|
||||
if G.is_directed():
|
||||
assert isinstance(G._pred, mydict2)
|
||||
assert isinstance(G._succ, mydict2)
|
||||
assert isinstance(G._pred[1], mydict3)
|
||||
G.add_edge(1, 2)
|
||||
if G.is_multigraph():
|
||||
assert isinstance(G._adj[1][2], mydict4)
|
||||
assert isinstance(G._adj[1][2][0], mydict5)
|
||||
else:
|
||||
assert isinstance(G._adj[1][2], mydict5)
|
||||
|
||||
|
||||
class TestSpecialGraph(_TestGraph):
|
||||
def setup_method(self):
|
||||
_TestGraph.setup_method(self)
|
||||
self.Graph = nx.Graph
|
||||
|
||||
|
||||
class TestThinGraph(BaseGraphTester):
|
||||
def setup_method(self):
|
||||
all_edge_dict = {"weight": 1}
|
||||
|
||||
class MyGraph(nx.Graph):
|
||||
def edge_attr_dict_factory(self):
|
||||
return all_edge_dict
|
||||
|
||||
self.Graph = MyGraph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict)
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.k3adj
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
|
||||
class TestSpecialDiGraph(_TestDiGraph):
|
||||
def setup_method(self):
|
||||
_TestDiGraph.setup_method(self)
|
||||
self.Graph = nx.DiGraph
|
||||
|
||||
|
||||
class TestThinDiGraph(BaseDiGraphTester):
|
||||
def setup_method(self):
|
||||
all_edge_dict = {"weight": 1}
|
||||
|
||||
class MyGraph(nx.DiGraph):
|
||||
def edge_attr_dict_factory(self):
|
||||
return all_edge_dict
|
||||
|
||||
self.Graph = MyGraph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict)
|
||||
ed4, ed5, ed6 = (all_edge_dict, all_edge_dict, all_edge_dict)
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = self.k3adj
|
||||
# K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}}
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
ed1, ed2 = (all_edge_dict, all_edge_dict)
|
||||
self.P3 = self.Graph()
|
||||
self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}}
|
||||
# P3._adj is synced with P3._succ
|
||||
self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}}
|
||||
self.P3._node = {}
|
||||
self.P3._node[0] = {}
|
||||
self.P3._node[1] = {}
|
||||
self.P3._node[2] = {}
|
||||
|
||||
|
||||
class TestSpecialMultiGraph(_TestMultiGraph):
|
||||
def setup_method(self):
|
||||
_TestMultiGraph.setup_method(self)
|
||||
self.Graph = nx.MultiGraph
|
||||
|
||||
|
||||
class TestSpecialMultiDiGraph(_TestMultiDiGraph):
|
||||
def setup_method(self):
|
||||
_TestMultiDiGraph.setup_method(self)
|
||||
self.Graph = nx.MultiDiGraph
|
||||
@@ -1,363 +0,0 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
|
||||
class TestSubGraphView:
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.Graph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_edges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_edges)
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.path_graph(9, create_using=cls.graph())
|
||||
cls.hide_edges_w_hide_nodes = {(3, 4), (4, 5), (5, 6)}
|
||||
|
||||
def test_hidden_nodes(self):
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
gview = self.gview
|
||||
print(gview)
|
||||
G = gview(self.G, filter_node=nodes_gone)
|
||||
assert self.G.nodes - G.nodes == {4, 5}
|
||||
assert self.G.edges - G.edges == self.hide_edges_w_hide_nodes
|
||||
if G.is_directed():
|
||||
assert list(G[3]) == []
|
||||
assert list(G[2]) == [3]
|
||||
else:
|
||||
assert list(G[3]) == [2]
|
||||
assert set(G[2]) == {1, 3}
|
||||
pytest.raises(KeyError, G.__getitem__, 4)
|
||||
pytest.raises(KeyError, G.__getitem__, 112)
|
||||
pytest.raises(KeyError, G.__getitem__, 111)
|
||||
assert G.degree(3) == (3 if G.is_multigraph() else 1)
|
||||
assert G.size() == (7 if G.is_multigraph() else 5)
|
||||
|
||||
def test_hidden_edges(self):
|
||||
hide_edges = [(2, 3), (8, 7), (222, 223)]
|
||||
edges_gone = self.hide_edges_filter(hide_edges)
|
||||
gview = self.gview
|
||||
G = gview(self.G, filter_edge=edges_gone)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert self.G.edges - G.edges == {(2, 3)}
|
||||
assert list(G[2]) == []
|
||||
assert list(G.pred[3]) == []
|
||||
assert list(G.pred[2]) == [1]
|
||||
assert G.size() == 7
|
||||
else:
|
||||
assert self.G.edges - G.edges == {(2, 3), (7, 8)}
|
||||
assert list(G[2]) == [1]
|
||||
assert G.size() == 6
|
||||
assert list(G[3]) == [4]
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
assert G.degree(3) == 1
|
||||
|
||||
def test_shown_node(self):
|
||||
induced_subgraph = nx.filters.show_nodes([2, 3, 111])
|
||||
gview = self.gview
|
||||
G = gview(self.G, filter_node=induced_subgraph)
|
||||
assert set(G.nodes) == {2, 3}
|
||||
if G.is_directed():
|
||||
assert list(G[3]) == []
|
||||
else:
|
||||
assert list(G[3]) == [2]
|
||||
assert list(G[2]) == [3]
|
||||
pytest.raises(KeyError, G.__getitem__, 4)
|
||||
pytest.raises(KeyError, G.__getitem__, 112)
|
||||
pytest.raises(KeyError, G.__getitem__, 111)
|
||||
assert G.degree(3) == (3 if G.is_multigraph() else 1)
|
||||
assert G.size() == (3 if G.is_multigraph() else 1)
|
||||
|
||||
def test_shown_edges(self):
|
||||
show_edges = [(2, 3), (8, 7), (222, 223)]
|
||||
edge_subgraph = self.show_edges_filter(show_edges)
|
||||
G = self.gview(self.G, filter_edge=edge_subgraph)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert G.edges == {(2, 3)}
|
||||
assert list(G[3]) == []
|
||||
assert list(G[2]) == [3]
|
||||
assert list(G.pred[3]) == [2]
|
||||
assert list(G.pred[2]) == []
|
||||
assert G.size() == 1
|
||||
else:
|
||||
assert G.edges == {(2, 3), (7, 8)}
|
||||
assert list(G[3]) == [2]
|
||||
assert list(G[2]) == [3]
|
||||
assert G.size() == 2
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
assert G.degree(3) == 1
|
||||
|
||||
|
||||
class TestSubDiGraphView(TestSubGraphView):
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.DiGraph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_diedges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_diedges)
|
||||
hide_edges = [(2, 3), (8, 7), (222, 223)]
|
||||
excluded = {(2, 3), (3, 4), (4, 5), (5, 6)}
|
||||
|
||||
def test_inoutedges(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert self.G.in_edges - G.in_edges == self.excluded
|
||||
assert self.G.out_edges - G.out_edges == self.excluded
|
||||
|
||||
def test_pred(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert list(G.pred[2]) == [1]
|
||||
assert list(G.pred[6]) == []
|
||||
|
||||
def test_inout_degree(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert G.degree(2) == 1
|
||||
assert G.out_degree(2) == 0
|
||||
assert G.in_degree(2) == 1
|
||||
assert G.size() == 4
|
||||
|
||||
|
||||
# multigraph
|
||||
class TestMultiGraphView(TestSubGraphView):
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.MultiGraph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_multiedges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_multiedges)
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.path_graph(9, create_using=cls.graph())
|
||||
multiedges = {(2, 3, 4), (2, 3, 5)}
|
||||
cls.G.add_edges_from(multiedges)
|
||||
cls.hide_edges_w_hide_nodes = {(3, 4, 0), (4, 5, 0), (5, 6, 0)}
|
||||
|
||||
def test_hidden_edges(self):
|
||||
hide_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)]
|
||||
edges_gone = self.hide_edges_filter(hide_edges)
|
||||
G = self.gview(self.G, filter_edge=edges_gone)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert self.G.edges - G.edges == {(2, 3, 4)}
|
||||
assert list(G[3]) == [4]
|
||||
assert list(G[2]) == [3]
|
||||
assert list(G.pred[3]) == [2] # only one 2 but two edges
|
||||
assert list(G.pred[2]) == [1]
|
||||
assert G.size() == 9
|
||||
else:
|
||||
assert self.G.edges - G.edges == {(2, 3, 4), (7, 8, 0)}
|
||||
assert list(G[3]) == [2, 4]
|
||||
assert list(G[2]) == [1, 3]
|
||||
assert G.size() == 8
|
||||
assert G.degree(3) == 3
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
|
||||
def test_shown_edges(self):
|
||||
show_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)]
|
||||
edge_subgraph = self.show_edges_filter(show_edges)
|
||||
G = self.gview(self.G, filter_edge=edge_subgraph)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert G.edges == {(2, 3, 4)}
|
||||
assert list(G[3]) == []
|
||||
assert list(G.pred[3]) == [2]
|
||||
assert list(G.pred[2]) == []
|
||||
assert G.size() == 1
|
||||
else:
|
||||
assert G.edges == {(2, 3, 4), (7, 8, 0)}
|
||||
assert G.size() == 2
|
||||
assert list(G[3]) == [2]
|
||||
assert G.degree(3) == 1
|
||||
assert list(G[2]) == [3]
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
|
||||
|
||||
# multidigraph
|
||||
class TestMultiDiGraphView(TestMultiGraphView, TestSubDiGraphView):
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.MultiDiGraph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_multidiedges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_multidiedges)
|
||||
hide_edges = [(2, 3, 0), (8, 7, 0), (222, 223, 0)]
|
||||
excluded = {(2, 3, 0), (3, 4, 0), (4, 5, 0), (5, 6, 0)}
|
||||
|
||||
def test_inout_degree(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert G.degree(2) == 3
|
||||
assert G.out_degree(2) == 2
|
||||
assert G.in_degree(2) == 1
|
||||
assert G.size() == 6
|
||||
|
||||
|
||||
# induced_subgraph
|
||||
class TestInducedSubGraph:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.K3 = G = nx.complete_graph(3)
|
||||
G.graph["foo"] = []
|
||||
G.nodes[0]["foo"] = []
|
||||
G.remove_edge(1, 2)
|
||||
ll = []
|
||||
G.add_edge(1, 2, foo=ll)
|
||||
G.add_edge(2, 1, foo=ll)
|
||||
|
||||
def test_full_graph(self):
|
||||
G = self.K3
|
||||
H = nx.induced_subgraph(G, [0, 1, 2, 5])
|
||||
assert H.name == G.name
|
||||
self.graphs_equal(H, G)
|
||||
self.same_attrdict(H, G)
|
||||
|
||||
def test_partial_subgraph(self):
|
||||
G = self.K3
|
||||
H = nx.induced_subgraph(G, 0)
|
||||
assert dict(H.adj) == {0: {}}
|
||||
assert dict(G.adj) != {0: {}}
|
||||
|
||||
H = nx.induced_subgraph(G, [0, 1])
|
||||
assert dict(H.adj) == {0: {1: {}}, 1: {0: {}}}
|
||||
|
||||
def same_attrdict(self, H, G):
|
||||
old_foo = H[1][2]["foo"]
|
||||
H.edges[1, 2]["foo"] = "baz"
|
||||
assert G.edges == H.edges
|
||||
H.edges[1, 2]["foo"] = old_foo
|
||||
assert G.edges == H.edges
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G.nodes == H.nodes
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G.nodes == H.nodes
|
||||
|
||||
def graphs_equal(self, H, G):
|
||||
assert G._adj == H._adj
|
||||
assert G._node == H._node
|
||||
assert G.graph == H.graph
|
||||
assert G.name == H.name
|
||||
if not G.is_directed() and not H.is_directed():
|
||||
assert H._adj[1][2] is H._adj[2][1]
|
||||
assert G._adj[1][2] is G._adj[2][1]
|
||||
else: # at least one is directed
|
||||
if not G.is_directed():
|
||||
G._pred = G._adj
|
||||
G._succ = G._adj
|
||||
if not H.is_directed():
|
||||
H._pred = H._adj
|
||||
H._succ = H._adj
|
||||
assert G._pred == H._pred
|
||||
assert G._succ == H._succ
|
||||
assert H._succ[1][2] is H._pred[2][1]
|
||||
assert G._succ[1][2] is G._pred[2][1]
|
||||
|
||||
|
||||
# edge_subgraph
|
||||
class TestEdgeSubGraph:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
# Create a path graph on five nodes.
|
||||
cls.G = G = nx.path_graph(5)
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.edges[0, 1]["name"] = "edge01"
|
||||
G.edges[3, 4]["name"] = "edge34"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by the first and last edges.
|
||||
cls.H = nx.edge_subgraph(G, [(0, 1), (3, 4)])
|
||||
|
||||
def test_correct_nodes(self):
|
||||
"""Tests that the subgraph has the correct nodes."""
|
||||
assert [(0, "node0"), (1, "node1"), (3, "node3"), (4, "node4")] == sorted(
|
||||
self.H.nodes.data("name")
|
||||
)
|
||||
|
||||
def test_correct_edges(self):
|
||||
"""Tests that the subgraph has the correct edges."""
|
||||
assert edges_equal(
|
||||
[(0, 1, "edge01"), (3, 4, "edge34")], self.H.edges.data("name")
|
||||
)
|
||||
|
||||
def test_add_node(self):
|
||||
"""Tests that adding a node to the original graph does not
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.add_node(5)
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes)
|
||||
self.G.remove_node(5)
|
||||
|
||||
def test_remove_node(self):
|
||||
"""Tests that removing a node in the original graph
|
||||
removes the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.remove_node(0)
|
||||
assert [1, 3, 4] == sorted(self.H.nodes)
|
||||
self.G.add_node(0, name="node0")
|
||||
self.G.add_edge(0, 1, name="edge01")
|
||||
|
||||
def test_node_attr_dict(self):
|
||||
"""Tests that the node attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for v in self.H:
|
||||
assert self.G.nodes[v] == self.H.nodes[v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.nodes[0]["name"] = "foo"
|
||||
assert self.G.nodes[0] == self.H.nodes[0]
|
||||
self.H.nodes[1]["name"] = "bar"
|
||||
assert self.G.nodes[1] == self.H.nodes[1]
|
||||
# Revert the change, so tests pass with pytest-randomly
|
||||
self.G.nodes[0]["name"] = "node0"
|
||||
self.H.nodes[1]["name"] = "node1"
|
||||
|
||||
def test_edge_attr_dict(self):
|
||||
"""Tests that the edge attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for u, v in self.H.edges():
|
||||
assert self.G.edges[u, v] == self.H.edges[u, v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.edges[0, 1]["name"] = "foo"
|
||||
assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"]
|
||||
self.H.edges[3, 4]["name"] = "bar"
|
||||
assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"]
|
||||
# Revert the change, so tests pass with pytest-randomly
|
||||
self.G.edges[0, 1]["name"] = "edge01"
|
||||
self.H.edges[3, 4]["name"] = "edge34"
|
||||
|
||||
def test_graph_attr_dict(self):
|
||||
"""Tests that the graph attribute dictionary of the two graphs
|
||||
is the same object.
|
||||
|
||||
"""
|
||||
assert self.G.graph is self.H.graph
|
||||
|
||||
def test_readonly(self):
|
||||
"""Tests that the subgraph cannot change the graph structure"""
|
||||
pytest.raises(nx.NetworkXError, self.H.add_node, 5)
|
||||
pytest.raises(nx.NetworkXError, self.H.remove_node, 0)
|
||||
pytest.raises(nx.NetworkXError, self.H.add_edge, 5, 6)
|
||||
pytest.raises(nx.NetworkXError, self.H.remove_edge, 0, 1)
|
||||
Reference in New Issue
Block a user