topolib 0.4.2__py3-none-any.whl → 0.5.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.

Files changed (38) hide show
  1. topolib/assets/AMRES.json +1265 -0
  2. topolib/assets/Bell_canada.json +925 -0
  3. topolib/assets/Brazil.json +699 -0
  4. topolib/assets/CESNET.json +657 -0
  5. topolib/assets/CORONET.json +1957 -0
  6. topolib/assets/{China_pop.json → China.json} +109 -37
  7. topolib/assets/DT-14.json +470 -0
  8. topolib/assets/DT-17.json +525 -0
  9. topolib/assets/{DT-50_pop.json → DT-50.json} +165 -65
  10. topolib/assets/ES-30.json +967 -0
  11. topolib/assets/EURO-16.json +455 -0
  12. topolib/assets/FR-43.json +1277 -0
  13. topolib/assets/FUNET.json +317 -0
  14. topolib/assets/GCN-BG.json +855 -0
  15. topolib/assets/GRNET.json +1717 -0
  16. topolib/assets/HyperOne.json +255 -0
  17. topolib/assets/IT-21.json +649 -0
  18. topolib/assets/India.json +517 -0
  19. topolib/assets/JPN-12.json +331 -0
  20. topolib/assets/KOREN.json +287 -0
  21. topolib/assets/NORDUNet.json +783 -0
  22. topolib/assets/NSFNet.json +399 -0
  23. topolib/assets/PANEURO.json +757 -0
  24. topolib/assets/PAVLOV.json +465 -0
  25. topolib/assets/PLN-12.json +343 -0
  26. topolib/assets/SANReN.json +161 -0
  27. topolib/assets/SERBIA-MONTENEGRO.json +139 -0
  28. topolib/assets/Telefonica-21.json +637 -0
  29. topolib/assets/Turk_Telekom.json +551 -0
  30. topolib/assets/UKNet.json +685 -0
  31. topolib/assets/Vega_Telecom.json +819 -0
  32. topolib/topology/topology.py +252 -7
  33. {topolib-0.4.2.dist-info → topolib-0.5.0.dist-info}/METADATA +4 -2
  34. topolib-0.5.0.dist-info/RECORD +47 -0
  35. topolib-0.4.2.dist-info/RECORD +0 -18
  36. /topolib/assets/{Abilene_IXP.json → Abilene.json} +0 -0
  37. {topolib-0.4.2.dist-info → topolib-0.5.0.dist-info}/WHEEL +0 -0
  38. {topolib-0.4.2.dist-info → topolib-0.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -8,9 +8,14 @@ This file uses NetworkX (BSD 3-Clause License):
8
8
  https://github.com/networkx/networkx/blob/main/LICENSE.txt
9
9
  """
10
10
 
11
- from typing import List, Dict, Any, Optional
11
+ from typing import List, Optional, Any
12
+ from numpy.typing import NDArray
12
13
  import numpy as np
13
14
  import networkx as nx
15
+ import json
16
+ import jsonschema
17
+ import csv
18
+ import networkx as nx
14
19
  from topolib.elements.node import Node
15
20
  from topolib.elements.link import Link
16
21
 
@@ -62,7 +67,7 @@ class Topology:
62
67
  self.links = links if links is not None else []
63
68
  self.name = name
64
69
  # Internal NetworkX graph for algorithms and visualization
65
- self._graph = nx.Graph()
70
+ self._graph: nx.DiGraph[Any] = nx.DiGraph()
66
71
  for node in self.nodes:
67
72
  self._graph.add_node(node.id, node=node)
68
73
  for link in self.links:
@@ -78,12 +83,51 @@ class Topology:
78
83
  :return: Topology instance loaded from the file.
79
84
  :rtype: Topology
80
85
  """
81
- import json
82
- from topolib.elements.node import Node
83
- from topolib.elements.link import Link
84
-
85
86
  with open(json_path, "r", encoding="utf-8") as f:
86
87
  data = json.load(f)
88
+
89
+ # Validation schema for the assets JSON format
90
+ topology_schema: dict[str, Any] = {
91
+ "type": "object",
92
+ "properties": {
93
+ "name": {"type": "string"},
94
+ "nodes": {
95
+ "type": "array",
96
+ "items": {
97
+ "type": "object",
98
+ "properties": {
99
+ "id": {"type": "integer"},
100
+ "name": {"type": "string"},
101
+ "weight": {"type": "number"},
102
+ "latitude": {"type": "number"},
103
+ "longitude": {"type": "number"},
104
+ "pop": {"type": "integer"},
105
+ "DC": {"type": "integer"},
106
+ "IXP": {"type": "integer"},
107
+ },
108
+ "required": ["id", "name", "latitude", "longitude"],
109
+ },
110
+ },
111
+ "links": {
112
+ "type": "array",
113
+ "items": {
114
+ "type": "object",
115
+ "properties": {
116
+ "id": {"type": "integer"},
117
+ "src": {"type": "integer"},
118
+ "dst": {"type": "integer"},
119
+ "length": {"type": "number"},
120
+ },
121
+ "required": ["id", "src", "dst", "length"],
122
+ },
123
+ },
124
+ },
125
+ "required": ["nodes", "links"],
126
+ }
127
+ try:
128
+ jsonschema.validate(instance=data, schema=topology_schema)
129
+ except jsonschema.ValidationError as e:
130
+ raise ValueError(f"Invalid topology JSON format: {e.message}")
87
131
  nodes = [
88
132
  Node(
89
133
  n["id"],
@@ -152,7 +196,7 @@ class Topology:
152
196
  self._graph.remove_edge(link.source.id, link.target.id)
153
197
  self.links = [l for l in self.links if l.id != link_id]
154
198
 
155
- def adjacency_matrix(self) -> np.ndarray:
199
+ def adjacency_matrix(self) -> NDArray[np.int_]:
156
200
  """
157
201
  Return the adjacency matrix of the topology as a numpy array.
158
202
 
@@ -170,3 +214,204 @@ class Topology:
170
214
  node_ids = [n.id for n in self.nodes]
171
215
  mat = nx.to_numpy_array(self._graph, nodelist=node_ids, dtype=int)
172
216
  return mat
217
+
218
+ def export_to_json(self, file_path: str) -> None:
219
+ """
220
+ Exporta la topología actual al formato JSON usado en la carpeta assets.
221
+
222
+ :param file_path: Ruta donde se guardará el archivo JSON.
223
+ :type file_path: str
224
+
225
+ **Ejemplo de uso**
226
+ >>> topo.export_to_json("/ruta/salida.json")
227
+
228
+ **Ejemplo de formato de salida**
229
+ {
230
+ "name": "Abilene",
231
+ "nodes": [
232
+ {
233
+ "id": 0,
234
+ "name": "Seattle",
235
+ "weight": 0,
236
+ "longitude": -122.3328481,
237
+ "latitude": 47.6061389,
238
+ "pop": 780995,
239
+ "DC": 58,
240
+ "IXP": 5
241
+ },
242
+ # ...
243
+ ],
244
+ "links": [
245
+ {
246
+ "id": 0,
247
+ "src": 0,
248
+ "dst": 1,
249
+ "length": 1482.26
250
+ },
251
+ # ...
252
+ ]
253
+ }
254
+ """
255
+ nodes_list: list[dict[str, Any]] = []
256
+ for n in self.nodes:
257
+ node_dict: dict[str, Any] = {
258
+ "id": n.id,
259
+ "name": getattr(n, "name", None),
260
+ "weight": getattr(n, "weight", 0),
261
+ "latitude": getattr(n, "latitude", None),
262
+ "longitude": getattr(n, "longitude", None),
263
+ "pop": getattr(n, "pop", 0),
264
+ "DC": getattr(n, "dc", getattr(n, "DC", 0)),
265
+ "IXP": getattr(n, "ixp", getattr(n, "IXP", 0)),
266
+ }
267
+ nodes_list.append(node_dict)
268
+ links_list: list[dict[str, Any]] = []
269
+ for l in self.links:
270
+ link_dict: dict[str, Any] = {
271
+ "id": l.id,
272
+ "src": l.source.id,
273
+ "dst": l.target.id,
274
+ "length": getattr(l, "length", None),
275
+ }
276
+ links_list.append(link_dict)
277
+ data: dict[str, Any] = {
278
+ "name": self.name if self.name else "Topology",
279
+ "nodes": nodes_list,
280
+ "links": links_list,
281
+ }
282
+ with open(file_path, "w", encoding="utf-8") as f:
283
+ json.dump(data, f, indent=4, ensure_ascii=False)
284
+
285
+ def export_to_csv(self, filename_prefix: str) -> None:
286
+ """
287
+ Export the topology to two CSV files: one for nodes and one for links.
288
+ The files will be named as <filename_prefix>_nodes.csv and <filename_prefix>_links.csv.
289
+
290
+ :param filename_prefix: Prefix for the output files (e.g., 'topology1').
291
+ :type filename_prefix: str
292
+
293
+ Example:
294
+ >>> topo.export_to_csv("mytopo")
295
+ # Generates 'mytopo_nodes.csv' and 'mytopo_links.csv'
296
+ """
297
+ # Export nodes
298
+ nodes_path = f"{filename_prefix}_nodes.csv"
299
+ with open(nodes_path, "w", newline="", encoding="utf-8") as f:
300
+ writer = csv.writer(f)
301
+ # Header
302
+ writer.writerow(
303
+ ["id", "name", "weight", "latitude", "longitude", "pop", "DC", "IXP"]
304
+ )
305
+ for n in self.nodes:
306
+ writer.writerow(
307
+ [
308
+ n.id,
309
+ getattr(n, "name", None),
310
+ getattr(n, "weight", 0),
311
+ getattr(n, "latitude", None),
312
+ getattr(n, "longitude", None),
313
+ getattr(n, "pop", 0),
314
+ getattr(n, "dc", getattr(n, "DC", 0)),
315
+ getattr(n, "ixp", getattr(n, "IXP", 0)),
316
+ ]
317
+ )
318
+ # Export links
319
+ links_path = f"{filename_prefix}_links.csv"
320
+ with open(links_path, "w", newline="", encoding="utf-8") as f:
321
+ writer = csv.writer(f)
322
+ writer.writerow(["id", "src", "dst", "length"])
323
+ for l in self.links:
324
+ writer.writerow(
325
+ [
326
+ l.id,
327
+ l.source.id,
328
+ l.target.id,
329
+ getattr(l, "length", None),
330
+ ]
331
+ )
332
+
333
+ def export_to_flexnetsim_json(self, file_path: str, slots: int) -> None:
334
+ """
335
+ Export the current topology to a JSON file compatible with Flex Net Sim.
336
+
337
+ :param file_path: Path where the JSON file will be saved.
338
+ :type file_path: str
339
+ :param slots: Number of slots for each link.
340
+ :type slots: int
341
+
342
+ The generated format includes the following fields:
343
+ - alias: short name of the topology (uses self.name if available)
344
+ - name: full name of the topology (uses self.name if available)
345
+ - nodes: list of nodes with 'id' field
346
+ - links: list of links with id, src, dst, length, slots
347
+ """
348
+ alias = self.name if self.name else "Topology"
349
+ name = self.name if self.name else "Topology"
350
+ nodes_list = [{"id": n.id} for n in self.nodes]
351
+ links_list = []
352
+ for l in self.links:
353
+ link_dict = {
354
+ "id": l.id,
355
+ "src": l.source.id,
356
+ "dst": l.target.id,
357
+ "length": getattr(l, "length", None),
358
+ "slots": slots,
359
+ }
360
+ links_list.append(link_dict)
361
+ data = {
362
+ "alias": alias,
363
+ "name": name,
364
+ "nodes": nodes_list,
365
+ "links": links_list,
366
+ }
367
+ with open(file_path, "w", encoding="utf-8") as f:
368
+ json.dump(data, f, indent=4, ensure_ascii=False)
369
+
370
+ def export_to_flexnetsim_ksp_json(self, file_path: str, k: int = 3) -> None:
371
+ """
372
+ Export the k-shortest paths between all node pairs to a JSON file compatible with Flex Net Sim.
373
+
374
+ :param file_path: Path where the JSON file will be saved.
375
+ :type file_path: str
376
+ :param k: Number of shortest paths to compute for each node pair (default: 3).
377
+ :type k: int
378
+
379
+ The output format matches Flex Net Sim's routes.json:
380
+ {
381
+ "name": self.name,
382
+ "alias": self.name,
383
+ "routes": [
384
+ {"src": <id>, "dst": <id>, "paths": [[id, ...], ...]},
385
+ ...
386
+ ]
387
+ }
388
+ """
389
+
390
+ # Build a weighted graph using link length as edge weight
391
+ G = nx.DiGraph()
392
+ for l in self.links:
393
+ G.add_edge(l.source.id, l.target.id, weight=getattr(l, "length", 1))
394
+ routes = []
395
+ node_ids = [n.id for n in self.nodes]
396
+ for src in node_ids:
397
+ for dst in node_ids:
398
+ if src == dst:
399
+ continue
400
+ try:
401
+ # Compute k shortest paths using link length as weight
402
+ paths_gen = nx.shortest_simple_paths(G, src, dst, weight="weight")
403
+ paths = []
404
+ for i, path in enumerate(paths_gen):
405
+ if i >= k:
406
+ break
407
+ paths.append(path)
408
+ except (nx.NetworkXNoPath, nx.NodeNotFound):
409
+ paths = []
410
+ routes.append({"src": src, "dst": dst, "paths": paths})
411
+ data = {
412
+ "name": self.name if self.name else "Topology",
413
+ "alias": self.name if self.name else "Topology",
414
+ "routes": routes,
415
+ }
416
+ with open(file_path, "w", encoding="utf-8") as f:
417
+ json.dump(data, f, indent=4, ensure_ascii=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topolib
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: A compact Python library for modeling, analyzing, and visualizing optical network topologies.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -21,6 +21,7 @@ Classifier: Topic :: Scientific/Engineering :: Information Analysis
21
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
22
  Requires-Dist: contextily
23
23
  Requires-Dist: geopandas
24
+ Requires-Dist: jsonschema (>=4.0)
24
25
  Requires-Dist: matplotlib
25
26
  Requires-Dist: networkx (>=2.6)
26
27
  Requires-Dist: numpy (>=1.21)
@@ -51,7 +52,8 @@ Description-Content-Type: text/markdown
51
52
 
52
53
  Explore ready-to-run usage examples in the [`examples/`](examples/) folder!
53
54
  - [Show topology on a map](examples/show_topology_in_map.py) 🗺️
54
- - More coming soon!
55
+ - [Export topology to CSV and JSON](examples/export_csv_json.py) 📄
56
+ - [Export topology and k-shortest paths for FlexNetSim](examples/export_flexnetsim.py) 🔀
55
57
 
56
58
  ---
57
59
 
@@ -0,0 +1,47 @@
1
+ topolib/__init__.py,sha256=iLmy2rOkHS_4KZWMD8BgT7R3tLMKeaTCDVf3B4FyYxM,91
2
+ topolib/analysis/__init__.py,sha256=qvUC9wV_jQNQIlwJXk7LJ-dkTXhH1Ttn0lKWIdwBbrc,52
3
+ topolib/analysis/metrics.py,sha256=2o5PlMVzepDWwSQjzamtKemggqkxh9JuzzCUaeahfok,2555
4
+ topolib/assets/AMRES.json,sha256=PWQLEOOIpQzDelkWg27EUTg331Ewlqm-jIQGMNyIIdo,27082
5
+ topolib/assets/Abilene.json,sha256=5cnPMbjsNDjmpySdQDYQ2yd83zOFvCRjlAnbX1wyzgk,6010
6
+ topolib/assets/Bell_canada.json,sha256=pjsZBZcp6j-IP57P8MOlcBqnfnLkzbintKzgJxcC7ZE,19921
7
+ topolib/assets/Brazil.json,sha256=_4rSY46CKBd6ylpLLigaUuWjLrP83OYiYorg4wChmFU,14876
8
+ topolib/assets/CESNET.json,sha256=i6ebe-cDZJtTCDbbeuBo-dQwb7dhD4SRdc0I0N0Eczo,13739
9
+ topolib/assets/CORONET.json,sha256=dSpBSR-vBdxeG1IPcnjw5YYwpzujKMceBuLghGt3xQQ,42017
10
+ topolib/assets/China.json,sha256=L3co98t0MYzPApUi0Hv9i-QthDPHZQSsGcCvunspsGA,23820
11
+ topolib/assets/DT-14.json,sha256=IyNZIWelc2lW1eOa6nHOH4HRfCIOGZtBdwFUQhiS5is,9924
12
+ topolib/assets/DT-17.json,sha256=LBqGD3e3ad9nSaFlnJnrIWMk1eEVC6uF6zDElFzPUu8,10972
13
+ topolib/assets/DT-50.json,sha256=4Pe6R3eWaiHB_KOWO2Pprm3veHl6ttZA2dPyh_GxEGQ,31869
14
+ topolib/assets/ES-30.json,sha256=gXrrOGNveIlWNvO214FHcGo08pCCs1mElCRHXdvIJGY,20186
15
+ topolib/assets/EURO-16.json,sha256=LEd_oq9nY9XP-5wzrCcmhe3VI0D_iDlaNg1lAjeRHik,9513
16
+ topolib/assets/FR-43.json,sha256=QK4-95ETMw4C98jMzpgkpL8y2vlSkbiS7mN9-9QCEPw,26797
17
+ topolib/assets/FUNET.json,sha256=RtVbWVmJHGO-a8gSqCiGWkuxjfou-Ep1JWV4b9M2qIc,6650
18
+ topolib/assets/GCN-BG.json,sha256=e24fO_IlVUu6x9S2zpSJWBD7S9Obkw39TkHcKGzayDQ,18299
19
+ topolib/assets/GRNET.json,sha256=xJMwR4DGANRBcLdjv_8gWQp3ymuSSCR2Cws9_sAx9eg,36781
20
+ topolib/assets/HyperOne.json,sha256=jP-BT5jmozezD0AgOkwdb6nXyqiiL6TMy6BjjVOKEGE,5264
21
+ topolib/assets/IT-21.json,sha256=GmYsmC8jycG1WYGwRvVJtnrurZQ7uy8LN0Kmb8Zmg6w,13503
22
+ topolib/assets/India.json,sha256=7wiXKgWBIO0THTpV8pNE8TCriV-zfytI2lPKK6Y3Zoc,10839
23
+ topolib/assets/JPN-12.json,sha256=qz4uZAjE4GvLQnlBpKAiC9Zrp197r5hI8029hsRlDEY,6902
24
+ topolib/assets/KOREN.json,sha256=lKW2if-IdGxQsiX6vpysXpYw__3_6OTWeZ9-oD-h5Eg,5951
25
+ topolib/assets/NORDUNet.json,sha256=X934bx4bTyn98ASz8Eb0-UuEBxnR-3vTy14-gFn8Oms,16412
26
+ topolib/assets/NSFNet.json,sha256=LeU7h6H76HXEyIpUhlzuR6cbs6Q61eEgxmyUMaNUeEk,8375
27
+ topolib/assets/PANEURO.json,sha256=Xh_pmTBOwlusDhAUGpPzJz4tSRXbK-FTsN3Dnlbwf48,15969
28
+ topolib/assets/PAVLOV.json,sha256=YRDqlodGj-zqErX1cwk4bX-XuUkgP1CpiOmtlLIBmIk,9816
29
+ topolib/assets/PLN-12.json,sha256=oxKs0MTe-pEqD-kTa_LATWfDRswwAnlEFubeQlXMFRU,7135
30
+ topolib/assets/SANReN.json,sha256=VUe7JFbzmte6ED3lNyfm1cWhefsapeZ4P-zIG6-rZXc,3394
31
+ topolib/assets/SERBIA-MONTENEGRO.json,sha256=83Mk5yNju7B50JolE1uCwy8wQJgsaBzZ71xxhMGYOSc,2897
32
+ topolib/assets/Telefonica-21.json,sha256=Wom5SQn3lLL-z-ESZ3Du_Fz_ZQ2bzP2_bNhzmnmmW_I,13302
33
+ topolib/assets/Turk_Telekom.json,sha256=5yO0cgtJOmh6ulCCIb8g_nDFSmv8Wn52Yt_Oyoc1Y0w,11533
34
+ topolib/assets/UKNet.json,sha256=9BEkRM9YFeMMpih5kyDY34TsOGFzt5KBGsmgWd6KoB0,14210
35
+ topolib/assets/Vega_Telecom.json,sha256=E07ZCvG4exRj1a5DV8lqS3Sdo5tRm_Lc07IzIjP2EW0,17324
36
+ topolib/elements/__init__.py,sha256=ZWSd5uwVtppJtMnZ30zrAdzXhUAYIK62RrUaH9rsWu0,180
37
+ topolib/elements/link.py,sha256=BwjdCR8peh7dDpKunZodlIsjKcfvwjKxyQ3tmp1obb8,3778
38
+ topolib/elements/node.py,sha256=uOnljwA3jcVR4utUfI-om4SIt_QBsEQt8QLW9uvjr3Y,4974
39
+ topolib/topology/__init__.py,sha256=2VRhVm4ZvKBiTDB2T8BDmLZBpwGCVFRF3fvtxxC_d28,86
40
+ topolib/topology/path.py,sha256=oUNwmpBcS6LMMAJIxokROm3MVqr7vRR44M3Fh5ADq_w,2057
41
+ topolib/topology/topology.py,sha256=pRmbn8vaFh35Fi0dtSy-fl_3VNVz6MqW-iqfeh3BvPw,14896
42
+ topolib/visualization/__init__.py,sha256=wv065-KB5uDbTaQIASPVfMMW5sE76Bs-q0oai48vAzk,29
43
+ topolib/visualization/mapview.py,sha256=4iKJMYsH6oFNj9tOcgSKLVRtoYfUuH3XLjShsGwUXcM,2799
44
+ topolib-0.5.0.dist-info/METADATA,sha256=8jZNgjgAyWsX3d63Lxo5bI6T6JDCAmKUbu_PQ2svtXM,4169
45
+ topolib-0.5.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
46
+ topolib-0.5.0.dist-info/licenses/LICENSE,sha256=kbnIP0XU6f2ualiTjEawdlU81IGPBbwc-_GF3N-1e9E,1081
47
+ topolib-0.5.0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- topolib/__init__.py,sha256=iLmy2rOkHS_4KZWMD8BgT7R3tLMKeaTCDVf3B4FyYxM,91
2
- topolib/analysis/__init__.py,sha256=qvUC9wV_jQNQIlwJXk7LJ-dkTXhH1Ttn0lKWIdwBbrc,52
3
- topolib/analysis/metrics.py,sha256=2o5PlMVzepDWwSQjzamtKemggqkxh9JuzzCUaeahfok,2555
4
- topolib/assets/Abilene_IXP.json,sha256=5cnPMbjsNDjmpySdQDYQ2yd83zOFvCRjlAnbX1wyzgk,6010
5
- topolib/assets/China_pop.json,sha256=v-bs5qib8-CB81rvBNNM9ssoelrNGuFrPEyRCht9YpY,22262
6
- topolib/assets/DT-50_pop.json,sha256=hCv1MCvipgdrQ34VT-qXJ68BdATriQ8ZObh0fLPqar4,29719
7
- topolib/elements/__init__.py,sha256=ZWSd5uwVtppJtMnZ30zrAdzXhUAYIK62RrUaH9rsWu0,180
8
- topolib/elements/link.py,sha256=BwjdCR8peh7dDpKunZodlIsjKcfvwjKxyQ3tmp1obb8,3778
9
- topolib/elements/node.py,sha256=uOnljwA3jcVR4utUfI-om4SIt_QBsEQt8QLW9uvjr3Y,4974
10
- topolib/topology/__init__.py,sha256=2VRhVm4ZvKBiTDB2T8BDmLZBpwGCVFRF3fvtxxC_d28,86
11
- topolib/topology/path.py,sha256=oUNwmpBcS6LMMAJIxokROm3MVqr7vRR44M3Fh5ADq_w,2057
12
- topolib/topology/topology.py,sha256=PzPx80TxWMcOwpOCh4fohcWT2YUra-4m04tBjqyMU40,5605
13
- topolib/visualization/__init__.py,sha256=wv065-KB5uDbTaQIASPVfMMW5sE76Bs-q0oai48vAzk,29
14
- topolib/visualization/mapview.py,sha256=4iKJMYsH6oFNj9tOcgSKLVRtoYfUuH3XLjShsGwUXcM,2799
15
- topolib-0.4.2.dist-info/METADATA,sha256=O2V7bL8xtAJOhNVmbLX0mHLj1ic5ZZu_3bbnFFbEzAw,3993
16
- topolib-0.4.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
17
- topolib-0.4.2.dist-info/licenses/LICENSE,sha256=kbnIP0XU6f2ualiTjEawdlU81IGPBbwc-_GF3N-1e9E,1081
18
- topolib-0.4.2.dist-info/RECORD,,
File without changes