|
|
import pytest |
|
|
|
|
|
import networkx as nx |
|
|
from networkx.utils import edges_equal, nodes_equal |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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): |
|
|
G = nx.Graph() |
|
|
pytest.raises(nx.NetworkXNotImplemented, nx.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): |
|
|
MG = nx.MultiGraph(self.G) |
|
|
pytest.raises(nx.NetworkXNotImplemented, nx.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] |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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") |
|
|
assert not hasattr(DCSG, "_graph") |
|
|
|
|
|
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") |
|
|
assert not hasattr(DCSG, "_graph") |
|
|
|
|
|
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") |
|
|
assert not hasattr(DCSG, "_graph") |
|
|
|
|
|
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") |
|
|
assert not hasattr(DCSG, "_graph") |
|
|
|
|
|
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 |
|
|
|