linting ... 42/12042/1
authorMartin Skorupski <martin.skorupski@highstreet-technologies.com>
Sun, 12 Nov 2023 17:11:41 +0000 (18:11 +0100)
committerMartin Skorupski <martin.skorupski@highstreet-technologies.com>
Sun, 12 Nov 2023 17:11:55 +0000 (18:11 +0100)
- lint py files

Issue-ID: OAM-388
Change-Id: I797cf34049e4765971ee67017ee06f78fedebddf
Signed-off-by: Martin Skorupski <martin.skorupski@highstreet-technologies.com>
24 files changed:
code/network-generator/network_generation/base.py
code/network-generator/network_generation/cli.py
code/network-generator/network_generation/model/python/countries.py
code/network-generator/network_generation/model/python/cube.py
code/network-generator/network_generation/model/python/geo_location.py
code/network-generator/network_generation/model/python/hexagon.py
code/network-generator/network_generation/model/python/nr_cell_du.py
code/network-generator/network_generation/model/python/o_ran_cloud_du.py
code/network-generator/network_generation/model/python/o_ran_cu.py
code/network-generator/network_generation/model/python/o_ran_du.py
code/network-generator/network_generation/model/python/o_ran_near_rt_ric.py
code/network-generator/network_generation/model/python/o_ran_network.py
code/network-generator/network_generation/model/python/o_ran_node.py
code/network-generator/network_generation/model/python/o_ran_object.py
code/network-generator/network_generation/model/python/o_ran_ru.py
code/network-generator/network_generation/model/python/o_ran_smo.py
code/network-generator/network_generation/model/python/o_ran_spiral_radius_profile.py
code/network-generator/network_generation/model/python/o_ran_termination_point.py
code/network-generator/network_generation/model/python/point.py
code/network-generator/network_generation/model/python/top.py
code/network-generator/network_generation/model/python/tower.py
code/network-generator/network_generation/model/python/type_definitions.py
code/network-generator/network_generation/parameter_validator.py
code/network-generator/network_generation/view/network_viewer.py

index 7fe3964..bf1dab0 100644 (file)
@@ -35,7 +35,7 @@ class NetworkGenerator:
     __configuration: dict = {}
 
     # constructor
     __configuration: dict = {}
 
     # constructor
-    def __init__(self, configuration: dict):
+    def __init__(self, configuration: dict) -> None:
         self.__configuration = configuration
 
     # getters
         self.__configuration = configuration
 
     # getters
index ada37e1..ad4188a 100644 (file)
 
 # inspired by https://github.com/rochacbruno/python-project-template
 
 
 # inspired by https://github.com/rochacbruno/python-project-template
 
-"""CLI interface for network_generation project.
-
-Be creative! do whatever you want!
-
-- Install click or typer and create a CLI app
-- Use builtin argparse
-- Start a web application
-- Import things from your .base module
-"""
-
-
-"""
-Module as entry point to generate an ietf topology json
-"""
 import os
 import sys
 
 from network_generation.base import NetworkGenerator
 import os
 import sys
 
 from network_generation.base import NetworkGenerator
+from network_generation.model.python.o_ran_network import ORanNetwork
 from network_generation.parameter_validator import ParameterValidator
 from network_generation.view.network_viewer import NetworkViewer
 
 from network_generation.parameter_validator import ParameterValidator
 from network_generation.view.network_viewer import NetworkViewer
 
+"""
+CLI interface for network_generation project.
+Module as entry point to generate an ietf topology json
+"""
+
 
 
-def main():  # pragma: no cover
+def main() -> None:  # pragma: no cover
     """
     The main function executes on commands:
     `python -m network_generation`.
     """
     The main function executes on commands:
     `python -m network_generation`.
@@ -45,10 +37,12 @@ def main():  # pragma: no cover
     validator: ParameterValidator = ParameterValidator(sys.argv)
 
     if validator.is_valid():
     validator: ParameterValidator = ParameterValidator(sys.argv)
 
     if validator.is_valid():
-        configuration = validator.configuration()
-        generator = NetworkGenerator(configuration["network"])
-        network = generator.generate()
-        viewer = NetworkViewer(network)
+        configuration: dict = validator.configuration()
+        generator: NetworkGenerator = NetworkGenerator(
+            configuration["network"]
+        )
+        network: ORanNetwork = generator.generate()
+        viewer: NetworkViewer = NetworkViewer(network)
 
         output_folder: str = configuration["output-folder"]
         # If folder doesn't exist, then create it.
 
         output_folder: str = configuration["output-folder"]
         # If folder doesn't exist, then create it.
@@ -56,20 +50,21 @@ def main():  # pragma: no cover
             os.makedirs(output_folder)
 
         name: str = configuration["network"]["name"]
             os.makedirs(output_folder)
 
         name: str = configuration["network"]["name"]
+        filename: str = ""
 
         # topology json
         if configuration["generation-tasks"]["topology"] is True:
 
         # topology json
         if configuration["generation-tasks"]["topology"] is True:
-            filename: str = output_folder + "/" + name + "-operational.json"
+            filename = output_folder + "/" + name + "-operational.json"
             viewer.json().save(filename)
 
         # svg xml
         if configuration["generation-tasks"]["svg"] is True:
             viewer.json().save(filename)
 
         # svg xml
         if configuration["generation-tasks"]["svg"] is True:
-            filename: str = output_folder + "/" + name + ".svg"
+            filename = output_folder + "/" + name + ".svg"
             viewer.svg(filename)
 
         # kml xml
         if configuration["generation-tasks"]["kml"] is True:
             viewer.svg(filename)
 
         # kml xml
         if configuration["generation-tasks"]["kml"] is True:
-            filename: str = output_folder + "/" + name + ".kml"
+            filename = output_folder + "/" + name + ".kml"
             viewer.kml(filename)
 
     else:
             viewer.kml(filename)
 
     else:
index 44e4eab..0f08909 100644 (file)
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A TypeDefinition as enum for countries
 
 """
 A TypeDefinition as enum for countries
index 0d4e2a3..2c5ef06 100644 (file)
@@ -14,7 +14,7 @@
 #
 # inspired by http://www.redblobgames.com/grids/hexagons/
 
 #
 # inspired by http://www.redblobgames.com/grids/hexagons/
 
-#!/usr/bin/python
+# !/usr/bin/python
 from network_generation.model.python.hexagon import Hex
 
 
 from network_generation.model.python.hexagon import Hex
 
 
@@ -35,7 +35,8 @@ class Cube:
     def direction(direction: int) -> Hex:
         if direction < 0 or direction > 5:
             raise ValueError(
     def direction(direction: int) -> Hex:
         if direction < 0 or direction > 5:
             raise ValueError(
-                "Invalid direction. The direction value must be in the range of [0..5]."
+                "Invalid direction. The direction value must be"
+                + " in the range of [0..5]."
             )
         return Cube.direction_vectors()[direction]
 
             )
         return Cube.direction_vectors()[direction]
 
@@ -55,7 +56,8 @@ class Cube:
     def ring(center: Hex, radius: int) -> list[Hex]:
         if not (radius > 0):
             raise ValueError(
     def ring(center: Hex, radius: int) -> list[Hex]:
         if not (radius > 0):
             raise ValueError(
-                "Invalid radius. The radius around the hex center must be greater than 0 rings."
+                "Invalid radius. The radius around the hex center must"
+                + " be greater than 0 rings."
             )
         results: list[Hex] = []
         hex: Hex = Cube.add(center, Cube.scale(Cube.direction(4), radius))
             )
         results: list[Hex] = []
         hex: Hex = Cube.add(center, Cube.scale(Cube.direction(4), radius))
index 3b6793a..64449f8 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A collection of TypeDefinitions for a geographical location
 """
 import math
 
 """
 A collection of TypeDefinitions for a geographical location
 """
 import math
+from typing import Any, TypedDict, cast
+
+from typing_extensions import Required
 
 from network_generation.model.python.point import Point
 
 
 
 from network_generation.model.python.point import Point
 
 
-class IGeoLocationData:
-    def __init__(
-        self, latitude: float, longitude: float, aboveMeanSeaLevel: float
-    ):
-        self.latitude = latitude
-        self.longitude = longitude
-        self.aboveMeanSeaLevel = aboveMeanSeaLevel
+class IGeoLocation(TypedDict):
+    latitude: Required[float]
+    longitude: Required[float]
+    aboveMeanSeaLevel: Required[float]
 
 
 
 
-class IGeoLocation:
-    def __init__(
-        self,
-        latitude: float = 0,
-        longitude: float = 0,
-        aboveMeanSeaLevel: float = 0,
-    ):
-        self.latitude = latitude
-        self.longitude = longitude
-        self.aboveMeanSeaLevel = aboveMeanSeaLevel
+default_value: IGeoLocation = {
+    "latitude": 0,
+    "longitude": 0,
+    "aboveMeanSeaLevel": 0,
+}
 
 
-    def __str__(self) -> str:
-        return f"lat : {self.latitude} : lon : {self.longitude} : amsl : {self.aboveMeanSeaLevel}"
 
 
+class GeoLocation:
+    @staticmethod
+    def default() -> dict[str, Any]:
+        return cast(dict[str, Any], default_value)
 
 
-class GeoLocation(IGeoLocation):
     _equatorialRadius = 6378137  # meters
     _polarRadius = 6356752  # meters
 
     _equatorialRadius = 6378137  # meters
     _polarRadius = 6356752  # meters
 
-    def __init__(self, geoLocation: IGeoLocationData = None):
-        super().__init__(
-            geoLocation["latitude"] if geoLocation else 0,
-            geoLocation["longitude"] if geoLocation else 0,
-            geoLocation["aboveMeanSeaLevel"] if geoLocation else 0,
-        )
+    def __init__(self, data: IGeoLocation = default_value) -> None:
+        self.latitude = data["latitude"]
+        self.longitude = data["longitude"]
+        self.aboveMeanSeaLevel = data["aboveMeanSeaLevel"]
 
     @property
     def equatorialRadius(self) -> int:
 
     @property
     def equatorialRadius(self) -> int:
@@ -65,19 +59,40 @@ class GeoLocation(IGeoLocation):
     def polarRadius(self) -> int:
         return GeoLocation._polarRadius
 
     def polarRadius(self) -> int:
         return GeoLocation._polarRadius
 
-    def set_latitude(self, value: float):
+    @property
+    def latitude(self) -> float:
+        return self._latitude
+
+    @latitude.setter
+    def latitude(self, value: float) -> None:
         if not (-90 <= value <= 90):
         if not (-90 <= value <= 90):
+            msg: str = "Invalid latitude. Latitude must be between -90 and 90."
+            raise ValueError(msg)
+        self._latitude = value
+
+    @property
+    def longitude(self) -> float:
+        return self._longitude
+
+    @longitude.setter
+    def longitude(self, value: float) -> None:
+        if not (-180 <= value <= 180):
             raise ValueError(
             raise ValueError(
-                "Invalid latitude. Latitude must be between -90 and 90."
+                "Invalid longitude. Longitude must be between -180 and 180."
             )
             )
-        self.latitude = value
+        self._longitude = value
+
+    @property
+    def aboveMeanSeaLevel(self) -> float:
+        return self._aboveMeanSeaLevel
 
 
-    def set_longitude(self, value: float):
+    @aboveMeanSeaLevel.setter
+    def aboveMeanSeaLevel(self, value: float) -> None:
         if not (-180 <= value <= 180):
             raise ValueError(
                 "Invalid longitude. Longitude must be between -180 and 180."
             )
         if not (-180 <= value <= 180):
             raise ValueError(
                 "Invalid longitude. Longitude must be between -180 and 180."
             )
-        self.longitude = value
+        self._aboveMeanSeaLevel = value
 
     def json(self) -> dict[str, float]:
         return {
 
     def json(self) -> dict[str, float]:
         return {
@@ -89,22 +104,21 @@ class GeoLocation(IGeoLocation):
     def __str__(self) -> str:
         return str(self.json())
 
     def __str__(self) -> str:
         return str(self.json())
 
-    def point_to_geo_location(self, point: Point):
+    def point_to_geo_location(self, point: Point) -> Any:
         """
         """
-        A static function which converts a point in pixels into a geographical location
-        when the self is represented as Point(0,0)
+        A static function which converts a point in pixels into a geographical
+        location when the self is represented as Point(0,0)
         @param point : The point to be converted
         returns The converted GeoLocation object.
         """
         @param point : The point to be converted
         returns The converted GeoLocation object.
         """
-        equatorialRadius = 6378137  # meters
-        new_lat = self.latitude + (point.y / equatorialRadius) * (
+        new_lat = self.latitude + (point.y / self.equatorialRadius) * (
             180 / math.pi
         )
             180 / math.pi
         )
-        new_lon = self.longitude + (point.x / equatorialRadius) * (
+        new_lon = self.longitude + (point.x / self.equatorialRadius) * (
             180 / math.pi
         ) / math.cos(self.latitude * math.pi / 180)
 
             180 / math.pi
         ) / math.cos(self.latitude * math.pi / 180)
 
-        geo_location: IGeoLocationData = {
+        geo_location: IGeoLocation = {
             "longitude": new_lon,
             "latitude": new_lat,
             "aboveMeanSeaLevel": self.aboveMeanSeaLevel,
             "longitude": new_lon,
             "latitude": new_lat,
             "aboveMeanSeaLevel": self.aboveMeanSeaLevel,
index 5a81c23..555c601 100644 (file)
@@ -14,7 +14,7 @@
 #
 # inspired by http://www.redblobgames.com/grids/hexagons/
 
 #
 # inspired by http://www.redblobgames.com/grids/hexagons/
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 from __future__ import division, print_function
 
 
 from __future__ import division, print_function
 
@@ -27,7 +27,7 @@ from network_generation.model.python.point import Point
 
 
 class Hex:
 
 
 class Hex:
-    def __init__(self, q: int, r: int, s: int):
+    def __init__(self, q: float, r: float, s: float) -> None:
         if round(q + r + s) != 0:
             raise ValueError("The sum of q, r, and s must be 0.")
         self.q = q
         if round(q + r + s) != 0:
             raise ValueError("The sum of q, r, and s must be 0.")
         self.q = q
@@ -50,11 +50,11 @@ def hex_scale(a: Hex, k: int) -> Hex:
     return Hex(a.q * k, a.r * k, a.s * k)
 
 
     return Hex(a.q * k, a.r * k, a.s * k)
 
 
-def hex_rotate_left(a) -> Hex:
+def hex_rotate_left(a: Hex) -> Hex:
     return Hex(-a.s, -a.q, -a.r)
 
 
     return Hex(-a.s, -a.q, -a.r)
 
 
-def hex_rotate_right(a) -> Hex:
+def hex_rotate_right(a: Hex) -> Hex:
     return Hex(-a.r, -a.s, -a.q)
 
 
     return Hex(-a.r, -a.s, -a.q)
 
 
@@ -90,18 +90,18 @@ def hex_diagonal_neighbor(hex: Hex, direction: int) -> Hex:
     return hex_add(hex, hex_diagonals[direction])
 
 
     return hex_add(hex, hex_diagonals[direction])
 
 
-def hex_length(hex: Hex) -> int:
+def hex_length(hex: Hex) -> float:
     return (abs(hex.q) + abs(hex.r) + abs(hex.s)) // 2
 
 
     return (abs(hex.q) + abs(hex.r) + abs(hex.s)) // 2
 
 
-def hex_distance(a: Hex, b: Hex) -> int:
+def hex_distance(a: Hex, b: Hex) -> float:
     return hex_length(hex_subtract(a, b))
 
 
 def hex_round(hex: Hex) -> Hex:
     return hex_length(hex_subtract(a, b))
 
 
 def hex_round(hex: Hex) -> Hex:
-    qi = int(round(hex.q))
-    ri = int(round(hex.r))
-    si = int(round(hex.s))
+    qi = round(hex.q)
+    ri = round(hex.r)
+    si = round(hex.s)
     q_diff = abs(qi - hex.q)
     r_diff = abs(ri - hex.r)
     s_diff = abs(si - hex.s)
     q_diff = abs(qi - hex.q)
     r_diff = abs(ri - hex.r)
     s_diff = abs(si - hex.s)
@@ -115,21 +115,21 @@ def hex_round(hex: Hex) -> Hex:
     return Hex(qi, ri, si)
 
 
     return Hex(qi, ri, si)
 
 
-def hex_lerp(a: Hex, b: Hex, t: int) -> Hex:  # linearly interpolation
+def hex_lerp(a: Hex, b: Hex, t: float) -> Hex:  # linearly interpolation
     return Hex(
     return Hex(
-        a.q * (1.0 - t) + b.q * t,
-        a.r * (1.0 - t) + b.r * t,
-        a.s * (1.0 - t) + b.s * t,
+        a.q * (1 - t) + b.q * t,
+        a.r * (1 - t) + b.r * t,
+        a.s * (1 - t) + b.s * t,
     )
 
 
     )
 
 
-def hex_linedraw(a: Hex, b: Hex) -> list[hex]:
-    N = hex_distance(a, b)
-    a_nudge = Hex(a.q + 1e-06, a.r + 1e-06, a.s - 2e-06)
-    b_nudge = Hex(b.q + 1e-06, b.r + 1e-06, b.s - 2e-06)
-    results: list[hex] = []
-    step = 1.0 / max(N, 1)
-    for i in range(0, N + 1):
+def hex_linedraw(a: Hex, b: Hex) -> list[Hex]:
+    N: float = hex_distance(a, b)
+    a_nudge: Hex = Hex(a.q + 1e-06, a.r + 1e-06, a.s - 2e-06)
+    b_nudge: Hex = Hex(b.q + 1e-06, b.r + 1e-06, b.s - 2e-06)
+    results: list[Hex] = []
+    step: float = 1 / max(N, 1)
+    for i in range(0, int(N) + 1):
         results.append(hex_round(hex_lerp(a_nudge, b_nudge, step * i)))
     return results
 
         results.append(hex_round(hex_lerp(a_nudge, b_nudge, step * i)))
     return results
 
@@ -140,33 +140,36 @@ EVEN: int = 1
 ODD: int = -1
 
 
 ODD: int = -1
 
 
-def qoffset_from_cube(offset: int, hex: Hex) -> OffsetCoord:
+def qoffset_from_cube(offset: float, hex: Hex) -> OffsetCoord:
     col = hex.q
     col = hex.q
-    row = hex.r + (hex.q + offset * (hex.q & 1)) // 2
+    row = hex.r + (hex.q + offset * (int(hex.q) & 1)) // 2
     if offset != EVEN and offset != ODD:
         raise ValueError("offset must be EVEN (+1) or ODD (-1)")
     return OffsetCoord(col, row)
 
 
     if offset != EVEN and offset != ODD:
         raise ValueError("offset must be EVEN (+1) or ODD (-1)")
     return OffsetCoord(col, row)
 
 
-def qoffset_to_cube(offset: int, hex: Hex) -> Hex:
-    q = hex.col
-    r = hex.row - (hex.col + offset * (hex.col & 1)) // 2
+def qoffset_to_cube(offset: int, offsetCoord: OffsetCoord) -> Hex:
+    q = offsetCoord.col
+    r = (
+        offsetCoord.row
+        - (offsetCoord.col + offset * (offsetCoord.col & 1)) // 2
+    )
     s = -q - r
     if offset != EVEN and offset != ODD:
         raise ValueError("offset must be EVEN (+1) or ODD (-1)")
     return Hex(q, r, s)
 
 
     s = -q - r
     if offset != EVEN and offset != ODD:
         raise ValueError("offset must be EVEN (+1) or ODD (-1)")
     return Hex(q, r, s)
 
 
-def roffset_from_cube(offset: int, hex: Hex) -> OffsetCoord:
-    col = hex.q + (hex.r + offset * (hex.r & 1)) // 2
+def roffset_from_cube(offset: float, hex: Hex) -> OffsetCoord:
+    col = hex.q + (hex.r + offset * (int(hex.r) & 1)) // 2
     row = hex.r
     if offset != EVEN and offset != ODD:
         raise ValueError("offset must be EVEN (+1) or ODD (-1)")
     return OffsetCoord(col, row)
 
 
     row = hex.r
     if offset != EVEN and offset != ODD:
         raise ValueError("offset must be EVEN (+1) or ODD (-1)")
     return OffsetCoord(col, row)
 
 
-def roffset_to_cube(offset: int, hex: Hex) -> Hex:
-    q = hex.col - (hex.row + offset * (hex.row & 1)) // 2
+def roffset_to_cube(offset: float, hex: OffsetCoord) -> Hex:
+    q = hex.col - (hex.row + offset * (int(hex.row) & 1)) // 2
     r = hex.row
     s = -q - r
     if offset != EVEN and offset != ODD:
     r = hex.row
     s = -q - r
     if offset != EVEN and offset != ODD:
@@ -177,15 +180,15 @@ def roffset_to_cube(offset: int, hex: Hex) -> Hex:
 DoubledCoord = collections.namedtuple("DoubledCoord", ["col", "row"])
 
 
 DoubledCoord = collections.namedtuple("DoubledCoord", ["col", "row"])
 
 
-def qdoubled_from_cube(hex: Hex):
+def qdoubled_from_cube(hex: Hex) -> DoubledCoord:
     col = hex.q
     row = 2 * hex.r + hex.q
     return DoubledCoord(col, row)
 
 
     col = hex.q
     row = 2 * hex.r + hex.q
     return DoubledCoord(col, row)
 
 
-def qdoubled_to_cube(hex: Hex) -> Hex:
-    q = hex.col
-    r = (hex.row - hex.col) // 2
+def qdoubled_to_cube(doubledCoord: DoubledCoord) -> Hex:
+    q = doubledCoord.col
+    r = (doubledCoord.row - doubledCoord.col) // 2
     s = -q - r
     return Hex(q, r, s)
 
     s = -q - r
     return Hex(q, r, s)
 
@@ -196,9 +199,9 @@ def rdoubled_from_cube(hex: Hex) -> DoubledCoord:
     return DoubledCoord(col, row)
 
 
     return DoubledCoord(col, row)
 
 
-def rdoubled_to_cube(hex: Hex):
-    q = (hex.col - hex.row) // 2
-    r = hex.row
+def rdoubled_to_cube(doubledCoord: DoubledCoord) -> Hex:
+    q = (doubledCoord.col - doubledCoord.row) // 2
+    r = doubledCoord.row
     s = -q - r
     return Hex(q, r, s)
 
     s = -q - r
     return Hex(q, r, s)
 
@@ -279,284 +282,4 @@ def hex_to_geo_location(
     layout: Layout, hex: Hex, reference: GeoLocation
 ) -> GeoLocation:
     hexPoint: Point = hex_to_pixel(layout, hex)
     layout: Layout, hex: Hex, reference: GeoLocation
 ) -> GeoLocation:
     hexPoint: Point = hex_to_pixel(layout, hex)
-    return GeoLocation(reference).point_to_geo_location(hexPoint)
-
-
-# Tests
-
-
-def complain(name):
-    print("FAIL {0}".format(name))
-
-
-def equal_hex(name, a, b):
-    if not (a.q == b.q and a.s == b.s and a.r == b.r):
-        complain(name)
-
-
-def equal_offsetcoord(name, a, b):
-    if not (a.col == b.col and a.row == b.row):
-        complain(name)
-
-
-def equal_doubledcoord(name, a, b):
-    if not (a.col == b.col and a.row == b.row):
-        complain(name)
-
-
-def equal_int(name, a, b):
-    if not (a == b):
-        complain(name)
-
-
-def equal_hex_array(name, a, b):
-    equal_int(name, len(a), len(b))
-    for i in range(0, len(a)):
-        equal_hex(name, a[i], b[i])
-
-
-def test_hex_arithmetic():
-    equal_hex("hex_add", Hex(4, -10, 6), hex_add(Hex(1, -3, 2), Hex(3, -7, 4)))
-    equal_hex(
-        "hex_subtract",
-        Hex(-2, 4, -2),
-        hex_subtract(Hex(1, -3, 2), Hex(3, -7, 4)),
-    )
-
-
-def test_hex_direction():
-    equal_hex("hex_direction", Hex(0, -1, 1), hex_direction(2))
-
-
-def test_hex_neighbor():
-    equal_hex("hex_neighbor", Hex(1, -3, 2), hex_neighbor(Hex(1, -2, 1), 2))
-
-
-def test_hex_diagonal():
-    equal_hex(
-        "hex_diagonal", Hex(-1, -1, 2), hex_diagonal_neighbor(Hex(1, -2, 1), 3)
-    )
-
-
-def test_hex_distance():
-    equal_int("hex_distance", 7, hex_distance(Hex(3, -7, 4), Hex(0, 0, 0)))
-
-
-def test_hex_rotate_right():
-    equal_hex(
-        "hex_rotate_right", hex_rotate_right(Hex(1, -3, 2)), Hex(3, -2, -1)
-    )
-
-
-def test_hex_rotate_left():
-    equal_hex(
-        "hex_rotate_left", hex_rotate_left(Hex(1, -3, 2)), Hex(-2, -1, 3)
-    )
-
-
-def test_hex_round():
-    a = Hex(0.0, 0.0, 0.0)
-    b = Hex(1.0, -1.0, 0.0)
-    c = Hex(0.0, -1.0, 1.0)
-    equal_hex(
-        "hex_round 1",
-        Hex(5, -10, 5),
-        hex_round(hex_lerp(Hex(0.0, 0.0, 0.0), Hex(10.0, -20.0, 10.0), 0.5)),
-    )
-    equal_hex("hex_round 2", hex_round(a), hex_round(hex_lerp(a, b, 0.499)))
-    equal_hex("hex_round 3", hex_round(b), hex_round(hex_lerp(a, b, 0.501)))
-    equal_hex(
-        "hex_round 4",
-        hex_round(a),
-        hex_round(
-            Hex(
-                a.q * 0.4 + b.q * 0.3 + c.q * 0.3,
-                a.r * 0.4 + b.r * 0.3 + c.r * 0.3,
-                a.s * 0.4 + b.s * 0.3 + c.s * 0.3,
-            )
-        ),
-    )
-    equal_hex(
-        "hex_round 5",
-        hex_round(c),
-        hex_round(
-            Hex(
-                a.q * 0.3 + b.q * 0.3 + c.q * 0.4,
-                a.r * 0.3 + b.r * 0.3 + c.r * 0.4,
-                a.s * 0.3 + b.s * 0.3 + c.s * 0.4,
-            )
-        ),
-    )
-
-
-def test_hex_linedraw():
-    equal_hex_array(
-        "hex_linedraw",
-        [
-            Hex(0, 0, 0),
-            Hex(0, -1, 1),
-            Hex(0, -2, 2),
-            Hex(1, -3, 2),
-            Hex(1, -4, 3),
-            Hex(1, -5, 4),
-        ],
-        hex_linedraw(Hex(0, 0, 0), Hex(1, -5, 4)),
-    )
-
-
-def test_layout():
-    h = Hex(3, 4, -7)
-    flat = Layout(layout_flat, Point(10.0, 15.0), Point(35.0, 71.0))
-    equal_hex(
-        "layout", h, hex_round(pixel_to_hex(flat, hex_to_pixel(flat, h)))
-    )
-    pointy = Layout(layout_pointy, Point(10.0, 15.0), Point(35.0, 71.0))
-    equal_hex(
-        "layout", h, hex_round(pixel_to_hex(pointy, hex_to_pixel(pointy, h)))
-    )
-
-
-def test_offset_roundtrip():
-    a = Hex(3, 4, -7)
-    b = OffsetCoord(1, -3)
-    equal_hex(
-        "conversion_roundtrip even-q",
-        a,
-        qoffset_to_cube(EVEN, qoffset_from_cube(EVEN, a)),
-    )
-    equal_offsetcoord(
-        "conversion_roundtrip even-q",
-        b,
-        qoffset_from_cube(EVEN, qoffset_to_cube(EVEN, b)),
-    )
-    equal_hex(
-        "conversion_roundtrip odd-q",
-        a,
-        qoffset_to_cube(ODD, qoffset_from_cube(ODD, a)),
-    )
-    equal_offsetcoord(
-        "conversion_roundtrip odd-q",
-        b,
-        qoffset_from_cube(ODD, qoffset_to_cube(ODD, b)),
-    )
-    equal_hex(
-        "conversion_roundtrip even-r",
-        a,
-        roffset_to_cube(EVEN, roffset_from_cube(EVEN, a)),
-    )
-    equal_offsetcoord(
-        "conversion_roundtrip even-r",
-        b,
-        roffset_from_cube(EVEN, roffset_to_cube(EVEN, b)),
-    )
-    equal_hex(
-        "conversion_roundtrip odd-r",
-        a,
-        roffset_to_cube(ODD, roffset_from_cube(ODD, a)),
-    )
-    equal_offsetcoord(
-        "conversion_roundtrip odd-r",
-        b,
-        roffset_from_cube(ODD, roffset_to_cube(ODD, b)),
-    )
-
-
-def test_offset_from_cube():
-    equal_offsetcoord(
-        "offset_from_cube even-q",
-        OffsetCoord(1, 3),
-        qoffset_from_cube(EVEN, Hex(1, 2, -3)),
-    )
-    equal_offsetcoord(
-        "offset_from_cube odd-q",
-        OffsetCoord(1, 2),
-        qoffset_from_cube(ODD, Hex(1, 2, -3)),
-    )
-
-
-def test_offset_to_cube():
-    equal_hex(
-        "offset_to_cube even-",
-        Hex(1, 2, -3),
-        qoffset_to_cube(EVEN, OffsetCoord(1, 3)),
-    )
-    equal_hex(
-        "offset_to_cube odd-q",
-        Hex(1, 2, -3),
-        qoffset_to_cube(ODD, OffsetCoord(1, 2)),
-    )
-
-
-def test_doubled_roundtrip():
-    a = Hex(3, 4, -7)
-    b = DoubledCoord(1, -3)
-    equal_hex(
-        "conversion_roundtrip doubled-q",
-        a,
-        qdoubled_to_cube(qdoubled_from_cube(a)),
-    )
-    equal_doubledcoord(
-        "conversion_roundtrip doubled-q",
-        b,
-        qdoubled_from_cube(qdoubled_to_cube(b)),
-    )
-    equal_hex(
-        "conversion_roundtrip doubled-r",
-        a,
-        rdoubled_to_cube(rdoubled_from_cube(a)),
-    )
-    equal_doubledcoord(
-        "conversion_roundtrip doubled-r",
-        b,
-        rdoubled_from_cube(rdoubled_to_cube(b)),
-    )
-
-
-def test_doubled_from_cube():
-    equal_doubledcoord(
-        "doubled_from_cube doubled-q",
-        DoubledCoord(1, 5),
-        qdoubled_from_cube(Hex(1, 2, -3)),
-    )
-    equal_doubledcoord(
-        "doubled_from_cube doubled-r",
-        DoubledCoord(4, 2),
-        rdoubled_from_cube(Hex(1, 2, -3)),
-    )
-
-
-def test_doubled_to_cube():
-    equal_hex(
-        "doubled_to_cube doubled-q",
-        Hex(1, 2, -3),
-        qdoubled_to_cube(DoubledCoord(1, 5)),
-    )
-    equal_hex(
-        "doubled_to_cube doubled-r",
-        Hex(1, 2, -3),
-        rdoubled_to_cube(DoubledCoord(4, 2)),
-    )
-
-
-def test_all():
-    test_hex_arithmetic()
-    test_hex_direction()
-    test_hex_neighbor()
-    test_hex_diagonal()
-    test_hex_distance()
-    test_hex_rotate_right()
-    test_hex_rotate_left()
-    test_hex_round()
-    test_hex_linedraw()
-    test_layout()
-    test_offset_roundtrip()
-    test_offset_from_cube()
-    test_offset_to_cube()
-    test_doubled_roundtrip()
-    test_doubled_from_cube()
-    test_doubled_to_cube()
-    print("test finished")
-
-
-if __name__ == "__main__":
-    test_all()
+    return reference.point_to_geo_location(hexPoint)
index a0fb6e8..40fa66b 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A Class representing a 3GPP new radio cell du (NrCellDu)
 """
 import xml.etree.ElementTree as ET
 
 """
 A Class representing a 3GPP new radio cell du (NrCellDu)
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
-from network_generation.model.python.geo_location import GeoLocation
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.geo_location import (
+    GeoLocation,
+    IGeoLocation,
+)
+from network_generation.model.python.o_ran_node import IORanNode, ORanNode
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
@@ -31,42 +33,54 @@ from network_generation.model.python.point import Point
 
 
 # Define the "INrCellDu" interface
 
 
 # Define the "INrCellDu" interface
-class INrCellDu(IORanObject):
-    def __init__(self, cell_angel: int, azimuth: int, **kwargs):
-        super().__init__(**kwargs)
-        self._cell_angle = cell_angel
-        self._azimuth = azimuth
+class INrCellDu(IORanNode):
+    cell_angle: int
+    azimuth: int
+
+
+default_value: INrCellDu = cast(
+    INrCellDu,
+    {
+        **ORanNode.default(),
+        **{"cellAngle": 120, "azimuth": 120},
+    },
+)
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class NrCellDu(ORanNode, INrCellDu):
-    def __init__(self, cell_data: INrCellDu = None, **kwargs):
-        super().__init__(cell_data, **kwargs)
-        self._cell_angle = (
-            cell_data["cellAngle"]
-            if cell_data and "cellAngle" in cell_data
-            else 120
-        )
-        self._azimuth = (
-            cell_data["azimuth"] if cell_data and "azimuth" in cell_data else 0
-        )
+class NrCellDu(ORanNode):
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        cell_data: INrCellDu = self._to_cell_data(data)
+        super().__init__(cast(dict[str, Any], cell_data), **kwargs)
+        self._cell_angle: int = int(str(cell_data["cellAngle"]))
+        self._azimuth: int = int(str(cell_data["azimuth"]))
+
+    def _to_cell_data(self, data: dict[str, Any]) -> INrCellDu:
+        result: INrCellDu = default_value
+        for key, key_type in INrCellDu.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
 
 
-    @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         result.append(
             ORanTerminationPoint({"id": self.name, "name": self.name})
         )
         return result
 
         result.append(
             ORanTerminationPoint({"id": self.name, "name": self.name})
         )
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
         # a cell is not a node it is a Termination Point
         # a cell is not a node it is a Termination Point
-        result: list[dict[str, dict]] = []  # super().to_topology_nodes()
+        result: list[dict[str, Any]] = []  # super().to_topology_nodes()
         return result
 
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
+    def to_topology_links(self) -> list[dict[str, Any]]:
         # as a cell is not a node, it does not have links
         # as a cell is not a node, it does not have links
-        result: list[dict[str, dict]] = []  # super().to_topology_links()
+        result: list[dict[str, Any]] = []  # super().to_topology_links()
         return result
 
     def toKml(self) -> ET.Element:
         return result
 
     def toKml(self) -> ET.Element:
@@ -84,15 +98,16 @@ class NrCellDu(ORanNode, INrCellDu):
         points: list[Point] = Hexagon.polygon_corners(
             self.layout, self.position
         )
         points: list[Point] = Hexagon.polygon_corners(
             self.layout, self.position
         )
-        method = GeoLocation(
-            self.parent.parent.parent.parent.parent.parent.geoLocation
-        ).point_to_geo_location
+        method = (
+            self.parent.parent.parent.parent.parent.parent
+            .geo_location.point_to_geo_location
+        )
         geo_locations: list[GeoLocation] = list(map(method, points))
         text: list[str] = []
 
         index: int = 1 + int(self._azimuth / self._cell_angle)
         geo_locations: list[GeoLocation] = list(map(method, points))
         text: list[str] = []
 
         index: int = 1 + int(self._azimuth / self._cell_angle)
-        network_center: GeoLocation = GeoLocation(
-            self.parent.parent.parent.parent.parent.parent.geoLocation
+        network_center: GeoLocation = (
+            self.parent.parent.parent.parent.parent.parent.geo_location
         )
 
         intersect1: Point = Point(
         )
 
         intersect1: Point = Point(
@@ -115,7 +130,8 @@ class NrCellDu(ORanNode, INrCellDu):
             network_center.point_to_geo_location(intersect2)
         )
 
             network_center.point_to_geo_location(intersect2)
         )
 
-        tower: GeoLocation = GeoLocation(self.geoLocation)
+        tower: GeoLocation = GeoLocation(cast(IGeoLocation, self.geo_location))
+        # TODO: Why a cast is required
 
         cell_polygon: list[GeoLocation] = []
         cell_polygon.append(tower)
 
         cell_polygon: list[GeoLocation] = []
         cell_polygon.append(tower)
@@ -126,13 +142,17 @@ class NrCellDu(ORanNode, INrCellDu):
         # close polygon
         cell_polygon.append(tower)
 
         # close polygon
         cell_polygon.append(tower)
 
-        for geo_location in cell_polygon:
-            text.append(
-                f"{'%.6f' % geo_location.longitude},{'%.6f' % geo_location.latitude},{'%.6f' % geo_location.aboveMeanSeaLevel}"
-            )
+        for gl in cell_polygon:
+            index += 1
+            strs: list[str] = [
+                str("%.6f" % float(gl.longitude)),
+                str("%.6f" % float(gl.latitude)),
+                str("%.6f" % float(gl.aboveMeanSeaLevel)),
+            ]
+            text.append(",".join(strs))
         coordinates.text = " ".join(text)
 
         return placemark
 
         coordinates.text = " ".join(text)
 
         return placemark
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index 0c5b782..b97f97e 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 
 """
-A Class representing an O-RAN O-Cloud resource pool for O-RAN distributed units (ORanDu)
+A Class representing an O-RAN O-Cloud resource pool for O-RAN distributed units
+(ORanDu).
 By default all O-RAN-DUs associated with the towers around  are deployed here.
 By default all O-RAN-DUs associated with the towers around  are deployed here.
-Maybe dedicated hardware is required to host O-DUs, but it is expected 
+Maybe dedicated hardware is required to host O-DUs, but it is expected
 that the O-Cloud mechanism and concepts can be applied here.
 """
 import xml.etree.ElementTree as ET
 that the O-Cloud mechanism and concepts can be applied here.
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 from network_generation.model.python.cube import Cube
 
 import network_generation.model.python.hexagon as Hexagon
 from network_generation.model.python.cube import Cube
+from network_generation.model.python.geo_location import GeoLocation
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.hexagon import Hex
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import (
+    IORanNode,
+    ORanNode,
+    default_value,
+)
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
-
 # Define the "IORanDu" interface
 # Define the "IORanDu" interface
-class IORanCloudDu(IORanObject):
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
+IORanCloudDu = IORanNode
 
 
 # Implements a concrete O-RAN Node class
 
 
 # Implements a concrete O-RAN Node class
-class ORanCloudDu(ORanNode, IORanCloudDu):
-    def __init__(self, o_ran_du_data: IORanCloudDu = None, **kwargs):
-        super().__init__(o_ran_du_data, **kwargs)
+class ORanCloudDu(ORanNode):
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_cloud_du_data: IORanCloudDu = self._to_o_ran_cloud_du_data(data)
+
+        super().__init__(cast(dict[str, Any], o_ran_cloud_du_data), **kwargs)
         self._towers: list[Tower] = self._calculate_towers()
 
         self._towers: list[Tower] = self._calculate_towers()
 
+    def _to_o_ran_cloud_du_data(self, data: dict[str, Any]) -> IORanCloudDu:
+        result: IORanCloudDu = default_value
+        for key, key_type in IORanCloudDu.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
     def _calculate_towers(self) -> list[Tower]:
         hex_ring_radius: int = (
     def _calculate_towers(self) -> list[Tower]:
         hex_ring_radius: int = (
-            self.spiralRadiusProfile.oRanDuSpiralRadiusOfTowers
+            self.parent.parent.parent.parent
+            .spiral_radius_profile.oRanDuSpiralRadiusOfTowers
         )
         hex_list: list[Hex] = Cube.spiral(self.position, hex_ring_radius)
         result: list[Tower] = []
         )
         hex_list: list[Hex] = Cube.spiral(self.position, hex_ring_radius)
         result: list[Tower] = []
@@ -57,10 +73,12 @@ class ORanCloudDu(ORanNode, IORanCloudDu):
             name: str = "-".join(
                 [
                     self.name.replace("O-Cloud-DU", "Tower"),
             name: str = "-".join(
                 [
                     self.name.replace("O-Cloud-DU", "Tower"),
-                    s[len(s) - 2 : len(s)],
+                    s[len(s) - 2: len(s)],
                 ]
             )
                 ]
             )
-            network_center: dict = self.parent.parent.parent.parent.center
+            network_center: GeoLocation = (
+                self.parent.parent.parent.parent.center
+            )
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
@@ -71,7 +89,6 @@ class ORanCloudDu(ORanNode, IORanCloudDu):
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
-                        "spiralRadiusProfile": self.spiralRadiusProfile,
                         "parent": self,
                     }
                 )
                         "parent": self,
                     }
                 )
@@ -82,9 +99,8 @@ class ORanCloudDu(ORanNode, IORanCloudDu):
     def towers(self) -> list[Tower]:
         return self._towers
 
     def towers(self) -> list[Tower]:
         return self._towers
 
-    @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["o2"]:
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["o2"]:
@@ -96,14 +112,14 @@ class ORanCloudDu(ORanNode, IORanCloudDu):
             )
         return result
 
             )
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         for tower in self.towers:
             result.extend(tower.to_topology_nodes())
         return result
 
         for tower in self.towers:
             result.extend(tower.to_topology_nodes())
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_links()
         for tower in self.towers:
             result.extend(tower.to_topology_links())
         return result
         for tower in self.towers:
             result.extend(tower.to_topology_links())
         return result
@@ -118,5 +134,5 @@ class ORanCloudDu(ORanNode, IORanCloudDu):
             o_ran_cloud_du.append(tower.toKml())
         return o_ran_cloud_du
 
             o_ran_cloud_du.append(tower.toKml())
         return o_ran_cloud_du
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index d3034b4..be0006d 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A Class representing an O-RAN centralized unit (ORanCu)
 and at the same time a location for an O-Cloud resource pool
 """
 import xml.etree.ElementTree as ET
 
 """
 A Class representing an O-RAN centralized unit (ORanCu)
 and at the same time a location for an O-Cloud resource pool
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
-from network_generation.model.python.cube import Cube
+from network_generation.model.python.geo_location import GeoLocation
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.o_ran_cloud_du import ORanCloudDu
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.o_ran_cloud_du import ORanCloudDu
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import (
+    IORanNode,
+    ORanNode,
+    default_value,
+)
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
-
 # Define the "IORanCu" interface
 # Define the "IORanCu" interface
-class IORanCu(IORanObject):
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
+IORanCu = IORanNode
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class ORanCu(ORanNode, IORanCu):
-    def __init__(self, o_ran_cu_data: IORanCu = None, **kwargs):
-        super().__init__(o_ran_cu_data, **kwargs)
-        self._o_ran_cloud_dus: list[ORanCu] = self._calculate_o_ran_dus()
+class ORanCu(ORanNode):
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_cu_data: IORanCu = self._to_o_ran_cu_data(data)
+        super().__init__(cast(dict[str, Any], o_ran_cu_data), **kwargs)
+        self._o_ran_cloud_dus: list[ORanCloudDu] = self._calculate_o_ran_dus()
+
+    def _to_o_ran_cu_data(self, data: dict[str, Any]) -> IORanCu:
+        result: IORanCu = default_value
+        for key, key_type in IORanCu.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
 
     def _calculate_o_ran_dus(self) -> list[ORanCloudDu]:
         hex_ring_radius: int = (
 
     def _calculate_o_ran_dus(self) -> list[ORanCloudDu]:
         hex_ring_radius: int = (
-            self.spiralRadiusProfile.oRanCuSpiralRadiusOfODus
+            self.parent.parent.parent
+            .spiral_radius_profile.oRanCuSpiralRadiusOfODus
         )
         )
-        hex_list: list[Hex] = self.spiralRadiusProfile.oRanDuSpiral(
+        hex_list: list[
+            Hex
+        ] = self.parent.parent.parent.spiral_radius_profile.oRanDuSpiral(
             self.position, hex_ring_radius
         )
         result: list[ORanCloudDu] = []
         for index, hex in enumerate(hex_list):
             s: str = "00" + str(index)
             name: str = "-".join(
             self.position, hex_ring_radius
         )
         result: list[ORanCloudDu] = []
         for index, hex in enumerate(hex_list):
             s: str = "00" + str(index)
             name: str = "-".join(
-                [self.name.replace("CU", "O-Cloud-DU"), s[len(s) - 2 : len(s)]]
+                [self.name.replace("CU", "O-Cloud-DU"), s[len(s) - 2: len(s)]]
             )
             )
-            network_center: dict = self.parent.parent.parent.center
+            network_center: GeoLocation = self.parent.parent.parent.center
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
@@ -69,7 +84,6 @@ class ORanCu(ORanNode, IORanCu):
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
-                        "spiralRadiusProfile": self.spiralRadiusProfile,
                         "parent": self,
                     }
                 )
                         "parent": self,
                     }
                 )
@@ -88,11 +102,10 @@ class ORanCu(ORanNode, IORanCu):
                 result.append(tower)
         return result
 
                 result.append(tower)
         return result
 
-    @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         phy_tp: str = "-".join([self.name, "phy".upper()])
-        result.append({"tp-id": phy_tp, "name": phy_tp})
+        result.append(ORanTerminationPoint({"tp-id": phy_tp, "name": phy_tp}))
         for interface in ["e2", "o1"]:
             id: str = "-".join([self.name, interface.upper()])
             result.append(
         for interface in ["e2", "o1"]:
             id: str = "-".join([self.name, interface.upper()])
             result.append(
@@ -102,16 +115,16 @@ class ORanCu(ORanNode, IORanCu):
             )
         return result
 
             )
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         # for o_ran_du in self.o_ran_dus: # TODO
         #     result.extend(o_ran_du.to_topology_nodes())
         for o_ran_cloud_du in self.o_ran_cloud_dus:
             result.extend(o_ran_cloud_du.to_topology_nodes())
         return result
 
         # for o_ran_du in self.o_ran_dus: # TODO
         #     result.extend(o_ran_du.to_topology_nodes())
         for o_ran_cloud_du in self.o_ran_cloud_dus:
             result.extend(o_ran_cloud_du.to_topology_nodes())
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_links()
         # for o_ran_du in self.o_ran_dus:
         # result.extend(o_ran_du.to_topology_links())
         for o_ran_cloud_du in self.o_ran_cloud_dus:
         # for o_ran_du in self.o_ran_dus:
         # result.extend(o_ran_du.to_topology_links())
         for o_ran_cloud_du in self.o_ran_cloud_dus:
@@ -128,5 +141,5 @@ class ORanCu(ORanNode, IORanCu):
             o_ran_cu.append(o_ran_cloud_du.toKml())
         return o_ran_cu
 
             o_ran_cu.append(o_ran_cloud_du.toKml())
         return o_ran_cu
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index 6e5149b..0392d2c 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A Class representing an O-RAN distributed unit (ORanDu)
 """
 import xml.etree.ElementTree as ET
 
 """
 A Class representing an O-RAN distributed unit (ORanDu)
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import IORanNode, ORanNode
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 
 
 # Define the "IORanDu" interface
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 
 
 # Define the "IORanDu" interface
-class IORanDu(IORanObject):
-    def __init__(self, o_ran_ru_count: int, **kwargs):
-        super().__init__(**kwargs)
-        self._o_ran_ru_count = o_ran_ru_count
+class IORanDu(IORanNode):
+    o_ran_ru_count: int
+
+
+default_value: IORanDu = cast(
+    IORanDu,
+    {
+        **ORanNode.default(),
+        **{"oRanRuCount": 1},
+    },
+)
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class ORanDu(ORanNode, IORanDu):
-    def __init__(self, o_ran_du_data: IORanDu = None, **kwargs):
-        super().__init__(o_ran_du_data, **kwargs)
+class ORanDu(ORanNode):
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_du_data: IORanDu = self._to_o_ran_du_data(data)
+        super().__init__(cast(dict[str, Any], o_ran_du_data), **kwargs)
         self._o_ran_ru_count = (
             o_ran_du_data["oRanRuCount"]
             if o_ran_du_data and "oRanRuCount" in o_ran_du_data
             else 1
         )
 
         self._o_ran_ru_count = (
             o_ran_du_data["oRanRuCount"]
             if o_ran_du_data and "oRanRuCount" in o_ran_du_data
             else 1
         )
 
-    @property
+    def _to_o_ran_du_data(self, data: dict[str, Any]) -> IORanDu:
+        result: IORanDu = default_value
+        for key, key_type in IORanDu.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["e2", "o1", "ofhm", "ofhc", "ofhu", "ofhs"]:
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["e2", "o1", "ofhm", "ofhc", "ofhu", "ofhs"]:
@@ -58,12 +75,12 @@ class ORanDu(ORanNode, IORanDu):
             )
         return result
 
             )
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         return result
 
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_links()
         for interface in ["e2", "o1"]:
             link_id: str = "".join(
                 [interface, ":", self.name, "<->", self.parent.name]
         for interface in ["e2", "o1"]:
             link_id: str = "".join(
                 [interface, ":", self.name, "<->", self.parent.name]
@@ -91,9 +108,9 @@ class ORanDu(ORanNode, IORanDu):
         open.text = "1"
         name: ET.Element = ET.SubElement(o_ran_du, "name")
         name.text = self.name
         open.text = "1"
         name: ET.Element = ET.SubElement(o_ran_du, "name")
         name.text = self.name
-        for tower in self.towers:
-            o_ran_du.append(tower.toKml())
+        for tower in self.towers:
+            o_ran_du.append(tower.toKml())
         return o_ran_du
 
         return o_ran_du
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index 4e92a5b..5a44843 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 
 """
-A Class representing an O-RAN Near real-time intelligent controller (ORanNearRtRic)
+A Class representing an O-RAN Near real-time intelligent controller
+(ORanNearRtRic)
 """
 import xml.etree.ElementTree as ET
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
+from network_generation.model.python.geo_location import GeoLocation
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.o_ran_cu import ORanCu
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.o_ran_cu import ORanCu
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import (
+    IORanNode,
+    ORanNode,
+    default_value,
+)
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
-
 # Define the "IORanNearRtRic" interface
 # Define the "IORanNearRtRic" interface
-class IORanNearRtRic(IORanObject):
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
+IORanNearRtRic = IORanNode
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class ORanNearRtRic(ORanNode, IORanNearRtRic):
+class ORanNearRtRic(ORanNode):
     def __init__(
     def __init__(
-        self, o_ran_near_rt_ric_data: IORanNearRtRic = None, **kwargs
-    ):
-        super().__init__(o_ran_near_rt_ric_data, **kwargs)
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_near_rt_ric_data: IORanNearRtRic = (
+            self._to_o_ran_near_rt_ric_data(data)
+        )
+        super().__init__(
+            cast(dict[str, Any], o_ran_near_rt_ric_data), **kwargs
+        )
         self._o_ran_cus: list[ORanCu] = self._calculate_o_ran_cus()
 
         self._o_ran_cus: list[ORanCu] = self._calculate_o_ran_cus()
 
+    def _to_o_ran_near_rt_ric_data(
+        self, data: dict[str, Any]
+    ) -> IORanNearRtRic:
+        result: IORanNearRtRic = default_value
+        for key, key_type in IORanNearRtRic.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
     def _calculate_o_ran_cus(self) -> list[ORanCu]:
         hex_ring_radius: int = (
     def _calculate_o_ran_cus(self) -> list[ORanCu]:
         hex_ring_radius: int = (
-            self.spiralRadiusProfile.oRanNearRtRicSpiralRadiusOfOCus
+            self.parent.parent
+            .spiral_radius_profile.oRanNearRtRicSpiralRadiusOfOCus
         )
         )
-        hex_list: list[Hex] = self.spiralRadiusProfile.oRanCuSpiral(
+        hex_list: list[
+            Hex
+        ] = self.parent.parent.spiral_radius_profile.oRanCuSpiral(
             self.position, hex_ring_radius
         )
         result: list[ORanCu] = []
         for index, hex in enumerate(hex_list):
             s: str = "00" + str(index)
             name: str = "-".join(
             self.position, hex_ring_radius
         )
         result: list[ORanCu] = []
         for index, hex in enumerate(hex_list):
             s: str = "00" + str(index)
             name: str = "-".join(
-                [self.name.replace("NearRtRic", "CU"), s[len(s) - 2 : len(s)]]
+                [self.name.replace("NearRtRic", "CU"), s[len(s) - 2: len(s)]]
             )
             )
-            network_center: dict = self.parent.parent.center
+            network_center: GeoLocation = self.parent.parent.center
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
@@ -69,7 +90,6 @@ class ORanNearRtRic(ORanNode, IORanNearRtRic):
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
-                        "spiralRadiusProfile": self.spiralRadiusProfile,
                         "parent": self,
                     }
                 )
                         "parent": self,
                     }
                 )
@@ -88,11 +108,10 @@ class ORanNearRtRic(ORanNode, IORanNearRtRic):
                 result.append(tower)
         return result
 
                 result.append(tower)
         return result
 
-    @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         phy_tp: str = "-".join([self.name, "phy".upper()])
-        result.append({"tp-id": phy_tp, "name": phy_tp})
+        result.append(ORanTerminationPoint({"tp-id": phy_tp, "name": phy_tp}))
         for interface in ["a1", "o1", "o2", "e2"]:
             id: str = "-".join([self.name, interface.upper()])
             result.append(
         for interface in ["a1", "o1", "o2", "e2"]:
             id: str = "-".join([self.name, interface.upper()])
             result.append(
@@ -102,14 +121,14 @@ class ORanNearRtRic(ORanNode, IORanNearRtRic):
             )
         return result
 
             )
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         for o_ran_cu in self.o_ran_cus:
             result.extend(o_ran_cu.to_topology_nodes())
         return result
 
         for o_ran_cu in self.o_ran_cus:
             result.extend(o_ran_cu.to_topology_nodes())
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_links()
         for o_ran_cu in self.o_ran_cus:
             result.extend(o_ran_cu.to_topology_links())
         return result
         for o_ran_cu in self.o_ran_cus:
             result.extend(o_ran_cu.to_topology_links())
         return result
@@ -124,5 +143,5 @@ class ORanNearRtRic(ORanNode, IORanNearRtRic):
             ric.append(o_ran_cu.toKml())
         return ric
 
             ric.append(o_ran_cu.toKml())
         return ric
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index bb39b61..3f816b3 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 """
 Module for a class representing a O-RAN Network
 """
 import xml.etree.ElementTree as ET
 """
 Module for a class representing a O-RAN Network
 """
 import xml.etree.ElementTree as ET
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
+from network_generation.model.python.geo_location import (
+    GeoLocation,
+    IGeoLocation,
+)
 from network_generation.model.python.hexagon import Layout
 from network_generation.model.python.o_ran_object import (
     IORanObject,
 from network_generation.model.python.hexagon import Layout
 from network_generation.model.python.o_ran_object import (
     IORanObject,
@@ -30,25 +35,38 @@ from network_generation.model.python.o_ran_spiral_radius_profile import (
 )
 from network_generation.model.python.point import Point
 
 )
 from network_generation.model.python.point import Point
 
+# Define the "IORanNetwork" interface
+IORanNetwork = IORanObject
+
 
 class ORanNetwork(ORanObject):
     """
     Class representing an O-RAN Network object.
     """
 
 
 class ORanNetwork(ORanObject):
     """
     Class representing an O-RAN Network object.
     """
 
+    __my_default_value: IORanNetwork = cast(IORanNetwork, ORanObject.default())
+
     # constructor
     def __init__(
     # constructor
     def __init__(
-        self, configuration: dict[str, dict], of: IORanObject = None, **kwargs
-    ):
-        super().__init__(of, **kwargs)
+        self,
+        configuration: dict[str, dict],
+        data: dict[str, Any] = cast(dict[str, Any], __my_default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_network_data: IORanNetwork = self._to_o_ran_network_data(data)
+        super().__init__(cast(dict[str, Any], o_ran_network_data), **kwargs)
         self.__configuration = configuration
         self.__configuration = configuration
-        self.name = configuration["name"]
-        self.center = configuration["center"]
-        size = configuration["pattern"]["nr-cell-du"]["max-reach"]
+
+        self.name = str(configuration["name"])
+        self._center: IGeoLocation = cast(
+            IGeoLocation, configuration["center"]
+        )
+
+        size: int = int(configuration["pattern"]["nr-cell-du"]["max-reach"])
         layout = Layout(
             Hexagon.layout_flat, Point(size, size), Point(0, 0)
         )  # 1 pixel = 1 meter
         layout = Layout(
             Hexagon.layout_flat, Point(size, size), Point(0, 0)
         )  # 1 pixel = 1 meter
-        spiral_radius_profile = SpiralRadiusProfile(
+        self._spiral_radius_profile: SpiralRadiusProfile = SpiralRadiusProfile(
             {
                 "oRanSmoSpiralRadiusOfNearRtRics": configuration["pattern"][
                     "smo"
             {
                 "oRanSmoSpiralRadiusOfNearRtRics": configuration["pattern"][
                     "smo"
@@ -69,22 +87,44 @@ class ORanNetwork(ORanObject):
                 "name": "O-RAN-SMO",
                 "geoLocation": self.center,
                 "layout": layout,
                 "name": "O-RAN-SMO",
                 "geoLocation": self.center,
                 "layout": layout,
-                "spiralRadiusProfile": spiral_radius_profile,
                 "parent": self,
             }
         )
 
                 "parent": self,
             }
         )
 
-    # getter
-    def configuration(self) -> dict[str, dict]:
+    def _to_o_ran_network_data(self, data: dict[str, Any]) -> IORanNetwork:
+        result: IORanNetwork = self.__my_default_value
+        for key, key_type in IORanNetwork.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
+    @property
+    def center(self) -> GeoLocation:
+        """
+        Getter for a json object representing the O-RAN Network.
+        :return O-RAN Network as json object.
+        """
+        return GeoLocation(self._center)
+
+    @property
+    def spiral_radius_profile(self) -> SpiralRadiusProfile:
+        """
+        Getter for a json object representing the SpiralRadiusProfile.
+        :return SpiralRadiusProfile.
+        """
+        return self._spiral_radius_profile
+
+    @property
+    def configuration(self) -> dict[str, Any]:
         """
         Getter for a json object representing the O-RAN Network.
         :return O-RAN Network as json object.
         """
         return self.__configuration
 
         """
         Getter for a json object representing the O-RAN Network.
         :return O-RAN Network as json object.
         """
         return self.__configuration
 
-    def to_topology(self) -> dict[str, dict]:
-        nodes: dict[str, dict] = self._o_ran_smo.to_topology_nodes()
-        links: dict[str, dict] = self._o_ran_smo.to_topology_links()
+    def to_topology(self) -> dict[str, Any]:
+        nodes: list[dict[str, Any]] = self._o_ran_smo.to_topology_nodes()
+        links: list[dict[str, Any]] = self._o_ran_smo.to_topology_links()
         return {
             "ietf-network:networks": {
                 "network": [
         return {
             "ietf-network:networks": {
                 "network": [
@@ -129,12 +169,15 @@ class ORanNetwork(ORanObject):
             xmlns="http://www.w3.org/2000/svg",
         )
         desc = ET.Element("desc")
             xmlns="http://www.w3.org/2000/svg",
         )
         desc = ET.Element("desc")
-        # desc.text="\n context: " + str(self.id()) + "\n name: " + str(self.name())
+        desc.text = "\n context: " + self.id + "\n name: " + self.name
         root.append(desc)
 
         title = ET.Element("title")
         root.append(desc)
 
         title = ET.Element("title")
-        title.text = self.configuration()["name"]
+        title.text = str(self.configuration["name"])
         root.append(title)
 
         # root.append(self.__context.svg(x, y))
         return root
         root.append(title)
 
         # root.append(self.__context.svg(x, y))
         return root
+
+    def json(self) -> dict[str, Any]:
+        return super().json()
index 7e5ec63..e8471ab 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 An abstract Class for O-RAN Node
 """
 
 """
 An abstract Class for O-RAN Node
 """
-import json
 import xml.etree.ElementTree as ET
 import xml.etree.ElementTree as ET
-from abc import abstractmethod, abstractproperty
-from typing import Any
+from abc import abstractmethod
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
+from network_generation.model.python.countries import Country
 from network_generation.model.python.geo_location import GeoLocation
 from network_generation.model.python.hexagon import Hex, Layout
 from network_generation.model.python.o_ran_object import (
 from network_generation.model.python.geo_location import GeoLocation
 from network_generation.model.python.hexagon import Hex, Layout
 from network_generation.model.python.o_ran_object import (
@@ -41,74 +41,98 @@ from network_generation.model.python.type_definitions import AddressType
 
 # Define the "IORanObject" interface
 class IORanNode(IORanObject):
 
 # Define the "IORanObject" interface
 class IORanNode(IORanObject):
-    def __init__(
-        self,
-        address: AddressType = None,
-        geoLocation: GeoLocation = None,
-        url: str = None,
-        position: Hex = None,
-        layout: Layout = None,
-        spiralRadiusProfile: SpiralRadiusProfile = None,
-        parent=None,
-        **kwargs
-    ):
-        super().__init__(**kwargs)
-        self.address = address
-        self.geoLocation = geoLocation
-        self.url = url
-        self.position = position
-        self.layout = layout
-        self.spiralRadiusProfile = (spiralRadiusProfile,)
-        self.parent = parent
+    address: AddressType
+    geoLocation: GeoLocation
+    url: str
+    position: Hex
+    layout: Layout
+    spiralRadiusProfile: SpiralRadiusProfile
+    parent: Any
+
+
+default_address: AddressType = {
+    "street": "highstreet",
+    "building": "none",
+    "city": "heaven",
+    "room": "frist",
+    "zip": "12345",
+    "state": "none",
+    "country": Country.Germany,
+}
+default_value: IORanNode = cast(
+    IORanNode,
+    {
+        **ORanObject.default(),
+        **{
+            "address": default_address,
+            "geoLocation": GeoLocation(),
+            "url": "non-url",
+            "position": Hex(0, 0, 0),
+            "layout": Layout(Hexagon.layout_flat, Point(1, 1), Point(0, 0)),
+            "spiralRadiusProfile": SpiralRadiusProfile(),
+            "parent": None,
+        },
+    },
+)
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class ORanNode(ORanObject, IORanNode):
-    def __init__(self, of: IORanNode = None, **kwargs):
-        super().__init__(of, **kwargs)
-        self.address = of["address"] if of and "address" in of else None
-        self.geoLocation = (
-            of["geoLocation"] if of and "geoLocation" in of else GeoLocation()
-        )
-        self.url = of["url"] if of and "url" in of else self.id
-        self.position = (
-            of["position"] if of and "position" in of else Hex(0, 0, 0)
+class ORanNode(ORanObject):
+    @staticmethod
+    def default() -> dict[str, Any]:
+        return cast(dict[str, Any], default_value)
+
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_node_data: IORanNode = self._to_o_ran_node_data(data)
+        super().__init__(cast(dict[str, Any], data), **kwargs)
+        self._address: AddressType = cast(
+            AddressType, o_ran_node_data["address"]
         )
         )
-        self.layout = (
-            of["layout"]
-            if of and "layout" in of
-            else Layout(Hexagon.layout_flat, Point(1, 1), Point(0, 0))
+        self._geo_location: GeoLocation = cast(
+            GeoLocation, o_ran_node_data["geoLocation"]
         )
         )
-        self.spiralRadiusProfile = (
-            of["spiralRadiusProfile"]
-            if of and "spiralRadiusProfile" in of
-            else SpiralRadiusProfile()
+        self._url: str = str(o_ran_node_data["url"])
+        self._position: Hex = cast(Hex, o_ran_node_data["position"])
+        self._layout: Layout = cast(Layout, o_ran_node_data["layout"])
+        self._spiral_radius_profile: SpiralRadiusProfile = cast(
+            SpiralRadiusProfile, o_ran_node_data["spiralRadiusProfile"]
         )
         )
-        self.parent = of["parent"] if of and "parent" in of else None
+        self._parent: Any = o_ran_node_data["parent"]
         self._termination_points: list[ORanTerminationPoint] = []
 
         self._termination_points: list[ORanTerminationPoint] = []
 
+    def _to_o_ran_node_data(self, data: dict[str, Any]) -> IORanNode:
+        result: IORanNode = default_value
+        for key, key_type in IORanNode.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
     @property
     @property
-    def address(self) -> str:
+    def address(self) -> AddressType:
         return self._address
 
     @address.setter
         return self._address
 
     @address.setter
-    def address(self, value: str):
+    def address(self, value: AddressType) -> None:
         self._address = value
 
     @property
         self._address = value
 
     @property
-    def geoLocation(self) -> GeoLocation:
-        return self._geographicalLocation
+    def geo_location(self) -> GeoLocation:
+        return self._geo_location
 
 
-    @geoLocation.setter
-    def geoLocation(self, value: GeoLocation):
-        self._geographicalLocation = value
+    @geo_location.setter
+    def geo_location(self, value: GeoLocation) -> None:
+        self._geo_location = value
 
     @property
     def url(self) -> str:
         return self._url
 
     @url.setter
 
     @property
     def url(self) -> str:
         return self._url
 
     @url.setter
-    def url(self, value: str):
+    def url(self, value: str) -> None:
         self._url = value
 
     @property
         self._url = value
 
     @property
@@ -116,7 +140,7 @@ class ORanNode(ORanObject, IORanNode):
         return self._position
 
     @position.setter
         return self._position
 
     @position.setter
-    def position(self, value: Hex):
+    def position(self, value: Hex) -> None:
         self._position = value
 
     @property
         self._position = value
 
     @property
@@ -124,16 +148,16 @@ class ORanNode(ORanObject, IORanNode):
         return self._layout
 
     @layout.setter
         return self._layout
 
     @layout.setter
-    def layout(self, value: Layout):
+    def layout(self, value: Layout) -> None:
         self._layout = value
 
     @property
         self._layout = value
 
     @property
-    def spiralRadiusProfile(self) -> SpiralRadiusProfile:
-        return self._spiralRadiusProfile
+    def spiral_radius_profile(self) -> SpiralRadiusProfile:
+        return self._spiral_radius_profile
 
 
-    @spiralRadiusProfile.setter
-    def spiralRadiusProfile(self, value: SpiralRadiusProfile):
-        self._spiralRadiusProfile = value
+    @spiral_radius_profile.setter
+    def spiral_radius_profile(self, value: SpiralRadiusProfile) -> None:
+        self._spiral_radius_profile = value
 
     @property
     def parent(
 
     @property
     def parent(
@@ -142,34 +166,26 @@ class ORanNode(ORanObject, IORanNode):
         return self._parent
 
     @parent.setter
         return self._parent
 
     @parent.setter
-    def parent(self, value: Any):
+    def parent(self, value: Any) -> None:
         self._parent = value
 
         self._parent = value
 
-    @abstractproperty
+    # @property
+    # @abstractmethod
     def termination_points(self) -> list[ORanTerminationPoint]:
         return self._termination_points
 
     def termination_points(self) -> list[ORanTerminationPoint]:
         return self._termination_points
 
-    def json(self) -> dict[str, dict]:
-        result: dict = super().json()
-        result["address"] = self.address
-        result["geoLocation"] = self.geoLocation
-        result["url"] = self.url
-        result["layout"] = self.layout
-        result["spiralRadiusProfile"] = self.spiralRadiusProfile
-        result["parent"] = self.parent
-        return result
-
     @abstractmethod
     @abstractmethod
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        tps: list[dict[str, dict]] = []
-        for tp in self.termination_points:
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        tps: list[dict[str, Any]] = []
+        for tp in self.termination_points():
             if (
                 str(type(tp))
             if (
                 str(type(tp))
-                == "<class 'model.python.o_ran_termination_point.ORanTerminationPoint'>"
+                == "<class 'model.python.o_ran_termination_point"
+                + ".ORanTerminationPoint'>"
             ):
                 tps.append(tp.to_topology())
 
             ):
                 tps.append(tp.to_topology())
 
-        result: list[dict[str, dict]] = []
+        result: list[dict[str, Any]] = []
         result.append(
             {
                 "node-id": self.name,
         result.append(
             {
                 "node-id": self.name,
@@ -179,11 +195,11 @@ class ORanNode(ORanObject, IORanNode):
         return result
 
     @abstractmethod
         return result
 
     @abstractmethod
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = []
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = []
         source_tp: str = "-".join([self.name, "phy".upper()])
         dest_tp: str = "-".join([self.parent.name, "phy".upper()])
         source_tp: str = "-".join([self.name, "phy".upper()])
         dest_tp: str = "-".join([self.parent.name, "phy".upper()])
-        if self.parent and not "Tower" in source_tp and not "Tower" in dest_tp:
+        if self.parent and "Tower" not in source_tp and "Tower" not in dest_tp:
             link_id: str = "".join(
                 ["phy", ":", self.name, "<->", self.parent.name]
             )
             link_id: str = "".join(
                 ["phy", ":", self.name, "<->", self.parent.name]
             )
@@ -203,5 +219,5 @@ class ORanNode(ORanObject, IORanNode):
         pass
 
     @abstractmethod
         pass
 
     @abstractmethod
-    def toSvg(self) -> ET.Element | None:
+    def toSvg(self) -> ET.Element:
         pass
         pass
index 3e367a6..ef74b30 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 An abstract Class for O-RAN Objects
 """
 
 """
 An abstract Class for O-RAN Objects
 """
-from network_generation.model.python.top import ITop, Top
+from typing import Any, cast
 
 
+from network_generation.model.python.top import ITop, Top, default_value
 
 # Define the "IORanObject" interface
 
 # Define the "IORanObject" interface
-class IORanObject(ITop):
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
+# class IORanObject(ITop):
+IORanObject = ITop
 
 
 # Define an abstract O-RAN Object class
 
 
 # Define an abstract O-RAN Object class
-class ORanObject(Top, IORanObject):
-    def __init__(self, of: IORanObject = None, **kwargs):
-        super().__init__(of, **kwargs)
-
-    def json(self) -> dict[str, dict]:
-        result: dict[str, dict] = super().json()
-        return result
-
-    def __str__(self) -> str:
-        return str(self.json())
+class ORanObject(Top):
+    @staticmethod
+    def default() -> dict[str, Any]:
+        return cast(dict[str, Any], default_value)
+
+    def __init__(
+        self, data: dict[str, Any] = default(), **kwargs: dict[str, Any]
+    ) -> None:
+        super().__init__(data, **kwargs)
+
+    def json(self) -> dict[str, Any]:
+        return {
+            **super().json(),
+            "id": self.id,
+            "name": self.name,
+            "administrativeState": self.administrativeState,
+            "operationalState": self.operationalState,
+            "lifeCycleState": self.lifeCycleState,
+            "alarmState": self.alarmState,
+            "usageState": self.usageState,
+            "utilization": self.utilization,
+        }
index d9b119d..e8ca9cf 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A Class representing an O-RAN radio unit (ORanRu)
 """
 import xml.etree.ElementTree as ET
 
 """
 A Class representing an O-RAN radio unit (ORanRu)
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 from network_generation.model.python.nr_cell_du import NrCellDu
 from network_generation.model.python.o_ran_du import ORanDu
 
 from network_generation.model.python.nr_cell_du import NrCellDu
 from network_generation.model.python.o_ran_du import ORanDu
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import IORanNode, ORanNode
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 
 
 # Define the "IORanRu" interface
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 
 
 # Define the "IORanRu" interface
-class IORanRu(IORanObject):
-    def __init__(
-        self, cell_count: int, ru_angle: int, ru_azimuth: int, **kwargs
-    ):
-        super().__init__(**kwargs)
-        self._cell_count = cell_count
-        self._ru_angle = ru_angle
-        self._ru_azimuth = ru_azimuth
+class IORanRu(IORanNode):
+    cellCount: int
+    ruAngle: int
+    ruAzimuth: int
+
+
+default_value: IORanRu = cast(
+    IORanRu,
+    {
+        **ORanNode.default(),
+        **{"cellCount": 1, "ruAngle": 120, "ruAzimuth": 0},
+    },
+)
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class ORanRu(ORanNode, IORanRu):
-    def __init__(self, o_ran_ru_data: IORanRu = None, **kwargs):
-        super().__init__(o_ran_ru_data, **kwargs)
-        self._cell_count = (
-            o_ran_ru_data["cellCount"]
+class ORanRu(ORanNode):
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_ru_data: IORanRu = self._to_o_ran_ru_data(data)
+        super().__init__(cast(dict[str, Any], o_ran_ru_data), **kwargs)
+        self._cell_count: int = (
+            int(str(o_ran_ru_data["cellCount"]))
             if o_ran_ru_data and "cellCount" in o_ran_ru_data
             else 1
         )
             if o_ran_ru_data and "cellCount" in o_ran_ru_data
             else 1
         )
-        self._ru_angle = (
-            o_ran_ru_data["ruAngle"]
+        self._ru_angle: int = (
+            int(str(o_ran_ru_data["ruAngle"]))
             if o_ran_ru_data and "ruAngle" in o_ran_ru_data
             else 120
         )
             if o_ran_ru_data and "ruAngle" in o_ran_ru_data
             else 120
         )
-        self._ru_azimuth = (
-            o_ran_ru_data["ruAzimuth"]
+        self._ru_azimuth: int = (
+            int(str(o_ran_ru_data["ruAzimuth"]))
             if o_ran_ru_data and "ruAzimuth" in o_ran_ru_data
             else 0
         )
         self._cells: list[NrCellDu] = self._create_cells()
         name: str = self.name.replace("RU", "DU")
             if o_ran_ru_data and "ruAzimuth" in o_ran_ru_data
             else 0
         )
         self._cells: list[NrCellDu] = self._create_cells()
         name: str = self.name.replace("RU", "DU")
-        self._oRanDu: ORanDu = ORanDu(
-            {
-                "name": name,
-                "geoLocation": self.parent.geoLocation,
-                "position": self.parent.position,
-                "layout": self.layout,
-                "parent": self.parent.parent.parent,
-            }
-        )
+
+        o_ran_du_data: dict[str, Any] = {
+            "name": name,
+            "geoLocation": self.parent.geo_location,
+            "position": self.parent.position,
+            "layout": self.layout,
+            "parent": self.parent.parent.parent,
+        }
+        self._oRanDu: ORanDu = ORanDu(o_ran_du_data)
+
+    def _to_o_ran_ru_data(self, data: dict[str, Any]) -> IORanRu:
+        result: IORanRu = default_value
+        for key, key_type in IORanRu.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
 
     def _create_cells(self) -> list[NrCellDu]:
         result: list[NrCellDu] = []
         cell_angle: int = (
 
     def _create_cells(self) -> list[NrCellDu]:
         result: list[NrCellDu] = []
         cell_angle: int = (
-            self.parent.parent.parent.parent.parent.parent.configuration()[
+            self.parent.parent.parent.parent.parent.parent.configuration[
                 "pattern"
             ]["nr-cell-du"]["cell-angle"]
         )
         for index in range(self._cell_count):
             s: str = "00" + str(index)
             name: str = "-".join(
                 "pattern"
             ]["nr-cell-du"]["cell-angle"]
         )
         for index in range(self._cell_count):
             s: str = "00" + str(index)
             name: str = "-".join(
-                [self.name.replace("RU", "NRCellDu"), s[len(s) - 2 : len(s)]]
+                [self.name.replace("RU", "NRCellDu"), s[len(s) - 2: len(s)]]
             )
             azimuth: int = index * cell_angle + self._ru_azimuth
             result.append(
                 NrCellDu(
                     {
                         "name": name,
             )
             azimuth: int = index * cell_angle + self._ru_azimuth
             result.append(
                 NrCellDu(
                     {
                         "name": name,
-                        "geoLocation": self.geoLocation,
+                        "geoLocation": self.geo_location,
                         "position": self.position,
                         "layout": self.layout,
                         "position": self.position,
                         "layout": self.layout,
-                        "spiralRadiusProfile": self.spiralRadiusProfile,
                         "parent": self,
                         "cellAngle": cell_angle,
                         "azimuth": azimuth,
                         "parent": self,
                         "cellAngle": cell_angle,
                         "azimuth": azimuth,
@@ -108,9 +123,8 @@ class ORanRu(ORanNode, IORanRu):
     def oRanDu(self) -> ORanDu:
         return self._oRanDu
 
     def oRanDu(self) -> ORanDu:
         return self._oRanDu
 
-    @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["ofhm", "ofhc", "ofhu", "ofhs"]:
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["ofhm", "ofhc", "ofhu", "ofhs"]:
@@ -121,16 +135,16 @@ class ORanRu(ORanNode, IORanRu):
                 )
             )
         for cell in self.cells:
                 )
             )
         for cell in self.cells:
-            result.extend(cell.termination_points)
+            result.extend(cell.termination_points())
         return result
 
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         result.extend(self.oRanDu.to_topology_nodes())
         return result
 
         result.extend(self.oRanDu.to_topology_nodes())
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_links()
         result.extend(self.oRanDu.to_topology_links())
         for interface in ["phy", "ofhm", "ofhc", "ofhu", "ofhs"]:
             link_id: str = "".join(
         result.extend(self.oRanDu.to_topology_links())
         for interface in ["phy", "ofhm", "ofhc", "ofhu", "ofhs"]:
             link_id: str = "".join(
@@ -163,5 +177,5 @@ class ORanRu(ORanNode, IORanRu):
             o_ran_ru.append(cell.toKml())
         return o_ran_ru
 
             o_ran_ru.append(cell.toKml())
         return o_ran_ru
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index 9b1be83..9308291 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 
 """
-A Class representing an O-RAN Service Management and Orchestration Framework (SMO)
+A Class representing an O-RAN Service Management and
+Orchestration Framework (SMO)
 """
 import xml.etree.ElementTree as ET
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
+from network_generation.model.python.geo_location import GeoLocation
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.o_ran_near_rt_ric import ORanNearRtRic
 from network_generation.model.python.hexagon import Hex
 from network_generation.model.python.o_ran_near_rt_ric import ORanNearRtRic
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import (
+    IORanNode,
+    ORanNode,
+    default_value,
+)
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 )
 from network_generation.model.python.tower import Tower
 
-
 # Define the "IORanSmo" interface
 # Define the "IORanSmo" interface
-class IORanSmo(IORanObject):
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
+IORanSmo = IORanNode
 
 
 # Define an abstract O-RAN Node class
 
 
 # Define an abstract O-RAN Node class
-class ORanSmo(ORanNode, IORanSmo):
-    def __init__(self, o_ran_smo_data: IORanSmo = None, **kwargs):
-        super().__init__(o_ran_smo_data, **kwargs)
-        self._o_ran_near_rt_rics: list[
-            ORanNearRtRic
-        ] = self._calculate_near_rt_rics()
+class ORanSmo(ORanNode):
+    """
+    Class representing an O-RAN Service Management and Operation object.
+    """
+
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        o_ran_smo_data: IORanSmo = self._to_o_ran_smo_data(data)
+        super().__init__(cast(dict[str, Any], o_ran_smo_data), **kwargs)
+        if self.parent is not None:
+            self._o_ran_near_rt_rics: list[
+                ORanNearRtRic
+            ] = self._calculate_near_rt_rics()
 
     def _calculate_near_rt_rics(self) -> list[ORanNearRtRic]:
         hex_ring_radius: int = (
 
     def _calculate_near_rt_rics(self) -> list[ORanNearRtRic]:
         hex_ring_radius: int = (
-            self.spiralRadiusProfile.oRanSmoSpiralRadiusOfNearRtRics
+            self.parent.spiral_radius_profile.oRanSmoSpiralRadiusOfNearRtRics
+            if self.parent is not None
+            else 1
         )
         )
-        hex_list: list[Hex] = self.spiralRadiusProfile.oRanNearRtRicSpiral(
+        hex_list: list[
+            Hex
+        ] = self.parent.spiral_radius_profile.oRanNearRtRicSpiral(
             self.position, hex_ring_radius
         )
         result: list[ORanNearRtRic] = []
         for index, hex in enumerate(hex_list):
             s: str = "00" + str(index)
             name: str = "-".join(
             self.position, hex_ring_radius
         )
         result: list[ORanNearRtRic] = []
         for index, hex in enumerate(hex_list):
             s: str = "00" + str(index)
             name: str = "-".join(
-                [self.name.replace("SMO", "NearRtRic"), s[len(s) - 2 : len(s)]]
+                [self.name.replace("SMO", "NearRtRic"), s[len(s) - 2: len(s)]]
             )
             )
-            network_center: dict = self.parent.center
+            network_center: GeoLocation = self.parent.center
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
             newGeo = Hexagon.hex_to_geo_location(
                 self.layout, hex, network_center
             ).json()
@@ -69,47 +85,58 @@ class ORanSmo(ORanNode, IORanSmo):
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
                         "geoLocation": newGeo,
                         "position": hex,
                         "layout": self.layout,
-                        "spiralRadiusProfile": self.spiralRadiusProfile,
                         "parent": self,
                         "parent": self,
-                    }
+                    },
                 )
             )
         return result
 
                 )
             )
         return result
 
+    def _to_o_ran_smo_data(self, data: dict[str, Any]) -> IORanSmo:
+        result: IORanSmo = default_value
+        for key, key_type in IORanSmo.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
     @property
     def o_ran_near_rt_rics(self) -> list[ORanNearRtRic]:
         return self._o_ran_near_rt_rics
 
     @property
     @property
     def o_ran_near_rt_rics(self) -> list[ORanNearRtRic]:
         return self._o_ran_near_rt_rics
 
     @property
+    def towers(self) -> list[Tower]:
+        result: list[Tower] = []
+        for ric in self.o_ran_near_rt_rics:
+            for tower in ric.towers:
+                result.append(tower)
+        return result
+
+    # @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["a1", "o1", "o2"]:
             id: str = "-".join([self.name, interface.upper()])
             result.append(
                 ORanTerminationPoint(
         phy_tp: str = "-".join([self.name, "phy".upper()])
         result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
         for interface in ["a1", "o1", "o2"]:
             id: str = "-".join([self.name, interface.upper()])
             result.append(
                 ORanTerminationPoint(
-                    {"id": id, "name": id, "supporter": phy_tp, "parent": self}
+                    {
+                        "id": id,
+                        "name": id,
+                        "supporter": phy_tp,
+                        "parent": self,
+                    },
                 )
             )
         return result
 
                 )
             )
         return result
 
-    @property
-    def towers(self) -> list[Tower]:
-        result: list[Tower] = []
-        for ric in self.o_ran_near_rt_rics:
-            for tower in ric.towers:
-                result.append(tower)
-        return result
-
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         for ric in self.o_ran_near_rt_rics:
             result.extend(ric.to_topology_nodes())
         return result
 
         for ric in self.o_ran_near_rt_rics:
             result.extend(ric.to_topology_nodes())
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = []  # super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = []  # super().to_topology_links()
         for ric in self.o_ran_near_rt_rics:
             result.extend(ric.to_topology_links())
         return result
         for ric in self.o_ran_near_rt_rics:
             result.extend(ric.to_topology_links())
         return result
@@ -124,5 +151,5 @@ class ORanSmo(ORanNode, IORanSmo):
             smo.append(ric.toKml())
         return smo
 
             smo.append(ric.toKml())
         return smo
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("not-implemented-yet-TODO")
index fd8c289..75d684c 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
+
+from typing import Any
 
 import network_generation.model.python.hexagon as Hexagon
 
 import network_generation.model.python.hexagon as Hexagon
-from network_generation.model.python.cube import Cube
 from network_generation.model.python.hexagon import Hex
 
 
 class SpiralRadiusProfile:
 from network_generation.model.python.hexagon import Hex
 
 
 class SpiralRadiusProfile:
-    def __init__(self, data: [dict[str, dict] | None] = None):
+    def __init__(self, data: dict[str, Any] | None = None) -> None:
         self._oRanSmoSpiralRadiusOfNearRtRics = (
             data.get("oRanSmoSpiralRadiusOfNearRtRics", 1) if data else 1
         )
         self._oRanSmoSpiralRadiusOfNearRtRics = (
             data.get("oRanSmoSpiralRadiusOfNearRtRics", 1) if data else 1
         )
@@ -33,10 +34,20 @@ class SpiralRadiusProfile:
         self._oRanDuSpiralRadiusOfTowers = (
             data.get("oRanDuSpiralRadiusOfTowers", 1) if data else 1
         )
         self._oRanDuSpiralRadiusOfTowers = (
             data.get("oRanDuSpiralRadiusOfTowers", 1) if data else 1
         )
+        # self._nrDuCellsPerSector: int = (
+        #     int(str(data.get("sectorCount"))) if data else 1
+        # )
 
     @property
     def id(self) -> str:
 
     @property
     def id(self) -> str:
-        return f"{self._oRanDuSpiralRadiusOfTowers}{self._oRanCuSpiralRadiusOfODus}{self._oRanNearRtRicSpiralRadiusOfOCus}{self._oRanSmoSpiralRadiusOfNearRtRics}"
+        return "".join(
+            [
+                str(self._oRanDuSpiralRadiusOfTowers),
+                str(self._oRanCuSpiralRadiusOfODus),
+                str(self._oRanNearRtRicSpiralRadiusOfOCus),
+                str(self._oRanSmoSpiralRadiusOfNearRtRics),
+            ]
+        )
 
     @property
     def count(self) -> int:
 
     @property
     def count(self) -> int:
@@ -64,7 +75,7 @@ class SpiralRadiusProfile:
         return self._oRanSmoSpiralRadiusOfNearRtRics
 
     @oRanSmoSpiralRadiusOfNearRtRics.setter
         return self._oRanSmoSpiralRadiusOfNearRtRics
 
     @oRanSmoSpiralRadiusOfNearRtRics.setter
-    def oRanSmoSpiralRadiusOfNearRtRics(self, value: int):
+    def oRanSmoSpiralRadiusOfNearRtRics(self, value: int) -> None:
         self._oRanSmoSpiralRadiusOfNearRtRics = value
 
     @property
         self._oRanSmoSpiralRadiusOfNearRtRics = value
 
     @property
@@ -72,7 +83,7 @@ class SpiralRadiusProfile:
         return self._oRanNearRtRicSpiralRadiusOfOCus
 
     @oRanNearRtRicSpiralRadiusOfOCus.setter
         return self._oRanNearRtRicSpiralRadiusOfOCus
 
     @oRanNearRtRicSpiralRadiusOfOCus.setter
-    def oRanNearRtRicSpiralRadiusOfOCus(self, value: int):
+    def oRanNearRtRicSpiralRadiusOfOCus(self, value: int) -> None:
         self._oRanNearRtRicSpiralRadiusOfOCus = value
 
     @property
         self._oRanNearRtRicSpiralRadiusOfOCus = value
 
     @property
@@ -80,7 +91,7 @@ class SpiralRadiusProfile:
         return self._oRanCuSpiralRadiusOfODus
 
     @oRanCuSpiralRadiusOfODus.setter
         return self._oRanCuSpiralRadiusOfODus
 
     @oRanCuSpiralRadiusOfODus.setter
-    def oRanCuSpiralRadiusOfODus(self, value: int):
+    def oRanCuSpiralRadiusOfODus(self, value: int) -> None:
         self._oRanCuSpiralRadiusOfODus = value
 
     @property
         self._oRanCuSpiralRadiusOfODus = value
 
     @property
@@ -88,7 +99,7 @@ class SpiralRadiusProfile:
         return self._oRanDuSpiralRadiusOfTowers
 
     @oRanDuSpiralRadiusOfTowers.setter
         return self._oRanDuSpiralRadiusOfTowers
 
     @oRanDuSpiralRadiusOfTowers.setter
-    def oRanDuSpiralRadiusOfTowers(self, value: int):
+    def oRanDuSpiralRadiusOfTowers(self, value: int) -> None:
         self._oRanDuSpiralRadiusOfTowers = value
 
     @property
         self._oRanDuSpiralRadiusOfTowers = value
 
     @property
@@ -96,7 +107,7 @@ class SpiralRadiusProfile:
         return self._sectors
 
     @sectors.setter
         return self._sectors
 
     @sectors.setter
-    def sectors(self, value: int):
+    def sectors(self, value: int) -> None:
         self._sectors = value
 
     @property
         self._sectors = value
 
     @property
@@ -104,8 +115,8 @@ class SpiralRadiusProfile:
         return self._nrDuCellsPerSector
 
     @nrDuCellsPerSector.setter
         return self._nrDuCellsPerSector
 
     @nrDuCellsPerSector.setter
-    def nrDuCellsPerSector(self, value: int):
-        self._nrDuCellsPerSector: int = value
+    def nrDuCellsPerSector(self, value: int) -> None:
+        self._nrDuCellsPerSector = value
 
     def oRanDuDirections(self) -> list[Hex]:
         q: int = 2 * self._oRanDuSpiralRadiusOfTowers + 1
 
     def oRanDuDirections(self) -> list[Hex]:
         q: int = 2 * self._oRanDuSpiralRadiusOfTowers + 1
@@ -120,13 +131,14 @@ class SpiralRadiusProfile:
             Hex(-r, -s, -q),
         ]
 
             Hex(-r, -s, -q),
         ]
 
-    def oRanDuNeighbor(self, cube: Cube, direction: int):
+    def oRanDuNeighbor(self, cube: Hex, direction: int) -> Hex:
         return Hexagon.hex_add(cube, self.oRanDuDirections()[direction])
 
     def oRanDuRing(self, center: Hex, radius: int) -> list[Hex]:
         if radius <= 0:
             raise ValueError(
         return Hexagon.hex_add(cube, self.oRanDuDirections()[direction])
 
     def oRanDuRing(self, center: Hex, radius: int) -> list[Hex]:
         if radius <= 0:
             raise ValueError(
-                "Invalid radius. The radius around the hex center must be greater than 0 rings."
+                "Invalid radius. The radius around the hex center "
+                + "must be greater than 0 rings."
             )
         results: list[Hex] = []
         hex: Hex = Hexagon.hex_add(
             )
         results: list[Hex] = []
         hex: Hex = Hexagon.hex_add(
@@ -166,13 +178,14 @@ class SpiralRadiusProfile:
             Hex(-r, -s, -q),
         ]
 
             Hex(-r, -s, -q),
         ]
 
-    def oRanCuNeighbor(self, cube: Hex, direction: int) -> list[Hex]:
+    def oRanCuNeighbor(self, cube: Hex, direction: int) -> Hex:
         return Hexagon.hex_add(cube, self.oRanCuDirections()[direction])
 
         return Hexagon.hex_add(cube, self.oRanCuDirections()[direction])
 
-    def oRanCuRing(self, center: Hex, radius: int):
+    def oRanCuRing(self, center: Hex, radius: int) -> list[Hex]:
         if not (radius > 0):
             raise ValueError(
         if not (radius > 0):
             raise ValueError(
-                "Invalid radius. The radius around the hex center must be greater than 0 rings."
+                "Invalid radius. The radius around the hex center "
+                + "must be greater than 0 rings."
             )
 
         results: list[Hex] = []
             )
 
         results: list[Hex] = []
@@ -207,45 +220,45 @@ class SpiralRadiusProfile:
         q: int = 3 * q0 - self.oRanNearRtRicSpiralRadiusOfOCus
         r: int = -r0 - self.oRanNearRtRicSpiralRadiusOfOCus
 
         q: int = 3 * q0 - self.oRanNearRtRicSpiralRadiusOfOCus
         r: int = -r0 - self.oRanNearRtRicSpiralRadiusOfOCus
 
-        profile_id: str = self.id[0 : len(self.id) - 1]
+        profile_id: str = self.id[0: len(self.id) - 1]
         if profile_id in {"111", "112", "113", "114"}:
         if profile_id in {"111", "112", "113", "114"}:
-            q: int = 21 + 14 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -7 * self.oRanNearRtRicSpiralRadiusOfOCus
+            q = 21 + 14 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -7 * self.oRanNearRtRicSpiralRadiusOfOCus
         elif profile_id in {"121", "122", "123", "124"}:
         elif profile_id in {"121", "122", "123", "124"}:
-            q: int = 25 + 13 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = 9 + 10 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            q = 25 + 13 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = 9 + 10 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
         elif profile_id in {"131", "132"}:
         elif profile_id in {"131", "132"}:
-            q: int = 49 + 30 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -21 - 34 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            q = 49 + 30 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -21 - 34 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
         elif profile_id == "133":
         elif profile_id == "133":
-            q: int = 74
-            r: int = 37
+            q = 74
+            r = 37
         elif profile_id == "134":
         elif profile_id == "134":
-            q: int = 93
-            r: int = 50
+            q = 93
+            r = 50
         elif profile_id in {"211", "212", "213", "214"}:
         elif profile_id in {"211", "212", "213", "214"}:
-            q: int = 34 + 23 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -10 * self.oRanNearRtRicSpiralRadiusOfOCus - 1
+            q = 34 + 23 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -10 * self.oRanNearRtRicSpiralRadiusOfOCus - 1
         elif profile_id in {"221", "222", "223", "224"}:
         elif profile_id in {"221", "222", "223", "224"}:
-            q: int = 57 + 38 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -19 * self.oRanNearRtRicSpiralRadiusOfOCus
+            q = 57 + 38 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -19 * self.oRanNearRtRicSpiralRadiusOfOCus
         elif profile_id in {"231", "232", "233", "234"}:
         elif profile_id in {"231", "232", "233", "234"}:
-            q: int = 80 + 53 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -28 * self.oRanNearRtRicSpiralRadiusOfOCus - 1
+            q = 80 + 53 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -28 * self.oRanNearRtRicSpiralRadiusOfOCus - 1
         elif profile_id in {"241", "242", "243", "244"}:
         elif profile_id in {"241", "242", "243", "244"}:
-            q: int = 103 + 68 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -39 * self.oRanNearRtRicSpiralRadiusOfOCus + 2 * (
+            q = 103 + 68 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -39 * self.oRanNearRtRicSpiralRadiusOfOCus + 2 * (
                 self.oRanNearRtRicSpiralRadiusOfOCus - 1
             )
         elif profile_id in {"311", "312", "313", "314"}:
                 self.oRanNearRtRicSpiralRadiusOfOCus - 1
             )
         elif profile_id in {"311", "312", "313", "314"}:
-            q: int = 47 + 32 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -11 - 13 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            q = 47 + 32 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -11 - 13 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
         elif profile_id in {"321", "322", "323", "324"}:
         elif profile_id in {"321", "322", "323", "324"}:
-            q: int = 79 + 53 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -24 - 25 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            q = 79 + 53 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -24 - 25 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
         elif profile_id in {"331", "332", "333", "334"}:
         elif profile_id in {"331", "332", "333", "334"}:
-            q: int = 111 + 75 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
-            r: int = -37 - 37 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            q = 111 + 75 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
+            r = -37 - 37 * (self.oRanNearRtRicSpiralRadiusOfOCus - 1)
         else:
             # Handle the default case or raise a warning
             pass
         else:
             # Handle the default case or raise a warning
             pass
@@ -260,13 +273,14 @@ class SpiralRadiusProfile:
             Hex(-r, -s, -q),
         ]
 
             Hex(-r, -s, -q),
         ]
 
-    def oRanNearRtRicNeighbor(self, cube: Hex, direction: int):
+    def oRanNearRtRicNeighbor(self, cube: Hex, direction: int) -> Hex:
         return Hexagon.hex_add(cube, self.oRanNearRtRicDirections()[direction])
 
     def oRanNearRtRicRing(self, center: Hex, radius: int) -> list[Hex]:
         if not (radius > 0):
             raise ValueError(
         return Hexagon.hex_add(cube, self.oRanNearRtRicDirections()[direction])
 
     def oRanNearRtRicRing(self, center: Hex, radius: int) -> list[Hex]:
         if not (radius > 0):
             raise ValueError(
-                "Invalid radius. The radius around the hex center must be greater than 0 rings."
+                "Invalid radius. The radius around the hex center "
+                + "must be greater than 0 rings."
             )
 
         results: list[Hex] = []
             )
 
         results: list[Hex] = []
index 6aba16d..034c49a 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 An abstract Class for O-RAN TerminationPoint
 """
 
 """
 An abstract Class for O-RAN TerminationPoint
 """
-from abc import abstractmethod
+from typing import Any, cast
 
 from network_generation.model.python.o_ran_object import (
     IORanObject,
 
 from network_generation.model.python.o_ran_object import (
     IORanObject,
@@ -26,50 +26,94 @@ from network_generation.model.python.o_ran_object import (
 
 
 # Define the "IORanObject" interface
 
 
 # Define the "IORanObject" interface
-class IORanTerminationPointData(IORanObject):
-    def __init__(self, supporter: str = None, parent=None, **kwargs):
-        super().__init__(**kwargs)
-        self.supporter = supporter
-        self.parent = parent
-
-
-# Define an O-RAN Termination Point (ietf-interface, onf:logical-termination-point) class
-class ORanTerminationPoint(ORanObject, IORanTerminationPointData):
-    def __init__(self, tp: IORanTerminationPointData = None, **kwargs):
-        super().__init__(tp, **kwargs)
-        self.supporter = tp["supporter"] if tp and "supporter" in tp else None
-        self.parent = tp["parent"] if tp and "parent" in tp else None
-
-    def to_topology(self):
-        result: dict[str, dict] = {"tp-id": self.name}
-        if self.supporter:
-            network_ref: str = ""
-            match str(type(self.parent)):
-                case "<class 'model.python.o_ran_smo.ORanSmo'>":
-                    network_ref = self.parent.parent.id
-                case "<class 'model.python.o_ran_near_rt_ric.ORanNearRtRic'>":
-                    network_ref = self.parent.parent.parent.id
-                case "<class 'model.python.o_ran_cu.ORanCu'>":
-                    network_ref = self.parent.parent.parent.parent.id
-                case "<class 'model.python.o_ran_du.ORanDu'>":
-                    network_ref = self.parent.parent.parent.parent.parent.id
-                case "<class 'model.python.o_ran_cloud_du.ORanCloudDu'>":
-                    network_ref = self.parent.parent.parent.parent.parent.id
-                case "<class 'model.python.o_ran_ru.ORanRu'>":
-                    network_ref = (
-                        self.parent.parent.parent.parent.parent.parent.id
-                    )
-                case _:
-                    print("unknown: implement " + str(type(self.parent)))
-                    network_ref = "unknown: implement " + str(
-                        type(self.parent)
-                    )
-
-            result["supporting-termination-point"] = [
-                {
-                    "network-ref": network_ref,
-                    "node-ref": self.parent.name,
-                    "tp-ref": self.supporter,
-                }
-            ]
+class IORanTerminationPoint(IORanObject):
+    supporter: str
+    parent: Any
+
+
+default_value: IORanTerminationPoint = cast(
+    IORanTerminationPoint,
+    {
+        **ORanObject.default(),
+        **{
+            "supporter": "TerminationPointLayer",
+            "parent": None,
+        },
+    },
+)
+
+
+# Define an O-RAN Termination Point
+# (ietf-interface, onf:logical-termination-point) class
+class ORanTerminationPoint(ORanObject):
+    @staticmethod
+    def default() -> dict[str, Any]:
+        return cast(dict[str, Any], default_value)
+
+    def __init__(
+        self, data: dict[str, Any] = default(), **kwargs: dict[str, Any]
+    ) -> None:
+        itp: IORanTerminationPoint = self._to_itp_data(data)
+        super().__init__(cast(dict[str, Any], itp), **kwargs)
+        self._supporter: str = str(itp["supporter"])
+        self._parent: Any = itp["parent"]
+
+    def _to_itp_data(self, data: dict[str, Any]) -> IORanTerminationPoint:
+        result: IORanTerminationPoint = default_value
+        for key, key_type in IORanTerminationPoint.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
+    @property
+    def supporter(self) -> str:
+        return self._supporter
+
+    @supporter.setter
+    def supporter(self, value: str) -> None:
+        self._supporter = value
+
+    @property
+    def parent(self) -> Any:
+        return self._utilization
+
+    @parent.setter
+    def parent(self, value: Any) -> None:
+        self._parent = value
+
+    def to_topology(self) -> dict[str, Any]:
+        result: dict[str, Any] = {"tp-id": self.name}
+        # TODO
+        # if self.supporter:
+        #     network_ref: str = ""
+        #     match self.parent.__qualname__:
+        #         case ORanSmo.__qualname__:
+        #             network_ref = self.parent.parent.id
+        # case "<class 'model.python.o_ran_smo.ORanSmo'>":
+        #     network_ref = self.parent.parent.id
+        # case "<class 'model.python.o_ran_near_rt_ric.ORanNearRtRic'>":
+        #     network_ref = self.parent.parent.parent.id
+        # case "<class 'model.python.o_ran_cu.ORanCu'>":
+        #     network_ref = self.parent.parent.parent.parent.id
+        # case "<class 'model.python.o_ran_du.ORanDu'>":
+        #     network_ref = self.parent.parent.parent.parent.parent.id
+        # case "<class 'model.python.o_ran_cloud_du.ORanCloudDu'>":
+        #     network_ref = self.parent.parent.parent.parent.parent.id
+        # case "<class 'model.python.o_ran_ru.ORanRu'>":
+        #     network_ref = (
+        #         self.parent.parent.parent.parent.parent.parent.id
+        #     )
+        #     case _:
+        #         print("unknown: implement " + str(type(self.parent)))
+        #         network_ref = "unknown: implement " + str(
+        #             type(self.parent)
+        #         )
+
+        # result["supporting-termination-point"] = [
+        #     {
+        #         "network-ref": network_ref,
+        #         "node-ref": self.parent.name,
+        #         "tp-ref": self.supporter,
+        #     }
+        # ]
         return result
         return result
index 1a9b772..41cd8a0 100644 (file)
@@ -14,7 +14,7 @@
 #
 # inspired by http://www.redblobgames.com/grids/hexagons/
 
 #
 # inspired by http://www.redblobgames.com/grids/hexagons/
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 from __future__ import division, print_function
 
 
 from __future__ import division, print_function
 
index 5d6ac02..e68c615 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 An abstract Class for all classes
 """
 
 """
 An abstract Class for all classes
 """
-import uuid
-from abc import ABC
+from abc import ABC, abstractmethod
+from typing import Any, TypedDict, cast
 
 from network_generation.model.python.type_definitions import (
     AdministrativeState,
 
 from network_generation.model.python.type_definitions import (
     AdministrativeState,
@@ -31,70 +31,65 @@ from network_generation.model.python.type_definitions import (
 
 
 # Define the ITop interface
 
 
 # Define the ITop interface
-class ITop:
-    def __init__(
-        self,
-        id: str = None,
-        name: str = None,
-        administrativeState: AdministrativeState = None,
-        operationalState: OperationalState = None,
-        lifeCycleState: LifeCycleState = None,
-        alarmState: AlarmState = None,
-        usageState: UsageState = None,
-        utilization: Utilization = None,
-    ):
-        self.id = id
-        self.name = name
-        self.administrativeState = administrativeState
-        self.operationalState = operationalState
-        self.lifeCycleState = lifeCycleState
-        self.alarmState = alarmState
-        self.usageState = usageState
-        self.utilization = utilization
+class ITop(TypedDict):
+    id: str
+    name: str
+    administrativeState: AdministrativeState
+    operationalState: OperationalState
+    lifeCycleState: LifeCycleState
+    alarmState: AlarmState
+    usageState: UsageState
+    utilization: Utilization
+
+
+# define default value
+default_value: ITop = {
+    "id": "be5229af-2660-4bae-8f2c-b9d0f788fad1",
+    "name": "NoName",
+    "administrativeState": AdministrativeState.LOCKED,
+    "operationalState": OperationalState.DISABLED,
+    "lifeCycleState": LifeCycleState.PLANNED,
+    "alarmState": 0,
+    "usageState": UsageState.UNUSED,
+    "utilization": 0,
+}
 
 
 # Define the Top class
 
 
 # Define the Top class
-class Top(ABC, ITop):
-    def __init__(self, data: [dict[str, dict] | None] = None):
-        self._id = data["id"] if data and "id" in data else str(uuid.uuid4())
-        self._name = (
-            data["name"]
-            if data and "name" in data
-            else " ".join(["Name", "of", self._id])
-        )
-        self._administrativeState = (
-            data["administrativeState"]
-            if data and "administrativeState" in data
-            else AdministrativeState.LOCKED
-        )
-        self._operationalState = (
-            data["operationalState"]
-            if data and "operationalState" in data
-            else OperationalState.DISABLED
-        )
-        self._lifeCycleState = (
-            data["lifeCycleState"]
-            if data and "lifeCycleState" in data
-            else LifeCycleState.PLANNED
-        )
-        self._alarmState = (
-            data["alarmState"] if data and "alarmState" in data else 0
-        )
-        self._usageState = (
-            data["usageState"]
-            if data and "usageState" in data
-            else UsageState.UNUSED
-        )
-        self._utilization = (
-            data["utilization"] if data and "utilization" in data else 0
-        )
+class Top(ABC):
+    @staticmethod
+    def default() -> dict[str, Any]:
+        return cast(dict[str, Any], default_value)
+
+    def __init__(
+        self, data: dict[str, Any] = cast(dict[str, Any], default_value)
+    ) -> None:
+        super().__init__()
+        itop: ITop = self._to_itop_data(data)
+        self._id: str = itop["id"]
+        self._name: str = itop["name"]
+        self._administrativeState: AdministrativeState = itop[
+            "administrativeState"
+        ]
+        self._operationalState: OperationalState = itop["operationalState"]
+        self._lifeCycleState: LifeCycleState = itop["lifeCycleState"]
+        self._alarmState: AlarmState = itop["alarmState"]
+        self._usageState: UsageState = itop["usageState"]
+        self._utilization: Utilization = itop["utilization"]
+
+    def _to_itop_data(self, data: dict[str, Any]) -> ITop:
+        result: ITop = default_value
+        for key, key_type in ITop.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
 
     @property
     def id(self) -> str:
         return self._id
 
     @id.setter
 
     @property
     def id(self) -> str:
         return self._id
 
     @id.setter
-    def id(self, value: str):
+    def id(self, value: str) -> None:
         self._id = value
 
     @property
         self._id = value
 
     @property
@@ -102,7 +97,7 @@ class Top(ABC, ITop):
         return self._name
 
     @name.setter
         return self._name
 
     @name.setter
-    def name(self, value: str):
+    def name(self, value: str) -> None:
         self._name = value
 
     @property
         self._name = value
 
     @property
@@ -110,7 +105,7 @@ class Top(ABC, ITop):
         return self._administrativeState
 
     @administrativeState.setter
         return self._administrativeState
 
     @administrativeState.setter
-    def administrativeState(self, value: AdministrativeState):
+    def administrativeState(self, value: AdministrativeState) -> None:
         self._administrativeState = value
 
     @property
         self._administrativeState = value
 
     @property
@@ -118,7 +113,7 @@ class Top(ABC, ITop):
         return self._operationalState
 
     @operationalState.setter
         return self._operationalState
 
     @operationalState.setter
-    def operationalState(self, value: OperationalState):
+    def operationalState(self, value: OperationalState) -> None:
         self._operationalState = value
 
     @property
         self._operationalState = value
 
     @property
@@ -126,7 +121,7 @@ class Top(ABC, ITop):
         return self._lifeCycleState
 
     @lifeCycleState.setter
         return self._lifeCycleState
 
     @lifeCycleState.setter
-    def lifeCycleState(self, value: LifeCycleState):
+    def lifeCycleState(self, value: LifeCycleState) -> None:
         self._lifeCycleState = value
 
     @property
         self._lifeCycleState = value
 
     @property
@@ -134,7 +129,7 @@ class Top(ABC, ITop):
         return self._alarmState
 
     @alarmState.setter
         return self._alarmState
 
     @alarmState.setter
-    def alarmState(self, value: AlarmState):
+    def alarmState(self, value: AlarmState) -> None:
         self._alarmState = value
 
     @property
         self._alarmState = value
 
     @property
@@ -142,7 +137,7 @@ class Top(ABC, ITop):
         return self._usageState
 
     @usageState.setter
         return self._usageState
 
     @usageState.setter
-    def usageState(self, value: UsageState):
+    def usageState(self, value: UsageState) -> None:
         self._usageState = value
 
     @property
         self._usageState = value
 
     @property
@@ -150,18 +145,19 @@ class Top(ABC, ITop):
         return self._utilization
 
     @utilization.setter
         return self._utilization
 
     @utilization.setter
-    def utilization(self, value: Utilization):
+    def utilization(self, value: Utilization) -> None:
         self._utilization = value
 
         self._utilization = value
 
-    def json(self) -> dict[str, dict]:
+    @abstractmethod
+    def json(self) -> dict[str, Any]:
         return {
             "id": self.id,
             "name": self.name,
         return {
             "id": self.id,
             "name": self.name,
-            "administrativeState": self.administrativeState.value,
-            "operationalState": self.operationalState.value,
-            "lifeCycleState": self.lifeCycleState.value,
+            "administrativeState": self.administrativeState,
+            "operationalState": self.operationalState,
+            "lifeCycleState": self.lifeCycleState,
             "alarmState": self.alarmState,
             "alarmState": self.alarmState,
-            "usageState": self.usageState.value,
+            "usageState": self.usageState,
             "utilization": self.utilization,
         }
 
             "utilization": self.utilization,
         }
 
index d708d5e..d650ee0 100644 (file)
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A Class representing a Tower to mount O-RAN RUs
 
 """
 A Class representing a Tower to mount O-RAN RUs
@@ -20,10 +20,9 @@ It can be interpreted as 'resource pool' for physical network
 functions.
 """
 import xml.etree.ElementTree as ET
 functions.
 """
 import xml.etree.ElementTree as ET
-from typing import overload
+from typing import Any, cast
 
 
-from network_generation.model.python.o_ran_node import ORanNode
-from network_generation.model.python.o_ran_object import IORanObject
+from network_generation.model.python.o_ran_node import IORanNode, ORanNode
 from network_generation.model.python.o_ran_ru import ORanRu
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
 from network_generation.model.python.o_ran_ru import ORanRu
 from network_generation.model.python.o_ran_termination_point import (
     ORanTerminationPoint,
@@ -31,37 +30,58 @@ from network_generation.model.python.o_ran_termination_point import (
 
 
 # Define the "IORanDu" interface
 
 
 # Define the "IORanDu" interface
-class ITower(IORanObject):
-    def __init__(self, o_ran_ru_count: int, **kwargs):
-        super().__init__(**kwargs)
-        self._o_ran_ru_count = o_ran_ru_count
+class ITower(IORanNode):
+    o_ran_ru_count: int
+
+
+default_value: ITower = cast(
+    ITower,
+    {
+        **ORanNode.default(),
+        **{
+            "o_ran_ru_count": 1,
+        },
+    },
+)
 
 
 # Implement a concrete O-RAN Node class
 class Tower(ORanNode):
 
 
 # Implement a concrete O-RAN Node class
 class Tower(ORanNode):
-    def __init__(self, tower_data: ITower = None, **kwargs):
-        super().__init__(tower_data, **kwargs)
-        self._o_ran_ru_count = (
-            tower_data["oRanRuCount"]
+    def __init__(
+        self,
+        data: dict[str, Any] = cast(dict[str, Any], default_value),
+        **kwargs: dict[str, Any]
+    ) -> None:
+        tower_data: ITower = self._to_tower_data(data)
+        super().__init__(cast(dict[str, Any], tower_data), **kwargs)
+        self._o_ran_ru_count: int = (
+            int(str(tower_data["oRanRuCount"]))
             if tower_data and "oRanRuCount" in tower_data
             else 3
         )
         self._o_ran_rus: list[ORanRu] = self._create_o_ran_rus()
 
             if tower_data and "oRanRuCount" in tower_data
             else 3
         )
         self._o_ran_rus: list[ORanRu] = self._create_o_ran_rus()
 
+    def _to_tower_data(self, data: dict[str, Any]) -> ITower:
+        result: ITower = default_value
+        for key, key_type in ITower.__annotations__.items():
+            if key in data:
+                result[key] = data[key]  # type: ignore
+        return result
+
     def _create_o_ran_rus(self) -> list[ORanRu]:
         result: list[ORanRu] = []
         for index in range(self._o_ran_ru_count):
             s: str = "00" + str(index)
             name: str = "-".join(
     def _create_o_ran_rus(self) -> list[ORanRu]:
         result: list[ORanRu] = []
         for index in range(self._o_ran_ru_count):
             s: str = "00" + str(index)
             name: str = "-".join(
-                [self.name.replace("Tower", "RU"), s[len(s) - 2 : len(s)]]
+                [self.name.replace("Tower", "RU"), s[len(s) - 2: len(s)]]
             )
             cell_count: int = (
             )
             cell_count: int = (
-                self.parent.parent.parent.parent.parent.configuration()[
+                self.parent.parent.parent.parent.parent.configuration[
                     "pattern"
                 ]["o-ran-ru"]["nr-cell-du-count"]
             )
             cell_angle: int = (
                     "pattern"
                 ]["o-ran-ru"]["nr-cell-du-count"]
             )
             cell_angle: int = (
-                self.parent.parent.parent.parent.parent.configuration()[
+                self.parent.parent.parent.parent.parent.configuration[
                     "pattern"
                 ]["nr-cell-du"]["cell-angle"]
             )
                     "pattern"
                 ]["nr-cell-du"]["cell-angle"]
             )
@@ -71,10 +91,9 @@ class Tower(ORanNode):
                 ORanRu(
                     {
                         "name": name,
                 ORanRu(
                     {
                         "name": name,
-                        "geoLocation": self.geoLocation,
+                        "geoLocation": self.geo_location,
                         "position": self.position,
                         "layout": self.layout,
                         "position": self.position,
                         "layout": self.layout,
-                        "spiralRadiusProfile": self.spiralRadiusProfile,
                         "parent": self,
                         "cellCount": cell_count,
                         "ruAngle": ru_angle,
                         "parent": self,
                         "cellCount": cell_count,
                         "ruAngle": ru_angle,
@@ -88,36 +107,37 @@ class Tower(ORanNode):
     def o_ran_rus(self) -> list[ORanRu]:
         return self._o_ran_rus
 
     def o_ran_rus(self) -> list[ORanRu]:
         return self._o_ran_rus
 
-    @property
     def termination_points(self) -> list[ORanTerminationPoint]:
     def termination_points(self) -> list[ORanTerminationPoint]:
-        result: list[ORanTerminationPoint] = super().termination_points
+        result: list[ORanTerminationPoint] = super().termination_points()
         phy_tp: str = "-".join([self.name, "phy".upper()])
         phy_tp: str = "-".join([self.name, "phy".upper()])
-        result.append({"tp-id": phy_tp})
+        result.append(ORanTerminationPoint({"tp-id": phy_tp}))
         for interface in ["e2", "o1", "ofhm", "ofhc", "ofhu", "ofhs"]:
             result.append(
         for interface in ["e2", "o1", "ofhm", "ofhc", "ofhu", "ofhs"]:
             result.append(
-                {
-                    "tp-id": "-".join([self.name, interface.upper()]),
-                    "supporting-termination-point": [
-                        {
-                            "network-ref": type(
-                                self.parent.parent.parent.parent
-                            ),
-                            "node-ref": self.name,
-                            "tp-ref": phy_tp,
-                        }
-                    ],
-                }
+                ORanTerminationPoint(
+                    {
+                        "tp-id": "-".join([self.name, interface.upper()]),
+                        "supporting-termination-point": [
+                            {
+                                "network-ref": type(
+                                    self.parent.parent.parent.parent
+                                ),
+                                "node-ref": self.name,
+                                "tp-ref": phy_tp,
+                            }
+                        ],
+                    }
+                )
             )
         return result
 
             )
         return result
 
-    def to_topology_nodes(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_nodes()
+    def to_topology_nodes(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_nodes()
         for o_ran_ru in self.o_ran_rus:
             result.extend(o_ran_ru.to_topology_nodes())
         return result
 
         for o_ran_ru in self.o_ran_rus:
             result.extend(o_ran_ru.to_topology_nodes())
         return result
 
-    def to_topology_links(self) -> list[dict[str, dict]]:
-        result: list[dict[str, dict]] = super().to_topology_links()
+    def to_topology_links(self) -> list[dict[str, Any]]:
+        result: list[dict[str, Any]] = super().to_topology_links()
         for o_ran_ru in self.o_ran_rus:
             result.extend(o_ran_ru.to_topology_links())
         return result
         for o_ran_ru in self.o_ran_rus:
             result.extend(o_ran_ru.to_topology_links())
         return result
@@ -132,5 +152,5 @@ class Tower(ORanNode):
             tower.append(o_ran_ru.toKml())
         return tower
 
             tower.append(o_ran_ru.toKml())
         return tower
 
-    def toSvg(self) -> None:
-        return None
+    def toSvg(self) -> ET.Element:
+        return ET.Element("to-be-implemented")
index 1430c3c..9dc0c8a 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 
 """
 A collection of TypeDefinitions
 """
 from enum import Enum
 
 """
 A collection of TypeDefinitions
 """
 from enum import Enum
+from typing import TypedDict
 
 from network_generation.model.python.countries import Country
 
 
 from network_generation.model.python.countries import Country
 
+# from typing import Any, TypedDict, TypeVar
+
+
+# from network_generation.model.python.o_ran_node import IORanNode
+# from network_generation.model.python.o_ran_object import IORanObject
+# from network_generation.model.python.top import ITop
+
+# Generic Types based on inheritance
+# IORanType = TypeVar("IORanType", ITop, IORanObject, IORanNode)
+
 
 # Define AdministrativeState enum
 class AdministrativeState(Enum):
 
 # Define AdministrativeState enum
 class AdministrativeState(Enum):
@@ -32,16 +43,16 @@ class AdministrativeState(Enum):
 # Define AlarmState type
 AlarmState = int
 
 # Define AlarmState type
 AlarmState = int
 
+
 # Define Address type
 # Define Address type
-AddressType = {
-    "street": str,
-    "building": str,
-    "room": str,
-    "city": str,
-    "zip": str,
-    "state": str,
-    "country": Country,
-}
+class AddressType(TypedDict):
+    street: str
+    building: str
+    room: str
+    city: str
+    zip: str
+    state: str
+    country: Country
 
 
 # Define OperationalState enum
 
 
 # Define OperationalState enum
@@ -66,20 +77,4 @@ class UsageState(Enum):
     UNUSED = "unused"
 
 
     UNUSED = "unused"
 
 
-# Define Enumerate type
-def Enumerate(N, Acc=None):
-    if Acc is None:
-        Acc = []
-    if len(Acc) == N:
-        return Acc[-1]
-    return Enumerate(N, Acc + [len(Acc)])
-
-
-# Define Range type
-def Range(F, T) -> list[int]:
-    return [i for i in range(F, T + 1)]
-
-
-# Define Procent and Utilization types
-Procent = Range(0, 100)
-Utilization = Procent
+Utilization = int
index 2c47299..4c1dabe 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 """
 Module containing a class for parameter validation
 """
 import json
 import os
 import os.path
 """
 Module containing a class for parameter validation
 """
 import json
 import os
 import os.path
+from typing import Any
 
 import jsonschema
 
 
 import jsonschema
 
@@ -39,9 +40,8 @@ class ParameterValidator:
     __is_valid: bool = False
 
     # constructor
     __is_valid: bool = False
 
     # constructor
-    def __init__(self, args):
+    def __init__(self, args: list[str]) -> None:
         self.args = args
         self.args = args
-
         if len(self.args) > 1:
             self.__config_file = args[1]
 
         if len(self.args) > 1:
             self.__config_file = args[1]
 
@@ -83,15 +83,17 @@ class ParameterValidator:
 
     def error_message(self) -> str:
         """
 
     def error_message(self) -> str:
         """
-        Getter for the error message after validation process or an empty sting,
-        when configuration is valid.
+        Getter for the error message after validation process or an
+        empty sting,  when configuration is valid.
         :return Error message as string.
         """
         return self.__error_message
 
     # private
 
         :return Error message as string.
         """
         return self.__error_message
 
     # private
 
-    def __is_json_valid(self, json_data, json_schema) -> bool:
+    def __is_json_valid(
+        self, json_data: dict[str, Any], json_schema: dict[str, Any]
+    ) -> bool:
         """
         Method validating json against a schema
         """
         """
         Method validating json against a schema
         """
index 54ba84f..fd8c4fa 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#!/usr/bin/python
+# !/usr/bin/python
 """
 Provides functions to convert the Network into different formats
 """
 
 import json
 import xml.etree.ElementTree as ET
 """
 Provides functions to convert the Network into different formats
 """
 
 import json
 import xml.etree.ElementTree as ET
+from typing import Any
 
 from network_generation.model.python.o_ran_network import ORanNetwork
 
 
 class NetworkViewer:
     """
 
 from network_generation.model.python.o_ran_network import ORanNetwork
 
 
 class NetworkViewer:
     """
-    This class contains all functions converting the Network into different formats
+    This class contains all functions converting the Network into
+    different formats
     """
 
     """
 
-    __network: ORanNetwork = None
-
     # constructor
     # constructor
-    def __init__(self, network: ORanNetwork):
+    def __init__(self, network: ORanNetwork) -> None:
         self.__network = network
 
     # json format
         self.__network = network
 
     # json format
@@ -43,7 +43,7 @@ class NetworkViewer:
         """
         return self
 
         """
         return self
 
-    def show_as_json(self) -> dict[str, dict]:
+    def show_as_json(self) -> None:
         """
         Method printing the class in json format.
         """
         """
         Method printing the class in json format.
         """
@@ -62,7 +62,7 @@ class NetworkViewer:
         :type filename: string
         """
         with open(filename, "w", encoding="utf-8") as json_file:
         :type filename: string
         """
         with open(filename, "w", encoding="utf-8") as json_file:
-            output: dict[str, dict] = self.__network.to_topology()
+            output: dict[str, Any] = self.__network.to_topology()
             json.dump(output, json_file, ensure_ascii=False, indent=2)
             print("File '" + filename + "' saved!")
 
             json.dump(output, json_file, ensure_ascii=False, indent=2)
             print("File '" + filename + "' saved!")
 
@@ -106,12 +106,12 @@ class NetworkViewer:
                 style = ET.Element("Style", {"id": key})
                 line_style = ET.SubElement(style, "LineStyle")
                 color = ET.SubElement(line_style, "color")
                 style = ET.Element("Style", {"id": key})
                 line_style = ET.SubElement(style, "LineStyle")
                 color = ET.SubElement(line_style, "color")
-                color.text = value["stroke"]["color"]
+                color.text = str(value["stroke"]["color"])
                 width = ET.SubElement(line_style, "width")
                 width = ET.SubElement(line_style, "width")
-                width.text = value["stroke"]["width"]
+                width.text = str(value["stroke"]["width"])
                 poly_style = ET.SubElement(style, "PolyStyle")
                 fill = ET.SubElement(poly_style, "color")
                 poly_style = ET.SubElement(style, "PolyStyle")
                 fill = ET.SubElement(poly_style, "color")
-                fill.text = value["fill"]["color"]
+                fill.text = str(value["fill"]["color"])
                 root.findall(".//Document")[0].append(style)
 
         ET.ElementTree(root).write(
                 root.findall(".//Document")[0].append(style)
 
         ET.ElementTree(root).write(