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))