Skip to content

Commit ffded69

Browse files
Andrey Golovanovclaude
andcommitted
Replace removed ngraph.lib.graph with local SimpleGraph
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2a437fd commit ffded69

5 files changed

Lines changed: 84 additions & 13 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ __pycache__/
1313
.Python
1414
bin/
1515
env/
16+
venv/
1617
build/
1718
develop-eggs/
1819
dist/

netsim/applications/packet_network/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import logging
77
from typing import Callable, Dict, List, Optional, Set, Type, Union, Generator, Any
88

9-
from ngraph.lib.graph import StrictMultiDiGraph
9+
from netsim.applications.packet_network.graph import SimpleGraph
1010
from schema import Schema
1111

1212
from netsim.applications.packet_network.common import (
@@ -111,16 +111,16 @@ def __init__(self, starttime: SimTime = 0) -> None:
111111
starttime: The simulation start time (default 0).
112112
"""
113113
super().__init__(starttime=starttime)
114-
self.topology: Dict[str, StrictMultiDiGraph] = {}
114+
self.topology: Dict[str, SimpleGraph] = {}
115115
self.state_db: Dict[NetSimObjectName, Any] = {}
116116

117-
def add_topology(self, name: str, graph: StrictMultiDiGraph) -> None:
117+
def add_topology(self, name: str, graph: SimpleGraph) -> None:
118118
"""
119119
Register a topology graph object in the context.
120120
121121
Args:
122122
name: A unique name for the topology.
123-
graph: The StrictMultiDiGraph object representing the topology.
123+
graph: The SimpleGraph object representing the topology.
124124
"""
125125
self.topology[name] = graph
126126

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Lightweight graph used by the packet-network simulation layer.
2+
3+
This replaces the former dependency on ``ngraph.lib.graph.StrictMultiDiGraph``
4+
with a minimal, self-contained implementation that exposes only the API surface
5+
that NetSim actually needs.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
from typing import Any, Dict, Tuple
11+
12+
13+
class SimpleGraph:
14+
"""A directed multi-graph that stores nodes and edges with attributes.
15+
16+
Nodes are identified by arbitrary hashable *node_id* values.
17+
Edges are stored under integer keys that can be supplied explicitly or
18+
auto-assigned.
19+
"""
20+
21+
def __init__(self) -> None:
22+
self._nodes: dict = {}
23+
self._edges: dict = {}
24+
self._next_edge_id: int = 0
25+
26+
# -- node operations --------------------------------------------------- #
27+
28+
def add_node(self, node_id: Any, **attrs: Any) -> None:
29+
"""Add (or update) a node with optional keyword attributes."""
30+
self._nodes[node_id] = attrs
31+
32+
def get_nodes(self) -> Dict[Any, Dict[str, Any]]:
33+
"""Return ``{node_id: {attr_name: attr_value, ...}, ...}``."""
34+
return self._nodes
35+
36+
# -- edge operations --------------------------------------------------- #
37+
38+
def add_edge(
39+
self, src: Any, dst: Any, key: Any = None, **attrs: Any
40+
) -> Any:
41+
"""Add an edge from *src* to *dst*.
42+
43+
Parameters
44+
----------
45+
src, dst:
46+
Source and destination node ids.
47+
key:
48+
Optional edge key. When *None* the next available integer id is
49+
used automatically.
50+
**attrs:
51+
Arbitrary edge attributes.
52+
53+
Returns
54+
-------
55+
The key under which the edge was stored.
56+
"""
57+
if key is None:
58+
key = self._next_edge_id
59+
self._next_edge_id += 1
60+
else:
61+
# Keep the auto-id ahead of any explicitly supplied integer keys
62+
# so that future auto-assigned keys never collide.
63+
if isinstance(key, int) and key >= self._next_edge_id:
64+
self._next_edge_id = key + 1
65+
self._edges[key] = (src, dst, key, attrs)
66+
return key
67+
68+
def get_edges(self) -> Dict[Any, Tuple[Any, Any, Any, Dict[str, Any]]]:
69+
"""Return ``{edge_id: (src, dst, edge_id, {attrs}), ...}``."""
70+
return self._edges

netsim/applications/packet_network/simulator.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from copy import deepcopy
55
from typing import Any, Dict, Iterator, Optional, Type, Union
66

7-
from ngraph.lib.graph import StrictMultiDiGraph
7+
from netsim.applications.packet_network.graph import SimpleGraph
88

99
from netsim.common import SimTime, TimeInterval
1010
from netsim.core import (
@@ -147,7 +147,7 @@ def enable_packet_trace(self) -> None:
147147
if getattr(ns_obj.stat, "enable_packet_trace", None):
148148
ns_obj.stat.enable_packet_trace(prefix=ns_obj.name)
149149

150-
def _parse_graph_nodes(self, graph: StrictMultiDiGraph) -> None:
150+
def _parse_graph_nodes(self, graph: SimpleGraph) -> None:
151151
"""
152152
Parse the nodes of the input graph, creating NetSimObjects accordingly.
153153
"""
@@ -165,7 +165,7 @@ def _parse_graph_nodes(self, graph: StrictMultiDiGraph) -> None:
165165

166166
self._ns[node] = ns_node_obj
167167

168-
def _parse_graph_edges(self, graph: StrictMultiDiGraph) -> None:
168+
def _parse_graph_edges(self, graph: SimpleGraph) -> None:
169169
"""
170170
Parse edges of the input graph, hooking up subscriptions or creating interfaces for PacketSwitch objects.
171171
"""
@@ -196,7 +196,7 @@ def _postprocess_ns_obj(self) -> None:
196196
if isinstance(ns_node_obj, PacketSwitch):
197197
ns_node_obj.create_packet_processor()
198198

199-
def load_graph(self, graph: StrictMultiDiGraph) -> None:
199+
def load_graph(self, graph: SimpleGraph) -> None:
200200
"""
201201
Load a topology graph into the simulation, creating NetSimObjects and hooking them up.
202202
"""

tests/applications/packet_network/test_netsim_sim.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import math
44
from typing import Dict
55

6-
from ngraph.lib.graph import StrictMultiDiGraph
6+
from netsim.applications.packet_network.graph import SimpleGraph
77

88
from netsim.applications.packet_network.simulator import NetSim
99
from netsim.applications.packet_network.base import (
@@ -37,7 +37,7 @@ def _src_profile(size: int = 1000, interval: float = 1.0, count: int = 10) -> Di
3737
# --------------------------------------------------------------------------- #
3838
def test_load_graph_creates_objects() -> None:
3939
sim = NetSim()
40-
g = StrictMultiDiGraph()
40+
g = SimpleGraph()
4141
g.add_node("S", ns_type="PacketSource", ns_attr=_src_profile())
4242
g.add_node("D", ns_type="PacketSink", ns_attr={})
4343
g.add_edge("S", "D", key=1, ns_attr={})
@@ -58,7 +58,7 @@ def test_load_graph_creates_objects() -> None:
5858
# --------------------------------------------------------------------------- #
5959
def test_run_until_time_collects_stats() -> None:
6060
sim = NetSim(stat_interval=1.0) # 1 s snapshots
61-
g = StrictMultiDiGraph()
61+
g = SimpleGraph()
6262
g.add_node("S", ns_type="PacketSource", ns_attr=_src_profile(count=6))
6363
g.add_node("D", ns_type="PacketSink", ns_attr={})
6464
g.add_edge("S", "D", key=1, ns_attr={})
@@ -82,7 +82,7 @@ def test_run_until_time_collects_stats() -> None:
8282
# --------------------------------------------------------------------------- #
8383
def test_switch_interfaces_and_forwarding() -> None:
8484
sim = NetSim()
85-
g = StrictMultiDiGraph()
85+
g = SimpleGraph()
8686

8787
g.add_node("SRC", ns_type="PacketSource", ns_attr=_src_profile(count=5))
8888
g.add_node("SW", ns_type="PacketSwitch", ns_attr={})
@@ -131,7 +131,7 @@ def _safe_todict(self): # type: ignore[override]
131131
monkeypatch.setattr(_Packet, "todict", _safe_todict, raising=True)
132132

133133
sim = NetSim()
134-
g = StrictMultiDiGraph()
134+
g = SimpleGraph()
135135
g.add_node("S", ns_type="PacketSource", ns_attr=_src_profile(count=2))
136136
g.add_node("D", ns_type="PacketSink", ns_attr={})
137137
g.add_edge("S", "D", key=1, ns_attr={})

0 commit comments

Comments
 (0)