chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:36:30 +08:00
commit 55ab4e4a73
473 changed files with 72932 additions and 0 deletions
View File
+145
View File
@@ -0,0 +1,145 @@
import sys
import pytest
np = pytest.importorskip("numpy")
pd = pytest.importorskip("pandas")
sp = pytest.importorskip("scipy")
import easygraph as eg
from easygraph.utils.misc import *
class TestConvertNumpyArray:
def setup_method(self):
self.G1 = eg.complete_graph(5)
def assert_equal(self, G1, G2):
assert nodes_equal(G1.nodes, G2.nodes)
assert edges_equal(G1.edges, G2.edges, need_data=False)
def identity_conversion(self, G, A, create_using):
assert A.sum() > 0
GG = eg.from_numpy_array(A, create_using=create_using)
self.assert_equal(G, GG)
GW = eg.to_easygraph_graph(A, create_using=create_using)
self.assert_equal(G, GW)
def test_identity_graph_array(self):
A = eg.to_numpy_array(self.G1)
self.identity_conversion(self.G1, A, eg.Graph())
class TestConvertPandas:
def setup_method(self):
self.rng = np.random.RandomState(seed=5)
ints = self.rng.randint(1, 11, size=(3, 2))
a = ["A", "B", "C"]
b = ["D", "A", "E"]
df = pd.DataFrame(ints, columns=["weight", "cost"])
df[0] = a
df["b"] = b
self.df = df
mdf = pd.DataFrame([[4, 16, "A", "D"]], columns=["weight", "cost", 0, "b"])
self.mdf = pd.concat([df, mdf])
def assert_equal(self, G1, G2):
assert nodes_equal(G1.nodes, G2.nodes)
assert edges_equal(G1.edges, G2.edges, need_data=False)
def test_from_edgelist_multi_attr(self):
Gtrue = eg.Graph(
[
("E", "C", {"cost": 9, "weight": 10}),
("B", "A", {"cost": 1, "weight": 7}),
("A", "D", {"cost": 7, "weight": 4}),
]
)
G = eg.from_pandas_edgelist(self.df, 0, "b", ["weight", "cost"])
self.assert_equal(G, Gtrue)
def test_from_adjacency(self):
Gtrue = eg.DiGraph([("A", "B"), ("B", "C")])
data = {
"A": {"A": 0, "B": 0, "C": 0},
"B": {"A": 1, "B": 0, "C": 0},
"C": {"A": 0, "B": 1, "C": 0},
}
dftrue = pd.DataFrame(data, dtype=np.intp)
df = dftrue[["A", "C", "B"]]
G = eg.from_pandas_adjacency(df, create_using=eg.DiGraph())
self.assert_equal(G, Gtrue)
class TestConvertScipy:
def setup_method(self):
self.G1 = eg.complete_graph(3)
def assert_equal(self, G1, G2):
assert nodes_equal(G1.nodes, G2.nodes)
assert edges_equal(G1.edges, G2.edges, need_data=False)
@pytest.mark.skipif(
sys.version_info < (3, 8), reason="requires python3.8 or higher"
)
def test_from_scipy(self):
data = sp.sparse.csr_matrix([[0, 1, 1], [1, 0, 1], [1, 1, 0]])
G = eg.from_scipy_sparse_matrix(data)
self.assert_equal(self.G1, G)
def test_from_edgelist():
edgelist = [(0, 1), (1, 2)]
G = eg.from_edgelist(edgelist)
assert sorted((u, v) for u, v, _ in G.edges) == [(0, 1), (1, 2)]
def test_from_dict_of_lists():
d = {0: [1], 1: [2]}
G = eg.to_easygraph_graph(d)
assert sorted((u, v) for u, v, _ in G.edges) == [(0, 1), (1, 2)]
def test_from_dict_of_dicts():
d = {0: {1: {}}, 1: {2: {}}}
G = eg.to_easygraph_graph(d)
assert sorted((u, v) for u, v, _ in G.edges) == [(0, 1), (1, 2)]
def test_from_numpy_array():
G = eg.complete_graph(3)
A = eg.to_numpy_array(G)
G2 = eg.from_numpy_array(A)
assert sorted((u, v) for u, v, _ in G.edges) == sorted(
(u, v) for u, v, _ in G2.edges
)
def test_from_pandas_edgelist():
df = pd.DataFrame({"source": [0, 1], "target": [1, 2], "weight": [0.5, 0.7]})
G = eg.from_pandas_edgelist(df, source="source", target="target", edge_attr=True)
assert sorted((u, v) for u, v, _ in G.edges) == [(0, 1), (1, 2)]
def test_from_pandas_adjacency():
df = pd.DataFrame([[0, 1], [1, 0]], columns=["A", "B"], index=["A", "B"])
G = eg.from_pandas_adjacency(df)
assert sorted((u, v) for u, v, _ in G.edges) == [("A", "B")]
def test_from_scipy_sparse_matrix():
mat = sp.sparse.csr_matrix([[0, 1, 0], [1, 0, 1], [0, 1, 0]])
G = eg.from_scipy_sparse_matrix(mat)
expected_edges = [(0, 1), (1, 2)]
assert sorted((u, v) for u, v, _ in G.edges) == expected_edges
def test_invalid_dict_type():
class NotGraph:
pass
with pytest.raises(eg.EasyGraphError):
eg.to_easygraph_graph(NotGraph())
@@ -0,0 +1,97 @@
import os
import unittest
from easygraph import DiGraph
class TestDiGraph(unittest.TestCase):
def setUp(self):
self.G = DiGraph()
def test_add_node_and_exists(self):
self.G.add_node("A")
self.assertTrue(self.G.has_node("A"))
self.assertIn("A", self.G.nodes)
def test_add_nodes_with_attrs(self):
self.G.add_nodes(["B", "C"], nodes_attr=[{"age": 30}, {"age": 40}])
self.assertEqual(self.G.nodes["B"]["age"], 30)
self.assertEqual(self.G.nodes["C"]["age"], 40)
def test_add_edge_and_attrs(self):
self.G.add_edge("A", "B", weight=5)
self.assertTrue(self.G.has_edge("A", "B"))
self.assertEqual(self.G.adj["A"]["B"]["weight"], 5)
def test_add_edges_with_attrs(self):
self.G.add_edges([("B", "C"), ("C", "D")], edges_attr=[{"w": 1}, {"w": 2}])
self.assertEqual(self.G.adj["B"]["C"]["w"], 1)
self.assertEqual(self.G.adj["C"]["D"]["w"], 2)
def test_remove_node_and_edges(self):
self.G.add_edges([("X", "Y"), ("Y", "Z")])
self.G.remove_node("Y")
self.assertFalse("Y" in self.G.nodes)
self.assertFalse(self.G.has_edge("Y", "Z"))
def test_remove_edge(self):
self.G.add_edge("M", "N")
self.G.remove_edge("M", "N")
self.assertFalse(self.G.has_edge("M", "N"))
def test_degrees(self):
self.G.add_edges(
[("A", "B"), ("C", "B")], edges_attr=[{"weight": 3}, {"weight": 2}]
)
in_degrees = self.G.in_degree(weight="weight")
out_degrees = self.G.out_degree(weight="weight")
degrees = self.G.degree(weight="weight")
self.assertEqual(in_degrees["B"], 5)
self.assertEqual(out_degrees["A"], 3)
self.assertEqual(degrees["B"], 5)
def test_neighbors_and_preds(self):
self.G.add_edges([("P", "Q"), ("R", "P")])
self.assertIn("Q", list(self.G.neighbors("P")))
self.assertIn("R", list(self.G.predecessors("P")))
all_n = list(self.G.all_neighbors("P"))
self.assertIn("Q", all_n)
self.assertIn("R", all_n)
def test_size_and_num_edges_nodes(self):
self.G.add_edges([("X", "Y"), ("Y", "Z")])
self.assertEqual(self.G.size(), 2)
self.assertEqual(self.G.number_of_edges(), 2)
self.assertEqual(self.G.number_of_nodes(), 3)
def test_subgraph_and_ego(self):
self.G.add_edges([("A", "B"), ("B", "C"), ("C", "D")])
sub = self.G.nodes_subgraph(["A", "B", "C"])
self.assertTrue(sub.has_edge("A", "B"))
self.assertFalse(sub.has_edge("C", "D"))
ego = self.G.ego_subgraph("B")
self.assertIn("A", ego.nodes or [])
self.assertIn("C", ego.nodes or [])
def test_to_index_node_graph(self):
self.G.add_edges([("foo", "bar"), ("bar", "baz")])
G2, node2idx, idx2node = self.G.to_index_node_graph()
self.assertEqual(len(G2.nodes), 3)
self.assertEqual(node2idx["foo"], 0)
self.assertEqual(idx2node[0], "foo")
def test_copy(self):
self.G.add_edge("copyA", "copyB", weight=42)
G_copy = self.G.copy()
self.assertEqual(G_copy.adj["copyA"]["copyB"]["weight"], 42)
def test_file_add_edges(self):
fname = "temp_edges.txt"
with open(fname, "w") as f:
f.write("1 2 3.5\n2 3 4.5\n")
self.G.add_edges_from_file(fname, weighted=True)
os.remove(fname)
self.assertEqual(self.G.adj["1"]["2"]["weight"], 3.5)
self.assertEqual(self.G.adj["2"]["3"]["weight"], 4.5)
+112
View File
@@ -0,0 +1,112 @@
import os
import sys
import time
# sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'..', '..')))
import easygraph as eg # Spend 4.9s on importing this damn big lib.
"""
def test_iter():
g = eg.Graph()
# tests of corner cases
g.add_edge(0, 0)
g.add_edge(True, False)
g.add_edge(False, 1)
g.add_edge(0b1000, 0x00a, edge_attr={"age": 19, "gender": "Male"})
# g.add_edge(None, None) # this shall result in an AssertionError
# g.add_edge(None, 1) # this shall result in an AssertionError
# g.add_edge(1, None) # this shall result in an AssertionError
# g.add_edges(None) # Triggers a TypeError saying that len() is not applicable to None
g.add_edges([(True, False), ("Beijing National", "Day School")], [{}, {"Rating": 100}])
g.add_node("FuDan Univ", node_attr={"faculty": 10000}) # 1.
g.add_edge("Beijing National", "FuDan Univ")
# g.add_node([]) # this shall result in an unhashable error
g.add_node('Jack', node_attr={
'age': 10,
'gender': 'M'
})
# g.remove_node("Beijing National")
g.remove_edges([('Day School', 'Beijing National')])
# g.add_edges_from()
print(g.add_extra_selfloop())
g.nbr_v()
g.nbunch_iter()
g.from_hypergraph_hypergcn()
# print(g._adj[8].get(10))
print(g.edges)
print(g.nodes)
test_iter()
"""
from easygraph.datasets import get_graph_karateclub
G = get_graph_karateclub()
# Calculate five shs(Structural Hole Spanners) in G
shs = eg.common_greedy(G, 5)
# Draw the Graph, and the shs is marked by a red star
eg.draw_SHS_center(G, shs)
# Draw CDF curves of "Number of Followers" of SH spanners and ordinary users in G.
eg.plot_Followers(G, shs)
import easygraph as eg
G = eg.Graph()
G.add_edge(1, 2) # Add a single edge
print(G.edges)
G.add_edges([(2, 3), (1, 3), (3, 4), (4, 5), ((1, 2), (3, 4))]) # Add edges
print(G.edges)
G.add_node("hello world")
G.add_node("Jack", node_attr={"age": 10, "gender": "M"})
print(G.nodes)
# G.remove_nodes(['hello world','Tom','Lily','a','b'])#remove edges
G.remove_nodes(["hello world"])
print(G.nodes)
G.remove_edge(4, 5)
print(G.edges)
print(len(G)) # __len__(self)
for x in G: # __iter__(self)
print(x)
print(G[1]) # return list(self._adj[node].keys()) __contains__ __getitem__
for neighbor in G.neighbors(node=2):
print(neighbor)
G.add_edges(
[(1, 2), (2, 3), (1, 3), (3, 4), (4, 5)],
edges_attr=[
{"weight": 20},
{"weight": 10},
{"weight": 15},
{"weight": 8},
{"weight": 12},
],
) # add weighted edges
G.add_node(6)
print(G.edges)
print(G.degree())
print(G.degree(weight="weight"))
G_index_graph, index_of_node, node_of_index = G.to_index_node_graph()
print(G_index_graph.adj)
G1 = G.copy()
print(G1.adj)
print(eg.effective_size(G))
+122
View File
@@ -0,0 +1,122 @@
import unittest
import easygraph as eg
class TestEasyGraph(unittest.TestCase):
def setUp(self):
self.G = eg.Graph()
def test_add_single_node(self):
self.G.add_node(1)
self.assertIn(1, self.G.nodes)
def test_add_multiple_nodes(self):
self.G.add_nodes([2, 3, 4])
for node in [2, 3, 4]:
self.assertIn(node, self.G.nodes)
def test_add_node_with_attributes(self):
self.G.add_node("node", color="red")
self.assertEqual(self.G.nodes["node"]["color"], "red")
def test_add_single_edge(self):
self.G.add_edge(1, 2)
self.assertTrue(self.G.has_edge(1, 2))
self.assertTrue(self.G.has_edge(2, 1))
def test_add_edge_with_weight(self):
self.G.add_edge("a", "b", weight=10)
self.assertEqual(self.G["a"]["b"]["weight"], 10)
def test_add_edges(self):
self.G.add_edges([(1, 2), (2, 3)], edges_attr=[{"weight": 5}, {"weight": 6}])
self.assertEqual(self.G[1][2]["weight"], 5)
self.assertEqual(self.G[2][3]["weight"], 6)
def test_remove_node(self):
self.G.add_node(10)
self.G.remove_node(10)
self.assertNotIn(10, self.G.nodes)
def test_remove_edge(self):
self.G.add_edge(1, 2)
self.G.remove_edge(1, 2)
self.assertFalse(self.G.has_edge(1, 2))
def test_neighbors(self):
self.G.add_edges([(1, 2), (1, 3)])
neighbors = list(self.G.neighbors(1))
self.assertIn(2, neighbors)
self.assertIn(3, neighbors)
def test_subgraph(self):
self.G.add_edges([(1, 2), (2, 3), (3, 4)])
subG = self.G.nodes_subgraph([2, 3])
self.assertIn(2, subG.nodes)
self.assertIn(3, subG.nodes)
self.assertTrue(subG.has_edge(2, 3))
self.assertFalse(subG.has_edge(3, 4))
def test_ego_subgraph(self):
self.G.add_edges([(1, 2), (2, 3), (2, 4)])
ego = self.G.ego_subgraph(2)
self.assertIn(2, ego.nodes)
self.assertIn(1, ego.nodes)
self.assertIn(3, ego.nodes)
self.assertIn(4, ego.nodes)
def test_to_index_node_graph(self):
self.G.add_edges([("a", "b"), ("b", "c")])
G_index, index_of_node, node_of_index = self.G.to_index_node_graph()
self.assertEqual(len(G_index.nodes), 3)
self.assertTrue(all(isinstance(k, int) for k in G_index.nodes))
def test_directed_conversion(self):
self.G.add_edge(1, 2)
H = self.G.to_directed()
self.assertTrue(H.is_directed())
self.assertTrue(H.has_edge(1, 2))
self.assertTrue(H.has_edge(2, 1))
def test_clone_graph(self):
self.G.add_edges([(1, 2), (2, 3)])
G_clone = self.G.copy()
self.assertTrue(G_clone.has_edge(1, 2))
self.assertTrue(G_clone.has_edge(2, 3))
def test_degree(self):
self.G.add_edge(1, 2, weight=5)
deg = self.G.degree()
self.assertEqual(deg[1], 5)
self.assertEqual(deg[2], 5)
def test_size(self):
self.G.add_edges([(1, 2), (2, 3)])
self.assertEqual(self.G.size(), 2)
def test_edge_weight_default(self):
self.G.add_edge(4, 5)
self.assertEqual(self.G[4][5].get("weight", 1), 1)
def test_node_index_mappings(self):
self.G.add_nodes([10, 20, 30])
index2node = self.G.index2node
node_index = self.G.node_index
for i, node in index2node.items():
self.assertEqual(node_index[node], i)
def test_graph_order(self):
self.G.add_nodes([1, 2, 3])
self.assertEqual(self.G.order(), 3)
def test_graph_size_with_weight(self):
self.G.add_edges([(1, 2), (2, 3)], edges_attr=[{"weight": 4}, {"weight": 6}])
self.assertEqual(self.G.size(weight="weight"), 10.0)
def test_clear_cache(self):
self.G.add_edge(1, 2)
_ = self.G.edges
self.assertIn("edge", self.G.cache)
self.G._clear_cache()
self.assertEqual(len(self.G.cache), 0)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,114 @@
import unittest
import easygraph as eg
import pytest
class Test(unittest.TestCase):
def setUp(self):
edges = [(1, 2), (2, 3), ("String", "Bool"), (2, 1), ((1, 2), (3, 4))]
self.g = eg.MultiDiGraph(edges)
def test_add_edge(self):
self.g.add_edge("from_Beijing", "to_California", key=3, attr=None)
print(self.g.edges)
def test_remove_edge(self):
self.g.add_edge("from_Beijing", "to_California", key=3, attr=None)
self.g.remove_edge("from_Beijing", "to_California")
print(self.g.edges)
def test_degree(self):
print(self.g.degree)
print(self.g.in_degree)
print(self.g.out_degree)
def test_reverse(self):
# error with _succ
print(self.g.reverse(copy=True).edges)
# print(self.g.reverse(copy=False).edges)
def test_attributes(self):
print(self.g.edges)
print(self.g.in_edges)
class TestMultiDiGraph(unittest.TestCase):
def setUp(self):
self.G = eg.MultiDiGraph()
def test_add_edge_without_key(self):
key1 = self.G.add_edge("A", "B", weight=1)
key2 = self.G.add_edge("A", "B", weight=2)
self.assertNotEqual(key1, key2)
self.assertEqual(len(self.G._adj["A"]["B"]), 2)
def test_add_edge_with_key(self):
key = self.G.add_edge("A", "B", key="mykey", weight=3)
self.assertEqual(key, "mykey")
self.assertEqual(self.G._adj["A"]["B"]["mykey"]["weight"], 3)
def test_edge_attributes_update(self):
self.G.add_edge("X", "Y", key=1, color="red")
self.G.add_edge("X", "Y", key=1, shape="circle")
self.assertEqual(self.G._adj["X"]["Y"][1]["color"], "red")
self.assertEqual(self.G._adj["X"]["Y"][1]["shape"], "circle")
def test_remove_edge_by_key(self):
self.G.add_edge("A", "B", key="k1")
self.G.add_edge("A", "B", key="k2")
self.G.remove_edge("A", "B", key="k1")
self.assertIn("k2", self.G._adj["A"]["B"])
self.assertNotIn("k1", self.G._adj["A"]["B"])
def test_remove_edge_without_key(self):
self.G.add_edge("A", "B", key="auto1")
self.G.add_edge("A", "B", key="auto2")
self.G.remove_edge("A", "B")
# Only one of the keys should remain
self.assertEqual(len(self.G._adj["A"]["B"]), 1)
def test_remove_nonexistent_edge_raises(self):
with self.assertRaises(eg.EasyGraphError):
self.G.remove_edge("X", "Y", key="doesnotexist")
def test_edges_property(self):
self.G.add_edge("U", "V", key="k", weight=5)
edges = self.G.edges
self.assertIn(("U", "V", "k", {"weight": 5}), edges)
def test_in_out_degree(self):
self.G.add_edge("A", "B", weight=3)
self.G.add_edge("C", "B", weight=2)
in_deg = {}
for n in self.G._node:
preds = self.G._pred[n]
in_deg[n] = sum(
d.get("weight", 1)
for key_dict in preds.values()
for d in key_dict.values()
)
self.assertEqual(in_deg["B"], 5)
def test_to_undirected(self):
self.G.add_edge("A", "B", key="k", weight=10)
UG = self.G.to_undirected()
self.assertTrue(UG.has_edge("A", "B"))
self.assertEqual(UG["A"]["B"]["k"]["weight"], 10)
def test_reverse_graph(self):
self.G.add_edge("A", "B", key="k", data=99)
RG = self.G.reverse()
self.assertTrue(RG.has_edge("B", "A"))
self.assertEqual(RG["B"]["A"]["k"]["data"], 99)
def test_is_multigraph_and_directed(self):
self.assertTrue(self.G.is_multigraph())
self.assertTrue(self.G.is_directed())
if __name__ == "__main__":
unittest.main()
# test()
+149
View File
@@ -0,0 +1,149 @@
import easygraph as eg
import pytest
class TestMultiGraph:
def setup_method(self):
self.Graph = eg.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_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_data_multigraph_input(self):
# standard case with edge keys and edge data
edata0 = dict(w=200, s="foo")
edata1 = dict(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=None)
assert list(G.edges) == multiple_edge
G = self.Graph(dododod, multigraph_input=False)
assert list(G.edges) == single_edge
def test_remove_node(self):
G = self.K3
G.remove_node(0)
assert G.adj == {1: {2: {0: {}}}, 2: {1: {0: {}}}}
with pytest.raises(eg.EasyGraphError):
G.remove_node(-1)
class TestMultiGraphExtended:
def test_add_multiple_edges_and_keys(self):
G = eg.MultiGraph()
k0 = G.add_edge(1, 2)
k1 = G.add_edge(1, 2)
assert k0 == 0
assert k1 == 1
assert G.number_of_edges(1, 2) == 2
def test_add_edge_with_key_and_attributes(self):
G = eg.MultiGraph()
k = G.add_edge(1, 2, key="custom", weight=3, label="test")
assert k == "custom"
assert G.get_edge_data(1, 2, "custom") == {"weight": 3, "label": "test"}
def test_add_edges_from_various_formats(self):
G = eg.MultiGraph()
edges = [
(1, 2), # 2-tuple
(2, 3, {"weight": 7}), # 3-tuple with attr
(3, 4, "k1", {"color": "red"}), # 4-tuple
]
keys = G.add_edges_from(edges, capacity=100)
assert len(keys) == 3
assert G.get_edge_data(3, 4, "k1")["color"] == "red"
assert G.get_edge_data(2, 3, 0)["capacity"] == 100
def test_remove_edge_with_key(self):
G = eg.MultiGraph()
G.add_edge(1, 2, key="a")
G.add_edge(1, 2, key="b")
G.remove_edge(1, 2, key="a")
assert not G.has_edge(1, 2, key="a")
assert G.has_edge(1, 2, key="b")
def test_remove_edge_arbitrary(self):
G = eg.MultiGraph()
G.add_edge(1, 2)
G.add_edge(1, 2)
G.remove_edge(1, 2)
assert G.number_of_edges(1, 2) == 1
def test_remove_edges_from_mixed(self):
G = eg.MultiGraph()
keys = G.add_edges_from([(1, 2), (1, 2), (2, 3)])
G.remove_edges_from([(1, 2), (2, 3)])
assert G.number_of_edges(1, 2) == 1
assert G.number_of_edges(2, 3) == 0
def test_to_directed_graph(self):
G = eg.MultiGraph()
G.add_edge(0, 1, weight=10)
D = G.to_directed()
assert D.is_directed()
assert D.has_edge(0, 1)
assert D.has_edge(1, 0)
assert D.get_edge_data(0, 1, 0)["weight"] == 10
def test_copy_graph(self):
G = eg.MultiGraph()
G.add_edge(1, 2, key="x", weight=9)
H = G.copy()
assert H.get_edge_data(1, 2, "x") == {"weight": 9}
assert H is not G
assert H.get_edge_data(1, 2, "x") is not G.get_edge_data(1, 2, "x")
def test_has_edge_variants(self):
G = eg.MultiGraph()
G.add_edge(1, 2)
G.add_edge(1, 2, key="z")
assert G.has_edge(1, 2)
assert G.has_edge(1, 2, key="z")
assert not G.has_edge(2, 1, key="nonexistent")
def test_get_edge_data_defaults(self):
G = eg.MultiGraph()
assert G.get_edge_data(10, 20) is None
assert G.get_edge_data(10, 20, key="any", default="missing") == "missing"
def test_edge_property_returns_all_edges(self):
G = eg.MultiGraph()
G.add_edge(0, 1, key=5, label="important")
G.add_edge(1, 0, key=3, label="also important")
edges = list(G.edges)
assert any((0, 1, 5, {"label": "important"}) == e for e in edges)
assert any((0, 1, 3, {"label": "also important"}) == e for e in edges)
+131
View File
@@ -0,0 +1,131 @@
import easygraph as eg
import pytest
from easygraph.classes import operation
from easygraph.utils import edges_equal
@pytest.mark.parametrize(
"graph_type", [eg.Graph, eg.DiGraph, eg.MultiGraph, eg.MultiDiGraph]
)
def test_selfloops(graph_type):
G = eg.complete_graph(3, create_using=graph_type)
G.add_edge(0, 0)
assert edges_equal(eg.selfloop_edges(G), [(0, 0)])
assert edges_equal(eg.selfloop_edges(G, data=True), [(0, 0, {})])
assert eg.number_of_selfloops(G) == 1
def test_set_edge_attributes_scalar():
G = eg.path_graph(3)
eg.set_edge_attributes(G, 5, "weight")
for _, _, data in G.edges:
assert data["weight"] == 5
def test_set_edge_attributes_dict():
G = eg.path_graph(3)
attrs = {(0, 1): 3, (1, 2): 7}
eg.set_edge_attributes(G, attrs, "weight")
assert G[0][1]["weight"] == 3
assert G[1][2]["weight"] == 7
def test_set_edge_attributes_dict_of_dict():
G = eg.path_graph(3)
attrs = {(0, 1): {"a": 1}, (1, 2): {"b": 2}}
eg.set_edge_attributes(G, attrs)
assert G[0][1]["a"] == 1
assert G[1][2]["b"] == 2
def test_set_node_attributes_scalar():
G = eg.path_graph(3)
eg.set_node_attributes(G, 42, "level")
for n in G.nodes:
assert G.nodes[n]["level"] == 42
def test_set_node_attributes_dict():
G = eg.path_graph(3)
eg.set_node_attributes(G, {0: "x", 1: "y"}, name="tag")
assert G.nodes[0]["tag"] == "x"
assert G.nodes[1]["tag"] == "y"
def test_set_node_attributes_dict_of_dict():
G = eg.path_graph(3)
eg.set_node_attributes(G, {0: {"foo": 10}, 1: {"bar": 20}})
assert G.nodes[0]["foo"] == 10
assert G.nodes[1]["bar"] == 20
def test_add_path_structure_and_attrs():
G = eg.Graph()
eg.add_path(G, [10, 11, 12], weight=9)
actual_edges = {(u, v) for u, v, _ in G.edges}
assert actual_edges == {(10, 11), (11, 12)}
assert G[10][11]["weight"] == 9
assert G[11][12]["weight"] == 9
def test_topological_sort_linear():
G = eg.DiGraph()
G.add_edges_from([(1, 2), (2, 3)])
assert list(operation.topological_sort(G)) == [1, 2, 3]
def test_topological_sort_cycle():
G = eg.DiGraph([(0, 1), (1, 2), (2, 0)])
with pytest.raises(AssertionError, match="contains a cycle"):
list(operation.topological_sort(G))
def test_selfloop_edges_variants():
G = eg.MultiGraph()
G.add_edge(0, 0, key="x", label="loop")
G.add_edge(1, 1, key="y", label="loop2")
basic = list(eg.selfloop_edges(G))
with_data = list(eg.selfloop_edges(G, data=True))
with_keys = list(eg.selfloop_edges(G, keys=True))
full = list(eg.selfloop_edges(G, keys=True, data="label"))
assert (0, 0) in basic and (1, 1) in basic
assert all(len(t) == 3 for t in with_data)
assert all(len(t) == 3 for t in with_keys)
assert "x" in [k for _, _, k, _ in full]
def test_number_of_selfloops():
G = eg.MultiGraph()
G.add_edges_from([(0, 0), (1, 1), (1, 2)])
assert eg.number_of_selfloops(G) == 2
def test_density_undirected():
G = eg.complete_graph(5)
d = eg.density(G)
assert pytest.approx(d, 0.01) == 1.0
def test_density_directed():
G = eg.DiGraph()
G.add_edges_from([(0, 1), (1, 2)])
d = eg.density(G)
assert pytest.approx(d, 0.01) == 2 / (3 * (3 - 1)) # 2/6
def test_topological_generations_linear():
G = eg.DiGraph()
G.add_edges_from([(1, 2), (2, 3), (3, 4)])
generations = list(operation.topological_generations(G))
assert generations == [[1], [2], [3], [4]]
def test_topological_generations_branching():
G = eg.DiGraph()
G.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
generations = list(operation.topological_generations(G))
# Valid topological generations: [1], [2, 3], [4]
assert generations[0] == [1]
assert set(generations[1]) == {2, 3}
assert generations[2] == [4]