| 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)] |
|
|
| 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)] |
|
|
| 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 |
| |
| 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 |
| 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}} |
| |
| 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,)]) |
| with pytest.raises(nx.NetworkXError): |
| G.add_edges_from([(0, 1, 2, 3)]) |
| with 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.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)]) |
|
|
| 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): |
| |
| G = nx.DiGraph(nx.path_graph(5)) |
| |
| 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" |
| |
| 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)) == [] |
|
|