160 lines
5.0 KiB
Python
160 lines
5.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
TEST_CONFIG_DEFINITION = {
|
|
"TC1": {"T1D": "STA5", "T1F": "STA56", "T1I": "STA58", "T1L": "STA64", "T2A":"STA63", "T2O":"STA65", "T2J": "STA59", "T2E": "STA6", "T3E": "STA4"},
|
|
"TC2": {"T1D": "STA64", "T1F": "STA4", "T1I": "STA5", "T1L": "STA58", "T2A":"STA56", "T2O":"STA59", "T2J": "STA6", "T2E": "STA65", "T3E": "STA63"},
|
|
"TC3": {"T1D": "STA58", "T1F": "STA63", "T1I": "STA64", "T2J": "STA65", "T2E": "STA59", "T3E": "STA56"},
|
|
"TC4": {"T1B": "STA56", "T1C": "STA4", "T1D": "STA63"},
|
|
"TC5": {"T1B": "STA4", "T1C": "STA63", "T1D": "STA56"},
|
|
"TC6": {"T1B": "STA63", "T1C": "STA56", "T1D": "STA4"},
|
|
"TC7": {"T1F": "STA4", "T2A": "STA63", "T3E": "STA56"},
|
|
"TC8": {"T1F": "STA63", "T2A": "STA56", "T3E": "STA4"},
|
|
"TC9": {"T1F": "STA63", "T2A": "STA64", "T3E": "STA4"},
|
|
"TC10": {"T1F": "STA4", "T3E": "STA56", "T1K2A": "STA63"},
|
|
"TC11": {"T1F": "STA56", "T3E": "STA63", "T1K2A": "STA4"},
|
|
"TC12": {"T1F": "STA56", "T3E": "STA4", "T1K2A": "STA63"},
|
|
}
|
|
|
|
|
|
|
|
def _norm(value: Any) -> str:
|
|
if value is None:
|
|
return ""
|
|
return " ".join(str(value).strip().upper().split())
|
|
|
|
|
|
def _get_test_config(test: Any) -> dict[str, dict[str, str | None]]:
|
|
if isinstance(test, dict):
|
|
config = test.get("config") or {}
|
|
else:
|
|
config = getattr(test, "config", None) or {}
|
|
return config if isinstance(config, dict) else {}
|
|
|
|
|
|
def _testpoint_to_station_sets(config: dict[str, dict[str, str | None]]) -> dict[str, set[str]]:
|
|
result: dict[str, set[str]] = {}
|
|
|
|
def _add_entry(entry: dict[str, str | None]) -> None:
|
|
testpoint = _norm(entry.get("test_point") or entry.get("Test Point"))
|
|
sta_raw = _norm(entry.get("sta") or entry.get("STA"))
|
|
if not testpoint or not sta_raw:
|
|
return
|
|
|
|
stations = {_norm(sta) for sta in sta_raw.split(",") if _norm(sta)}
|
|
if not stations:
|
|
return
|
|
|
|
result.setdefault(testpoint, set()).update(stations)
|
|
|
|
for entry in config.values():
|
|
if isinstance(entry, dict):
|
|
_add_entry(entry)
|
|
|
|
return result
|
|
|
|
|
|
def build_station_testpoint_map(config: dict[str, dict[str, str | None]]) -> dict[str, str]:
|
|
"""Build station->testpoint map used by legacy graph serialization."""
|
|
station_to_testpoint: dict[str, str] = {}
|
|
for testpoint, stations in _testpoint_to_station_sets(config).items():
|
|
for station in stations:
|
|
station_to_testpoint[station] = testpoint
|
|
return station_to_testpoint
|
|
|
|
|
|
def resolve_test_config_keys(config: dict[str, dict[str, str | None]]) -> list[str]:
|
|
"""Return all TC keys whose definitions contain all testpoint->station mappings in config."""
|
|
testpoint_stations = _testpoint_to_station_sets(config)
|
|
if not testpoint_stations:
|
|
return []
|
|
|
|
matches: list[str] = []
|
|
for tc_key, tc_mapping in TEST_CONFIG_DEFINITION.items():
|
|
is_match = True
|
|
for testpoint, stations in testpoint_stations.items():
|
|
# TC definitions map one testpoint to exactly one station.
|
|
if len(stations) != 1:
|
|
is_match = False
|
|
break
|
|
expected_station = tc_mapping.get(testpoint)
|
|
if expected_station is None or expected_station not in stations:
|
|
is_match = False
|
|
break
|
|
if is_match:
|
|
matches.append(tc_key)
|
|
|
|
return matches
|
|
|
|
|
|
def build_config_rows(tests: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
by_sta: dict[str, set[str]] = {}
|
|
|
|
for test in tests:
|
|
config = test.get("config") or {}
|
|
if not isinstance(config, dict):
|
|
continue
|
|
for entry in config.values():
|
|
if not isinstance(entry, dict):
|
|
continue
|
|
sta_raw = entry.get("sta") or entry.get("STA")
|
|
test_point = entry.get("test_point") or entry.get("Test Point")
|
|
if not sta_raw or not test_point:
|
|
continue
|
|
|
|
for sta_part in str(sta_raw).split(","):
|
|
sta = sta_part.strip().upper()
|
|
if not sta:
|
|
continue
|
|
by_sta.setdefault(sta, set()).add(str(test_point))
|
|
|
|
return [
|
|
{
|
|
"sta": sta,
|
|
"testPoints": sorted(points),
|
|
}
|
|
for sta, points in sorted(by_sta.items())
|
|
]
|
|
|
|
|
|
def build_bundle_test_configs(tests: list[Any]) -> list[str]:
|
|
merged_by_testpoint: dict[str, set[str]] = {}
|
|
for test in tests:
|
|
config = _get_test_config(test)
|
|
for entry in config.values():
|
|
if not isinstance(entry, dict):
|
|
continue
|
|
testpoint_raw = entry.get("test_point") or entry.get("Test Point")
|
|
sta_raw = entry.get("sta") or entry.get("STA")
|
|
if not testpoint_raw or not sta_raw:
|
|
continue
|
|
|
|
testpoint = " ".join(str(testpoint_raw).strip().upper().split())
|
|
if not testpoint:
|
|
continue
|
|
|
|
stations = {
|
|
" ".join(str(sta).strip().upper().split())
|
|
for sta in str(sta_raw).split(",")
|
|
if " ".join(str(sta).strip().upper().split())
|
|
}
|
|
if not stations:
|
|
continue
|
|
|
|
merged_by_testpoint.setdefault(testpoint, set()).update(stations)
|
|
|
|
merged_config: dict[str, dict[str, str | None]] = {}
|
|
for idx, (testpoint, stations) in enumerate(sorted(merged_by_testpoint.items()), start=1):
|
|
merged_config[f"Station {idx}"] = {
|
|
"test_point": testpoint,
|
|
"sta": ",".join(sorted(stations)),
|
|
}
|
|
|
|
return resolve_test_config_keys(merged_config)
|
|
|
|
|
|
def serialize_station_testpoint_map(config: dict[str, dict[str, str | None]]) -> str:
|
|
return json.dumps(build_station_testpoint_map(config))
|