__configuration: dict = {}
# constructor
- def __init__(self, configuration: dict):
+ def __init__(self, configuration: dict) -> None:
self.__configuration = configuration
# getters
# 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
+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
+"""
+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`.
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.
os.makedirs(output_folder)
name: str = configuration["network"]["name"]
+ filename: str = ""
# 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:
- filename: str = output_folder + "/" + name + ".svg"
+ filename = output_folder + "/" + name + ".svg"
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:
# 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
#
# inspired by http://www.redblobgames.com/grids/hexagons/
-#!/usr/bin/python
+# !/usr/bin/python
from network_generation.model.python.hexagon import Hex
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]
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))
# 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
+from typing import Any, TypedDict, cast
+
+from typing_extensions import Required
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
- 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:
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):
+ 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(
- "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."
)
- self.longitude = value
+ self._aboveMeanSeaLevel = value
def json(self) -> dict[str, float]:
return {
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.
"""
- equatorialRadius = 6378137 # meters
- new_lat = self.latitude + (point.y / equatorialRadius) * (
+ new_lat = self.latitude + (point.y / self.equatorialRadius) * (
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)
- geo_location: IGeoLocationData = {
+ geo_location: IGeoLocation = {
"longitude": new_lon,
"latitude": new_lat,
"aboveMeanSeaLevel": self.aboveMeanSeaLevel,
#
# inspired by http://www.redblobgames.com/grids/hexagons/
-#!/usr/bin/python
+# !/usr/bin/python
from __future__ import division, print_function
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
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)
-def hex_rotate_right(a) -> Hex:
+def hex_rotate_right(a: Hex) -> Hex:
return Hex(-a.r, -a.s, -a.q)
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
-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:
- 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)
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(
- 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
ODD: int = -1
-def qoffset_from_cube(offset: int, hex: Hex) -> OffsetCoord:
+def qoffset_from_cube(offset: float, hex: Hex) -> OffsetCoord:
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)
-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)
-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)
-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:
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)
-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)
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)
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)
# 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
-from typing import overload
+from typing import Any, cast
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,
)
# 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
-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]:
- result: list[ORanTerminationPoint] = super().termination_points
+ result: list[ORanTerminationPoint] = super().termination_points()
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
- result: list[dict[str, dict]] = [] # super().to_topology_nodes()
+ result: list[dict[str, Any]] = [] # super().to_topology_nodes()
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
- 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:
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)
- 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(
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)
# 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
- def toSvg(self) -> None:
- return None
+ def toSvg(self) -> ET.Element:
+ return ET.Element("to-be-implemented")
# 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.
-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
-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
+from network_generation.model.python.geo_location import GeoLocation
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
-
# Define the "IORanDu" interface
-class IORanCloudDu(IORanObject):
- def __init__(self, **kwargs):
- super().__init__(**kwargs)
+IORanCloudDu = IORanNode
# 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()
+ 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 = (
- 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] = []
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()
"geoLocation": newGeo,
"position": hex,
"layout": self.layout,
- "spiralRadiusProfile": self.spiralRadiusProfile,
"parent": self,
}
)
def towers(self) -> list[Tower]:
return self._towers
- @property
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"]:
)
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
- 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
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")
# 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
-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
+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.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
-
# Define the "IORanCu" interface
-class IORanCu(IORanObject):
- def __init__(self, **kwargs):
- super().__init__(**kwargs)
+IORanCu = IORanNode
# 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 = (
- 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.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()
"geoLocation": newGeo,
"position": hex,
"layout": self.layout,
- "spiralRadiusProfile": self.spiralRadiusProfile,
"parent": self,
}
)
result.append(tower)
return result
- @property
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({"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(
)
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
- 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:
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")
# 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
-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
-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
-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
)
- @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]:
- 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"]:
)
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
- 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]
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
- def toSvg(self) -> None:
- return None
+ def toSvg(self) -> ET.Element:
+ return ET.Element("to-be-implemented")
# 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
-from typing import overload
+from typing import Any, cast
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.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
-
# Define the "IORanNearRtRic" interface
-class IORanNearRtRic(IORanObject):
- def __init__(self, **kwargs):
- super().__init__(**kwargs)
+IORanNearRtRic = IORanNode
# Define an abstract O-RAN Node class
-class ORanNearRtRic(ORanNode, IORanNearRtRic):
+class ORanNearRtRic(ORanNode):
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()
+ 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 = (
- 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.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()
"geoLocation": newGeo,
"position": hex,
"layout": self.layout,
- "spiralRadiusProfile": self.spiralRadiusProfile,
"parent": self,
}
)
result.append(tower)
return result
- @property
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({"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(
)
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
- 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
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")
# 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
+from typing import Any, cast
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.point import Point
+# Define the "IORanNetwork" interface
+IORanNetwork = IORanObject
+
class ORanNetwork(ORanObject):
"""
Class representing an O-RAN Network object.
"""
+ __my_default_value: IORanNetwork = cast(IORanNetwork, ORanObject.default())
+
# 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.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
- spiral_radius_profile = SpiralRadiusProfile(
+ self._spiral_radius_profile: SpiralRadiusProfile = SpiralRadiusProfile(
{
"oRanSmoSpiralRadiusOfNearRtRics": configuration["pattern"][
"smo"
"name": "O-RAN-SMO",
"geoLocation": self.center,
"layout": layout,
- "spiralRadiusProfile": spiral_radius_profile,
"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
- 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": [
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")
- title.text = self.configuration()["name"]
+ title.text = str(self.configuration["name"])
root.append(title)
# root.append(self.__context.svg(x, y))
return root
+
+ def json(self) -> dict[str, Any]:
+ return super().json()
# 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
"""
-import json
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
+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 (
# 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
-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] = []
+ 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
- def address(self) -> str:
+ def address(self) -> AddressType:
return self._address
@address.setter
- def address(self, value: str):
+ def address(self, value: AddressType) -> None:
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
- def url(self, value: str):
+ def url(self, value: str) -> None:
self._url = value
@property
return self._position
@position.setter
- def position(self, value: Hex):
+ def position(self, value: Hex) -> None:
self._position = value
@property
return self._layout
@layout.setter
- def layout(self, value: Layout):
+ def layout(self, value: Layout) -> None:
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(
return self._parent
@parent.setter
- def parent(self, value: Any):
+ def parent(self, value: Any) -> None:
self._parent = value
- @abstractproperty
+ # @property
+ # @abstractmethod
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
- 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))
- == "<class 'model.python.o_ran_termination_point.ORanTerminationPoint'>"
+ == "<class 'model.python.o_ran_termination_point"
+ + ".ORanTerminationPoint'>"
):
tps.append(tp.to_topology())
- result: list[dict[str, dict]] = []
+ result: list[dict[str, Any]] = []
result.append(
{
"node-id": self.name,
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()])
- 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]
)
pass
@abstractmethod
- def toSvg(self) -> ET.Element | None:
+ def toSvg(self) -> ET.Element:
pass
# 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
"""
-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
-class IORanObject(ITop):
- def __init__(self, **kwargs):
- super().__init__(**kwargs)
+# class IORanObject(ITop):
+IORanObject = ITop
# 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,
+ }
# 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
-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.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
-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
-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
)
- 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
)
- 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")
- 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 = (
- 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(
- [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,
- "geoLocation": self.geoLocation,
+ "geoLocation": self.geo_location,
"position": self.position,
"layout": self.layout,
- "spiralRadiusProfile": self.spiralRadiusProfile,
"parent": self,
"cellAngle": cell_angle,
"azimuth": azimuth,
def oRanDu(self) -> ORanDu:
return self._oRanDu
- @property
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"]:
)
)
for cell in self.cells:
- result.extend(cell.termination_points)
+ result.extend(cell.termination_points())
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
- 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(
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")
# 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
-from typing import overload
+from typing import Any, cast
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.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
-
# Define the "IORanSmo" interface
-class IORanSmo(IORanObject):
- def __init__(self, **kwargs):
- super().__init__(**kwargs)
+IORanSmo = IORanNode
# 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 = (
- 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.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()
"geoLocation": newGeo,
"position": hex,
"layout": self.layout,
- "spiralRadiusProfile": self.spiralRadiusProfile,
"parent": self,
- }
+ },
)
)
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
+ 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]:
- 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(
- {"id": id, "name": id, "supporter": phy_tp, "parent": self}
+ {
+ "id": id,
+ "name": id,
+ "supporter": phy_tp,
+ "parent": self,
+ },
)
)
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
- 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
smo.append(ric.toKml())
return smo
- def toSvg(self) -> None:
- return None
+ def toSvg(self) -> ET.Element:
+ return ET.Element("not-implemented-yet-TODO")
# 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
-from network_generation.model.python.cube import Cube
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._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:
- 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:
return self._oRanSmoSpiralRadiusOfNearRtRics
@oRanSmoSpiralRadiusOfNearRtRics.setter
- def oRanSmoSpiralRadiusOfNearRtRics(self, value: int):
+ def oRanSmoSpiralRadiusOfNearRtRics(self, value: int) -> None:
self._oRanSmoSpiralRadiusOfNearRtRics = value
@property
return self._oRanNearRtRicSpiralRadiusOfOCus
@oRanNearRtRicSpiralRadiusOfOCus.setter
- def oRanNearRtRicSpiralRadiusOfOCus(self, value: int):
+ def oRanNearRtRicSpiralRadiusOfOCus(self, value: int) -> None:
self._oRanNearRtRicSpiralRadiusOfOCus = value
@property
return self._oRanCuSpiralRadiusOfODus
@oRanCuSpiralRadiusOfODus.setter
- def oRanCuSpiralRadiusOfODus(self, value: int):
+ def oRanCuSpiralRadiusOfODus(self, value: int) -> None:
self._oRanCuSpiralRadiusOfODus = value
@property
return self._oRanDuSpiralRadiusOfTowers
@oRanDuSpiralRadiusOfTowers.setter
- def oRanDuSpiralRadiusOfTowers(self, value: int):
+ def oRanDuSpiralRadiusOfTowers(self, value: int) -> None:
self._oRanDuSpiralRadiusOfTowers = value
@property
return self._sectors
@sectors.setter
- def sectors(self, value: int):
+ def sectors(self, value: int) -> None:
self._sectors = value
@property
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
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(
- "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(
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])
- def oRanCuRing(self, center: Hex, radius: int):
+ def oRanCuRing(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] = []
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"}:
- 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"}:
- 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"}:
- 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":
- q: int = 74
- r: int = 37
+ q = 74
+ r = 37
elif profile_id == "134":
- q: int = 93
- r: int = 50
+ q = 93
+ r = 50
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"}:
- 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"}:
- 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"}:
- 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"}:
- 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"}:
- 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"}:
- 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
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(
- "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] = []
# 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
"""
-from abc import abstractmethod
+from typing import Any, cast
from network_generation.model.python.o_ran_object import (
IORanObject,
# 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
#
# inspired by http://www.redblobgames.com/grids/hexagons/
-#!/usr/bin/python
+# !/usr/bin/python
from __future__ import division, print_function
# 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
"""
-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,
# 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
-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
- def id(self, value: str):
+ def id(self, value: str) -> None:
self._id = value
@property
return self._name
@name.setter
- def name(self, value: str):
+ def name(self, value: str) -> None:
self._name = value
@property
return self._administrativeState
@administrativeState.setter
- def administrativeState(self, value: AdministrativeState):
+ def administrativeState(self, value: AdministrativeState) -> None:
self._administrativeState = value
@property
return self._operationalState
@operationalState.setter
- def operationalState(self, value: OperationalState):
+ def operationalState(self, value: OperationalState) -> None:
self._operationalState = value
@property
return self._lifeCycleState
@lifeCycleState.setter
- def lifeCycleState(self, value: LifeCycleState):
+ def lifeCycleState(self, value: LifeCycleState) -> None:
self._lifeCycleState = value
@property
return self._alarmState
@alarmState.setter
- def alarmState(self, value: AlarmState):
+ def alarmState(self, value: AlarmState) -> None:
self._alarmState = value
@property
return self._usageState
@usageState.setter
- def usageState(self, value: UsageState):
+ def usageState(self, value: UsageState) -> None:
self._usageState = value
@property
return self._utilization
@utilization.setter
- def utilization(self, value: Utilization):
+ def utilization(self, value: Utilization) -> None:
self._utilization = value
- def json(self) -> dict[str, dict]:
+ @abstractmethod
+ def json(self) -> dict[str, Any]:
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,
- "usageState": self.usageState.value,
+ "usageState": self.usageState,
"utilization": self.utilization,
}
# 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
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,
# 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):
- 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()
+ 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(
- [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 = (
- 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 = (
- self.parent.parent.parent.parent.parent.configuration()[
+ self.parent.parent.parent.parent.parent.configuration[
"pattern"
]["nr-cell-du"]["cell-angle"]
)
ORanRu(
{
"name": name,
- "geoLocation": self.geoLocation,
+ "geoLocation": self.geo_location,
"position": self.position,
"layout": self.layout,
- "spiralRadiusProfile": self.spiralRadiusProfile,
"parent": self,
"cellCount": cell_count,
"ruAngle": ru_angle,
def o_ran_rus(self) -> list[ORanRu]:
return self._o_ran_rus
- @property
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({"tp-id": phy_tp})
+ result.append(ORanTerminationPoint({"tp-id": phy_tp}))
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
- 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
- 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
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")
# 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
+from typing import TypedDict
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 AlarmState type
AlarmState = int
+
# 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
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
# 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
+from typing import Any
import jsonschema
__is_valid: bool = False
# constructor
- def __init__(self, args):
+ def __init__(self, args: list[str]) -> None:
self.args = args
-
if len(self.args) > 1:
self.__config_file = args[1]
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
- 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
"""
# 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
+from typing import Any
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
- def __init__(self, network: ORanNetwork):
+ def __init__(self, network: ORanNetwork) -> None:
self.__network = network
# json format
"""
return self
- def show_as_json(self) -> dict[str, dict]:
+ def show_as_json(self) -> None:
"""
Method printing the class in json format.
"""
: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!")
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.text = value["stroke"]["width"]
+ width.text = str(value["stroke"]["width"])
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(