topolib 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of topolib might be problematic. Click here for more details.

@@ -0,0 +1,75 @@
1
+ @startuml TopolibModularClassDiagram
2
+
3
+ package topolib.topology {
4
+ class Topology {
5
+ - {static} topologies
6
+ -nodes: List<Node>
7
+ -links: List<Link>
8
+ +add_node(node: Node)
9
+ +remove_node(node_id: int)
10
+ +add_link(link: Link)
11
+ +remove_link(link_id: int)
12
+ +update_metrics()
13
+ +export_json(): str
14
+ +get_geographic_area(): float
15
+ +get_diameter(): float
16
+ +calculate_laplacian(): Matrix
17
+ +get_shortest_paths(s: int, d: int, N: int): List<Path>
18
+ +get_disjoint_paths(s: int, d: int, N: int): List<Path>
19
+ }
20
+
21
+ class Path {
22
+ -nodes: List<Node>
23
+ -total_length: float
24
+ +get_summary(): str
25
+ }
26
+ }
27
+
28
+ package topolib.elements {
29
+ class Node {
30
+ -id: int
31
+ -name: str
32
+ -latitude: float
33
+ -longitude: float
34
+ +coordinates(): Tuple[float, float]
35
+ }
36
+
37
+ class Link {
38
+ -id: int
39
+ -source: Node
40
+ -target: Node
41
+ -length: float
42
+ }
43
+ }
44
+
45
+ package topolib.analysis {
46
+ class Metrics {
47
+ +get_max_node_degree(topology: Topology): int
48
+ +get_min_node_degree(topology: Topology): int
49
+ +get_avg_node_degree(topology: Topology): float
50
+ +get_max_link_length(topology: Topology): float
51
+ +get_min_link_length(topology: Topology): float
52
+ +get_avg_link_length(topology: Topology): float
53
+ +get_connection_matrix(topology: Topology): numpy.ndarray
54
+ +get_link_value_matrix(topology: Topology): numpy.ndarray
55
+ +get_node_degree_matrix(topology: Topology): numpy.ndarray
56
+ }
57
+ }
58
+
59
+ package topolib.visualization {
60
+ class MapView {
61
+ +display_osm(topology: Topology)
62
+ +display_paper(topology: Topology)
63
+ }
64
+ }
65
+
66
+ topolib.topology.Topology --> topolib.elements.Node : uses
67
+ topolib.topology.Topology --> topolib.elements.Link : uses
68
+ topolib.topology.Topology --> topolib.analysis.Metrics : calculates
69
+ topolib.topology.Topology --> topolib.visualization.MapView : visualizes
70
+ topolib.topology.Topology --> topolib.topology.Path : generates
71
+
72
+ topolib.elements.Link --> topolib.elements.Node : connects
73
+ topolib.topology.Path --> topolib.elements.Node : traverses
74
+
75
+ @enduml
docs/Makefile ADDED
@@ -0,0 +1,20 @@
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line, and also
5
+ # from the environment for the first two.
6
+ SPHINXOPTS ?=
7
+ SPHINXBUILD ?= sphinx-build
8
+ SOURCEDIR = source
9
+ BUILDDIR = build
10
+
11
+ # Put it first so that "make" without argument is like "make help".
12
+ help:
13
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14
+
15
+ .PHONY: help Makefile
16
+
17
+ # Catch-all target: route all unknown targets to Sphinx using the new
18
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19
+ %: Makefile
20
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
docs/requirements.txt ADDED
@@ -0,0 +1,2 @@
1
+ sphinx
2
+ sphinx_rtd_theme
docs/source/conf.py ADDED
@@ -0,0 +1,37 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+
3
+ # -- Add project root to sys.path for autodoc --
4
+ import os
5
+ import sys
6
+ sys.path.insert(0, os.path.abspath(
7
+ os.path.join(os.path.dirname(__file__), '../../')))
8
+ #
9
+ # For the full list of built-in configuration values, see the documentation:
10
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
11
+
12
+ # -- Project information -----------------------------------------------------
13
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
14
+
15
+ project = 'topolib'
16
+ copyright = '2025, Danilo Borquez'
17
+ author = 'Danilo Borquez'
18
+ release = '0.1.0'
19
+
20
+ # -- General configuration ---------------------------------------------------
21
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
22
+
23
+ extensions = [
24
+ 'sphinx.ext.autodoc',
25
+ 'sphinx.ext.napoleon',
26
+ ]
27
+
28
+ templates_path = ['_templates']
29
+ exclude_patterns = []
30
+
31
+ language = 'en'
32
+
33
+ # -- Options for HTML output -------------------------------------------------
34
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
35
+
36
+ html_theme = 'sphinx_rtd_theme'
37
+ html_static_path = ['_static']
docs/source/index.rst ADDED
@@ -0,0 +1,33 @@
1
+ .. topolib documentation master file, created by
2
+ sphinx-quickstart on Wed Oct 8 18:21:25 2025.
3
+ You can adapt this file completely to your liking, but it should at least
4
+ contain the root `toctree` directive.
5
+
6
+
7
+ Welcome to Topolib's documentation!
8
+ ===================================
9
+
10
+ **Topolib** is a compact Python library for modeling, analyzing, and visualizing optical network topologies.
11
+ It provides a clean, object-oriented API for nodes, links, topologies, metrics, and visualization tools, making it ideal for research, teaching, and rapid prototyping in network science and engineering.
12
+
13
+ **Key features:**
14
+
15
+ - Modular design: elements, topology, analysis, and visualization
16
+ - Easy-to-use classes for nodes, links, and paths
17
+ - Built-in metrics and analysis helpers
18
+ - JSON import/export and interoperability
19
+ - Ready for integration with Sphinx, Read the Docs, and PyPI
20
+
21
+ Get started by exploring the modules below, or see the README for quick usage examples.
22
+
23
+ .. note::
24
+ This documentation is generated automatically from the source code and is always up to date with the latest release.
25
+
26
+
27
+
28
+ .. toctree::
29
+ :maxdepth: 2
30
+ :caption: Contents:
31
+
32
+ modules
33
+
@@ -0,0 +1,7 @@
1
+ topolib
2
+ =======
3
+
4
+ .. toctree::
5
+ :maxdepth: 4
6
+
7
+ topolib
@@ -0,0 +1,21 @@
1
+ topolib.analysis package
2
+ ========================
3
+
4
+ Submodules
5
+ ----------
6
+
7
+ topolib.analysis.metrics module
8
+ -------------------------------
9
+
10
+ .. automodule:: topolib.analysis.metrics
11
+ :members:
12
+ :undoc-members:
13
+ :show-inheritance:
14
+
15
+ Module contents
16
+ ---------------
17
+
18
+ .. automodule:: topolib.analysis
19
+ :members:
20
+ :undoc-members:
21
+ :show-inheritance:
@@ -0,0 +1,23 @@
1
+ topolib.elements package
2
+ ========================
3
+
4
+ Submodules
5
+ ----------
6
+
7
+ topolib.elements.link module
8
+ ----------------------------
9
+
10
+ .. automodule:: topolib.elements.link
11
+ :members:
12
+ :undoc-members:
13
+ :show-inheritance:
14
+
15
+ topolib.elements.node module
16
+ ----------------------------
17
+
18
+ .. automodule:: topolib.elements.node
19
+ :members:
20
+ :undoc-members:
21
+ :show-inheritance:
22
+
23
+
@@ -0,0 +1,20 @@
1
+ topolib package
2
+ ===============
3
+
4
+ Subpackages
5
+ -----------
6
+
7
+ .. toctree::
8
+ :maxdepth: 4
9
+
10
+ topolib.analysis
11
+ topolib.elements
12
+ topolib.topology
13
+
14
+ Module contents
15
+ ---------------
16
+
17
+ .. automodule:: topolib
18
+ :members:
19
+ :undoc-members:
20
+ :show-inheritance:
@@ -0,0 +1,29 @@
1
+ topolib.topology package
2
+ ========================
3
+
4
+ Submodules
5
+ ----------
6
+
7
+ topolib.topology.path module
8
+ ----------------------------
9
+
10
+ .. automodule:: topolib.topology.path
11
+ :members:
12
+ :undoc-members:
13
+ :show-inheritance:
14
+
15
+ topolib.topology.topology module
16
+ --------------------------------
17
+
18
+ .. automodule:: topolib.topology.topology
19
+ :members:
20
+ :undoc-members:
21
+ :show-inheritance:
22
+
23
+ Module contents
24
+ ---------------
25
+
26
+ .. automodule:: topolib.topology
27
+ :members:
28
+ :undoc-members:
29
+ :show-inheritance:
@@ -0,0 +1,11 @@
1
+ from topolib.visualization.mapview import MapView
2
+ from topolib.topology.topology import Topology
3
+
4
+ if __name__ == "__main__":
5
+ # Load real topology from JSON (you can change the file to another one from assets)
6
+ topo = Topology.from_json("topolib/assets/China_pop.json")
7
+ mapview = MapView(topo)
8
+ mapview.show_map()
9
+ topo = Topology.from_json("topolib/assets/DT-50_pop.json")
10
+ mapview = MapView(topo)
11
+ mapview.show_map()
tests/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # This file marks the tests directory as a Python package.
tests/test_link.py ADDED
@@ -0,0 +1,77 @@
1
+ import pytest
2
+ from topolib.elements.node import Node
3
+ from topolib.elements.link import Link
4
+
5
+
6
+ def test_link_creation_and_properties():
7
+ n1 = Node(1, "A", 0.0, 0.0)
8
+ n2 = Node(2, "B", 1.0, 1.0)
9
+ link = Link(10, n1, n2, 5.5)
10
+
11
+ assert link.id == 10
12
+ assert link.source is n1
13
+ assert link.target is n2
14
+ assert link.length == 5.5
15
+
16
+
17
+ def test_link_length_validation():
18
+ n1 = Node(1, "A", 0.0, 0.0)
19
+ n2 = Node(2, "B", 1.0, 1.0)
20
+ with pytest.raises(ValueError):
21
+ Link(1, n1, n2, -1)
22
+ with pytest.raises(TypeError):
23
+ Link(1, n1, n2, "not-a-number")
24
+
25
+
26
+ def test_link_endpoint_validation():
27
+ n1 = Node(1, "A", 0.0, 0.0)
28
+
29
+ # a dummy object without node attributes
30
+ class Dummy:
31
+ pass
32
+
33
+ with pytest.raises(TypeError):
34
+ Link(1, Dummy(), n1, 1.0)
35
+ with pytest.raises(TypeError):
36
+ Link(1, n1, Dummy(), 1.0)
37
+
38
+
39
+ def test_endpoints_and_repr():
40
+ n1 = Node(1, "A", 0.0, 0.0)
41
+ n2 = Node(2, "B", 1.0, 1.0)
42
+ link = Link(2, n1, n2, 10)
43
+ assert link.endpoints() == (n1, n2)
44
+ assert "Link(id=2" in repr(link)
45
+
46
+
47
+ def test_link_setters_and_errors():
48
+ n1 = Node(1, "A", 0.0, 0.0)
49
+ n2 = Node(2, "B", 1.0, 1.0)
50
+ link = Link(99, n1, n2, 1.0)
51
+ # Test id setter
52
+ link.id = 123
53
+ assert link.id == 123
54
+
55
+ # Test source setter error
56
+ class Dummy:
57
+ pass
58
+
59
+ with pytest.raises(TypeError):
60
+ link.source = Dummy()
61
+ # Test target setter error
62
+ with pytest.raises(TypeError):
63
+ link.target = Dummy()
64
+ # Test length setter error (non-numeric)
65
+ with pytest.raises(TypeError):
66
+ link.length = "bad"
67
+ # Test length setter error (negative)
68
+ with pytest.raises(ValueError):
69
+ link.length = -5
70
+
71
+
72
+ def test_link_length_setter_typeerror():
73
+ n1 = Node(1, "A", 0.0, 0.0)
74
+ n2 = Node(2, "B", 1.0, 1.0)
75
+ link = Link(1, n1, n2, 1.0)
76
+ with pytest.raises(TypeError):
77
+ link.length = object() # No convertible a float, cubre el except
tests/test_mapview.py ADDED
@@ -0,0 +1,33 @@
1
+ """
2
+ Unit tests for the MapView class in topolib.visualization.mapview.
3
+ Covers interface and error raising for unimplemented methods.
4
+ """
5
+
6
+ import pytest
7
+ from topolib.visualization import MapView
8
+ from topolib.topology import Topology
9
+ from topolib.elements.node import Node
10
+ from topolib.elements.link import Link
11
+ import matplotlib.pyplot as plt
12
+
13
+
14
+ def test_mapview_show_map_runs(monkeypatch):
15
+ """
16
+ Smoke test for MapView.show_map():
17
+ - Creates a minimal topology (2 nodes, 1 link)
18
+ - Instantiates MapView
19
+ - Mocks plt.show to avoid GUI popup
20
+ - Asserts that show_map() runs without error
21
+ """
22
+ # Create minimal topology
23
+ n1 = Node(1, "A", 0.0, 0.0)
24
+ n2 = Node(2, "B", 1.0, 1.0)
25
+ l1 = Link(1, n1, n2, 10.0)
26
+ topo = Topology(nodes=[n1, n2], links=[l1], name="TestNet")
27
+ mv = MapView(topo)
28
+
29
+ # Mock plt.show to avoid opening a window
30
+ monkeypatch.setattr(plt, "show", lambda: None)
31
+
32
+ # Should not raise any exception
33
+ mv.show_map()
tests/test_metrics.py ADDED
@@ -0,0 +1,53 @@
1
+ import pytest
2
+
3
+ from topolib.analysis.metrics import Metrics
4
+ from topolib.topology import Topology
5
+
6
+
7
+ from topolib.elements.node import Node
8
+ from topolib.elements.link import Link
9
+
10
+
11
+ def test_node_degree():
12
+ n1 = Node(1, "A", 0.0, 0.0)
13
+ n2 = Node(2, "B", 1.0, 1.0)
14
+ n3 = Node(3, "C", 2.0, 2.0)
15
+ l1 = Link(1, n1, n2, 10)
16
+ l2 = Link(2, n2, n3, 20)
17
+ topo = Topology(nodes=[n1, n2, n3], links=[l1, l2])
18
+ result = Metrics.node_degree(topo)
19
+ assert result == {1: 1, 2: 2, 3: 1}
20
+
21
+
22
+ def test_link_length_stats():
23
+ n1 = Node(1, "A", 0.0, 0.0)
24
+ n2 = Node(2, "B", 1.0, 1.0)
25
+ l1 = Link(1, n1, n2, 10)
26
+ l2 = Link(2, n2, n1, 20)
27
+ topo = Topology(nodes=[n1, n2], links=[l1, l2])
28
+ stats = Metrics.link_length_stats(topo)
29
+ assert stats["min"] == 10
30
+ assert stats["max"] == 20
31
+ assert stats["avg"] == 15
32
+ # Empty case
33
+ topo_empty = Topology()
34
+ assert Metrics.link_length_stats(topo_empty) == {
35
+ "min": None,
36
+ "max": None,
37
+ "avg": None,
38
+ }
39
+
40
+
41
+ def test_connection_matrix():
42
+ n1 = Node(1, "A", 0.0, 0.0)
43
+ n2 = Node(2, "B", 1.0, 1.0)
44
+ n3 = Node(3, "C", 2.0, 2.0)
45
+ l1 = Link(1, n1, n2, 10)
46
+ l2 = Link(2, n2, n3, 20)
47
+ topo = Topology(nodes=[n1, n2, n3], links=[l1, l2])
48
+ matrix = Metrics.connection_matrix(topo)
49
+ assert matrix == [
50
+ [0, 1, 0],
51
+ [1, 0, 1],
52
+ [0, 1, 0],
53
+ ]
tests/test_node.py ADDED
@@ -0,0 +1,44 @@
1
+ import pytest
2
+ from topolib.elements.node import Node
3
+
4
+
5
+ def test_node_creation():
6
+ node = Node(1, "A", -33.45, -70.66, weight=2.5, pop=100000)
7
+ assert node.id == 1
8
+ assert node.name == "A"
9
+ assert node.latitude == -33.45
10
+ assert node.longitude == -70.66
11
+ assert node.weight == 2.5
12
+ assert node.pop == 100000
13
+
14
+
15
+ def test_node_setters():
16
+ node = Node(0, "", 0.0, 0.0)
17
+ node.id = 10
18
+ node.name = "TestNode"
19
+ node.latitude = 55.5
20
+ node.longitude = -120.1
21
+ node.weight = 3.7
22
+ node.pop = 12345
23
+ assert node.id == 10
24
+ assert node.name == "TestNode"
25
+ assert node.latitude == 55.5
26
+ assert node.longitude == -120.1
27
+ assert node.weight == 3.7
28
+ assert node.pop == 12345
29
+
30
+
31
+ def test_node_coordinates():
32
+ node = Node(2, "B", 10.0, 20.0)
33
+ coords = node.coordinates()
34
+ assert coords == (10.0, 20.0)
35
+
36
+
37
+ def test_node_dc_ixp_attributes():
38
+ n = Node(1, "A", 0.0, 0.0, dc=42, ixp=7)
39
+ assert n.dc == 42
40
+ assert n.ixp == 7
41
+ n.dc = 100
42
+ n.ixp = 3
43
+ assert n.dc == 100
44
+ assert n.ixp == 3
tests/test_path.py ADDED
@@ -0,0 +1,46 @@
1
+ import pytest
2
+ from topolib.topology.path import Path
3
+
4
+
5
+ class DummyNode:
6
+ def __init__(self, id):
7
+ self.id = id
8
+
9
+ def __repr__(self):
10
+ return f"Node({self.id})"
11
+
12
+
13
+ class DummyLink:
14
+ def __init__(self, id):
15
+ self.id = id
16
+
17
+ def __repr__(self):
18
+ return f"Link({self.id})"
19
+
20
+
21
+ def test_path_creation():
22
+ nodes = [DummyNode(1), DummyNode(2), DummyNode(3)]
23
+ links = [DummyLink("a"), DummyLink("b")]
24
+ path = Path(nodes, links)
25
+ assert path.nodes == nodes
26
+ assert path.links == links
27
+ assert path.length() == 2
28
+ assert path.hop_count() == 2
29
+ assert path.endpoints() == (nodes[0], nodes[-1])
30
+
31
+
32
+ def test_path_invalid():
33
+ with pytest.raises(ValueError):
34
+ Path([], [])
35
+ with pytest.raises(ValueError):
36
+ Path([DummyNode(1)], [])
37
+ with pytest.raises(ValueError):
38
+ Path([DummyNode(1), DummyNode(2)], [DummyLink("a"), DummyLink("b")])
39
+
40
+
41
+ def test_path_repr():
42
+ nodes = [DummyNode(1), DummyNode(2)]
43
+ links = [DummyLink("a")]
44
+ path = Path(nodes, links)
45
+ s = repr(path)
46
+ assert s.startswith("Path(nodes=")