DavMelchi commited on
Commit
50e9987
·
1 Parent(s): cc3d5fb

Add IPADDRESSV4 export and update data assets

Browse files
apps/sector_kml_generator.py CHANGED
@@ -182,7 +182,7 @@ def _show_site_position_map(
182
  fig = go.Figure()
183
  mode = "markers+text" if show_labels else "markers"
184
  fig.add_trace(
185
- go.Scattermapbox(
186
  lat=map_df[lat_col],
187
  lon=map_df[lon_col],
188
  mode=mode,
@@ -197,12 +197,12 @@ def _show_site_position_map(
197
 
198
  fig.update_layout(
199
  title=title,
200
- mapbox_style="open-street-map",
201
- mapbox_center={
202
  "lat": float(map_df[lat_col].mean()),
203
  "lon": float(map_df[lon_col].mean()),
204
  },
205
- mapbox_zoom=_estimate_zoom(map_df, lat_col, lon_col),
206
  height=620,
207
  margin={"r": 0, "t": 45, "l": 0, "b": 0},
208
  )
@@ -234,7 +234,7 @@ def _show_sector_map(df: pd.DataFrame, show_labels: bool = True) -> None:
234
  lats = [coord[1] for coord in coords]
235
  rgba = kml_color_to_rgba(row["color"])
236
  fig.add_trace(
237
- go.Scattermapbox(
238
  lon=lons,
239
  lat=lats,
240
  mode="lines",
@@ -251,7 +251,7 @@ def _show_sector_map(df: pd.DataFrame, show_labels: bool = True) -> None:
251
  site_df = map_df.drop_duplicates(subset=["code"]).copy()
252
  mode = "markers+text" if show_labels else "markers"
253
  fig.add_trace(
254
- go.Scattermapbox(
255
  lat=site_df["Latitude"],
256
  lon=site_df["Longitude"],
257
  mode=mode,
@@ -266,12 +266,12 @@ def _show_sector_map(df: pd.DataFrame, show_labels: bool = True) -> None:
266
 
267
  fig.update_layout(
268
  title="Sector map preview",
269
- mapbox_style="open-street-map",
270
- mapbox_center={
271
  "lat": float(map_df["Latitude"].mean()),
272
  "lon": float(map_df["Longitude"].mean()),
273
  },
274
- mapbox_zoom=_estimate_zoom(map_df, "Latitude", "Longitude"),
275
  height=650,
276
  margin={"r": 0, "t": 45, "l": 0, "b": 0},
277
  )
 
182
  fig = go.Figure()
183
  mode = "markers+text" if show_labels else "markers"
184
  fig.add_trace(
185
+ go.Scattermap(
186
  lat=map_df[lat_col],
187
  lon=map_df[lon_col],
188
  mode=mode,
 
197
 
198
  fig.update_layout(
199
  title=title,
200
+ map_style="open-street-map",
201
+ map_center={
202
  "lat": float(map_df[lat_col].mean()),
203
  "lon": float(map_df[lon_col].mean()),
204
  },
205
+ map_zoom=_estimate_zoom(map_df, lat_col, lon_col),
206
  height=620,
207
  margin={"r": 0, "t": 45, "l": 0, "b": 0},
208
  )
 
234
  lats = [coord[1] for coord in coords]
235
  rgba = kml_color_to_rgba(row["color"])
236
  fig.add_trace(
237
+ go.Scattermap(
238
  lon=lons,
239
  lat=lats,
240
  mode="lines",
 
251
  site_df = map_df.drop_duplicates(subset=["code"]).copy()
252
  mode = "markers+text" if show_labels else "markers"
253
  fig.add_trace(
254
+ go.Scattermap(
255
  lat=site_df["Latitude"],
256
  lon=site_df["Longitude"],
257
  mode=mode,
 
266
 
267
  fig.update_layout(
268
  title="Sector map preview",
269
+ map_style="open-street-map",
270
+ map_center={
271
  "lat": float(map_df["Latitude"].mean()),
272
  "lon": float(map_df["Longitude"].mean()),
273
  },
274
+ map_zoom=_estimate_zoom(map_df, "Latitude", "Longitude"),
275
  height=650,
276
  margin={"r": 0, "t": 45, "l": 0, "b": 0},
277
  )
data/kpi_health_check_profiles/Profil_1.json CHANGED
@@ -1,7 +1,8 @@
1
  {
2
- "name": "Profil_1",
3
- "saved_at": "2025-12-13T13:16:45.937845Z",
4
  "config": {
 
5
  "analysis_range": [
6
  null,
7
  null
@@ -10,23 +11,31 @@
10
  "recent_days": 7,
11
  "rel_threshold_pct": 10.0,
12
  "min_consecutive_days": 3,
 
13
  "min_criticality": 0,
14
  "min_anomaly_score": 0,
15
  "city_filter": "",
16
  "top_rat_filter": [
17
  "2G",
18
  "3G",
19
- "LTE"
 
20
  ],
21
  "top_status_filter": [
22
  "DEGRADED",
23
  "PERSISTENT_DEGRADED"
24
  ],
25
- "preset_selected": "presets_1.json",
26
  "drilldown": {
27
- "site_code": 2130,
28
  "rat": "LTE",
29
- "kpi": ""
 
 
 
 
 
 
 
30
  }
31
  }
32
  }
 
1
  {
2
+ "name": "profil_1",
3
+ "saved_at": "2026-03-30T10:24:07.600473Z",
4
  "config": {
5
+ "granularity": "Hourly",
6
  "analysis_range": [
7
  null,
8
  null
 
11
  "recent_days": 7,
12
  "rel_threshold_pct": 10.0,
13
  "min_consecutive_days": 3,
14
+ "only_complaint_sites": false,
15
  "min_criticality": 0,
16
  "min_anomaly_score": 0,
17
  "city_filter": "",
18
  "top_rat_filter": [
19
  "2G",
20
  "3G",
21
+ "LTE",
22
+ "TWAMP"
23
  ],
24
  "top_status_filter": [
25
  "DEGRADED",
26
  "PERSISTENT_DEGRADED"
27
  ],
28
+ "preset_selected": "presets_1",
29
  "drilldown": {
 
30
  "rat": "LTE",
31
+ "site_value": "",
32
+ "kpi_group": "All (selected KPIs)",
33
+ "kpi_group_mode": "",
34
+ "kpi": "% MIMO RI 2",
35
+ "compare_kpis": [],
36
+ "compare_norm": "None",
37
+ "show_sla": true,
38
+ "corr_window": "Recent"
39
  }
40
  }
41
  }
physical_db/physical_database.csv CHANGED
The diff for this file is too large to render. See raw diff
 
queries/process_all_db.py CHANGED
@@ -1,6 +1,7 @@
1
  from queries.process_atoll_db import process_data_for_atoll
2
  from queries.process_gsm import combined_gsm_database, gsm_analaysis
3
  from queries.process_invunit import process_invunit_data, process_invunit_number_data
 
4
  from queries.process_lte import lte_fdd_analaysis, lte_tdd_analaysis, process_lte_data
5
  from queries.process_mrbts import process_mrbts_data
6
  from queries.process_nice_db import process_data_for_nice
@@ -33,21 +34,11 @@ def all_dbs(filepath: str):
33
  def process_all_tech_db(filepath: str):
34
  all_dbs(filepath)
35
  site_db()
 
36
 
37
  UtilsVars.final_all_database = convert_database_dfs(
38
  UtilsVars.all_db_dfs,
39
- [
40
- "GSM",
41
- "MAL",
42
- "TRX",
43
- "WCDMA",
44
- "LTE_FDD",
45
- "LTE_TDD",
46
- "MRBTS",
47
- "INVUNIT",
48
- "INVUNIT_NUMBER",
49
- "SITE",
50
- ],
51
  )
52
 
53
 
@@ -64,20 +55,10 @@ def process_all_tech_db_with_stats(
64
  )
65
  lte_fdd_analaysis(filepath)
66
  lte_tdd_analaysis(filepath)
 
67
  UtilsVars.final_all_database = convert_database_dfs(
68
  UtilsVars.all_db_dfs,
69
- [
70
- "GSM",
71
- "MAL",
72
- "TRX",
73
- "WCDMA",
74
- "LTE_FDD",
75
- "LTE_TDD",
76
- "MRBTS",
77
- "INVUNIT",
78
- "INVUNIT_NUMBER",
79
- "SITE",
80
- ],
81
  )
82
 
83
 
 
1
  from queries.process_atoll_db import process_data_for_atoll
2
  from queries.process_gsm import combined_gsm_database, gsm_analaysis
3
  from queries.process_invunit import process_invunit_data, process_invunit_number_data
4
+ from queries.process_ipaddressv4 import process_ipaddressv4_data
5
  from queries.process_lte import lte_fdd_analaysis, lte_tdd_analaysis, process_lte_data
6
  from queries.process_mrbts import process_mrbts_data
7
  from queries.process_nice_db import process_data_for_nice
 
34
  def process_all_tech_db(filepath: str):
35
  all_dbs(filepath)
36
  site_db()
37
+ process_ipaddressv4_data(filepath)
38
 
39
  UtilsVars.final_all_database = convert_database_dfs(
40
  UtilsVars.all_db_dfs,
41
+ UtilsVars.all_db_dfs_names,
 
 
 
 
 
 
 
 
 
 
 
42
  )
43
 
44
 
 
55
  )
56
  lte_fdd_analaysis(filepath)
57
  lte_tdd_analaysis(filepath)
58
+ process_ipaddressv4_data(filepath)
59
  UtilsVars.final_all_database = convert_database_dfs(
60
  UtilsVars.all_db_dfs,
61
+ UtilsVars.all_db_dfs_names,
 
 
 
 
 
 
 
 
 
 
 
62
  )
63
 
64
 
queries/process_ipaddressv4.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ from utils.dump_excel import read_dump_excel
4
+ from utils.utils_vars import UtilsVars
5
+
6
+ IPADDRESSV4_SHEET_NAME = "IPADDRESSV4"
7
+ IPADDRESSV4_COLUMNS = ["MRBTS", "localIpAddr"]
8
+
9
+
10
+ def _sheet_exists(file_path, sheet_name: str) -> bool:
11
+ if hasattr(file_path, "seek"):
12
+ file_path.seek(0)
13
+
14
+ with pd.ExcelFile(file_path, engine="calamine") as workbook:
15
+ exists = sheet_name in workbook.sheet_names
16
+
17
+ if hasattr(file_path, "seek"):
18
+ file_path.seek(0)
19
+
20
+ return exists
21
+
22
+
23
+ def _normalize_mrbts(series: pd.Series) -> pd.Series:
24
+ normalized = series.astype("string").str.strip()
25
+ return normalized.str.replace(r"\.0+$", "", regex=True)
26
+
27
+
28
+ def process_ipaddressv4_data(file_path: str) -> pd.DataFrame:
29
+ if not _sheet_exists(file_path, IPADDRESSV4_SHEET_NAME):
30
+ return pd.DataFrame(columns=IPADDRESSV4_COLUMNS)
31
+
32
+ dfs = read_dump_excel(
33
+ file_path,
34
+ sheet_name=[IPADDRESSV4_SHEET_NAME],
35
+ expected_columns=IPADDRESSV4_COLUMNS,
36
+ )
37
+ df_ipaddressv4 = dfs[IPADDRESSV4_SHEET_NAME].copy()
38
+ df_ipaddressv4.columns = df_ipaddressv4.columns.str.replace(r"[ ]", "", regex=True)
39
+
40
+ missing_columns = [
41
+ column for column in IPADDRESSV4_COLUMNS if column not in df_ipaddressv4.columns
42
+ ]
43
+ if missing_columns:
44
+ raise ValueError(
45
+ "IPADDRESSV4 sheet is missing required columns: "
46
+ + ", ".join(missing_columns)
47
+ )
48
+
49
+ df_ipaddressv4 = df_ipaddressv4[IPADDRESSV4_COLUMNS].copy()
50
+ df_ipaddressv4["MRBTS"] = _normalize_mrbts(df_ipaddressv4["MRBTS"])
51
+ df_ipaddressv4["localIpAddr"] = (
52
+ df_ipaddressv4["localIpAddr"].astype("string").str.strip()
53
+ )
54
+
55
+ UtilsVars.all_db_dfs.append(df_ipaddressv4)
56
+ UtilsVars.all_db_dfs_names.append(IPADDRESSV4_SHEET_NAME)
57
+ return df_ipaddressv4
tests/test_process_ipaddressv4.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import pytest
3
+
4
+ from queries.process_ipaddressv4 import process_ipaddressv4_data
5
+ from utils.utils_vars import UtilsVars
6
+
7
+
8
+ def setup_function():
9
+ UtilsVars.all_db_dfs = []
10
+ UtilsVars.all_db_dfs_names = []
11
+
12
+
13
+ def test_process_ipaddressv4_data_keeps_only_mrbts_and_local_ip(monkeypatch):
14
+ dump_dfs = {
15
+ "IPADDRESSV4": pd.DataFrame(
16
+ {
17
+ " MRBTS ": [" 12345.0 ", "67890"],
18
+ "local Ip Addr": [" 10.1.1.1 ", "10.2.2.2"],
19
+ "extraColumn": ["ignored", "ignored"],
20
+ }
21
+ )
22
+ }
23
+
24
+ monkeypatch.setattr("queries.process_ipaddressv4._sheet_exists", lambda *args: True)
25
+ monkeypatch.setattr(
26
+ "queries.process_ipaddressv4.read_dump_excel", lambda *args, **kwargs: dump_dfs
27
+ )
28
+
29
+ df = process_ipaddressv4_data("dummy.xlsb")
30
+
31
+ assert list(df.columns) == ["MRBTS", "localIpAddr"]
32
+ assert list(df["MRBTS"]) == ["12345", "67890"]
33
+ assert list(df["localIpAddr"]) == ["10.1.1.1", "10.2.2.2"]
34
+ assert UtilsVars.all_db_dfs_names == ["IPADDRESSV4"]
35
+ assert UtilsVars.all_db_dfs[0].equals(df)
36
+
37
+
38
+ def test_process_ipaddressv4_data_skips_when_sheet_is_absent(monkeypatch):
39
+ monkeypatch.setattr("queries.process_ipaddressv4._sheet_exists", lambda *args: False)
40
+
41
+ df = process_ipaddressv4_data("dummy.xlsb")
42
+
43
+ assert list(df.columns) == ["MRBTS", "localIpAddr"]
44
+ assert df.empty
45
+ assert UtilsVars.all_db_dfs == []
46
+ assert UtilsVars.all_db_dfs_names == []
47
+
48
+
49
+ def test_process_ipaddressv4_data_requires_local_ip_column(monkeypatch):
50
+ dump_dfs = {"IPADDRESSV4": pd.DataFrame({"MRBTS": ["12345"]})}
51
+
52
+ monkeypatch.setattr("queries.process_ipaddressv4._sheet_exists", lambda *args: True)
53
+ monkeypatch.setattr(
54
+ "queries.process_ipaddressv4.read_dump_excel", lambda *args, **kwargs: dump_dfs
55
+ )
56
+
57
+ with pytest.raises(ValueError, match="localIpAddr"):
58
+ process_ipaddressv4_data("dummy.xlsb")
59
+
60
+
61
+ def test_process_all_tech_db_exports_ipaddressv4_as_final_extra_sheet(monkeypatch):
62
+ from queries import process_all_db
63
+
64
+ captured = {}
65
+
66
+ def fake_all_dbs(filepath):
67
+ UtilsVars.all_db_dfs = [pd.DataFrame({"source": ["base"]})]
68
+ UtilsVars.all_db_dfs_names = ["GSM"]
69
+
70
+ def fake_site_db():
71
+ UtilsVars.all_db_dfs.append(pd.DataFrame({"source": ["site"]}))
72
+ UtilsVars.all_db_dfs_names.append("SITE")
73
+
74
+ def fake_ipaddressv4(filepath):
75
+ UtilsVars.all_db_dfs.append(pd.DataFrame({"MRBTS": ["12345"]}))
76
+ UtilsVars.all_db_dfs_names.append("IPADDRESSV4")
77
+
78
+ def fake_convert_database_dfs(dfs, sheet_names):
79
+ captured["dfs"] = dfs
80
+ captured["sheet_names"] = sheet_names
81
+ return b"excel"
82
+
83
+ monkeypatch.setattr(process_all_db, "all_dbs", fake_all_dbs)
84
+ monkeypatch.setattr(process_all_db, "site_db", fake_site_db)
85
+ monkeypatch.setattr(process_all_db, "process_ipaddressv4_data", fake_ipaddressv4)
86
+ monkeypatch.setattr(
87
+ process_all_db, "convert_database_dfs", fake_convert_database_dfs
88
+ )
89
+
90
+ process_all_db.process_all_tech_db("dummy.xlsb")
91
+
92
+ assert UtilsVars.final_all_database == b"excel"
93
+ assert captured["sheet_names"] == ["GSM", "SITE", "IPADDRESSV4"]
94
+ assert len(captured["dfs"]) == 3