web UI added and refactoring done

This commit is contained in:
Ayzen
2026-06-06 00:06:30 +03:00
parent 3c30a12d4a
commit af6005d68f
65 changed files with 3630 additions and 4720 deletions
+36 -10
View File
@@ -24,20 +24,18 @@ _MAX_COMBOS = 4096
def _require_int(payload: dict[str, Any], key: str, default: int) -> int:
"""Read an integer field, rejecting JSON arrays/objects with a named ValueError.
"""Read a strict JSON integer, treating an explicit ``null`` as 'use default'.
Bare ``int()`` raises ``TypeError`` on a list/dict, which escapes the
config-error contract; surface it as a ValueError naming the field instead.
Accept only a genuine JSON integer (not bool, not float, not numeric string):
silently truncating ``5.7`` or parsing ``"5"`` would hide a malformed config.
Mirrors ``run_config_codec._read_int`` so every config integer reads identically.
"""
value = payload.get(key, default)
if value is None: # explicit JSON null -> use the default, never coerce
return default
if isinstance(value, bool) or not isinstance(value, (int, float, str)):
if isinstance(value, bool) or not isinstance(value, int):
raise ValueError(f"{key} must be a JSON integer")
try:
return int(value)
except (TypeError, ValueError) as exc:
raise ValueError(f"{key} must be a JSON integer") from exc
return value
def _require_str(payload: dict[str, Any], key: str, default: str) -> str:
@@ -131,8 +129,8 @@ def validate_sweep_model(sweep: RadarSweepModel) -> None:
raise ValueError("radar.sweep.points must be an integer")
if points <= 0:
raise ValueError("radar.sweep.points must be > 0")
if float(sweep.stop_hz) < float(sweep.start_hz):
raise ValueError("radar.sweep.stop_hz must be >= radar.sweep.start_hz")
if float(sweep.stop_hz) <= float(sweep.start_hz):
raise ValueError("radar.sweep.stop_hz must be > radar.sweep.start_hz")
def validate_gpr_model(
@@ -173,6 +171,34 @@ def validate_gpr_model(
seen_input_positions.add(input_pos)
def validate_combos(
combos: list[ComboModel],
*,
input_positions: int,
output_positions: int,
) -> None:
"""Validate run combos against the configured switch dimensions.
Each combo's input/output must index a real switch position, and no
``input:output`` pair may repeat — an out-of-range or duplicate combo is a
config error that would otherwise produce missing or doubled traces downstream.
"""
seen: set[tuple[int, int]] = set()
for combo in combos:
if not 0 <= int(combo.input) < int(input_positions):
raise ValueError(
f"run.combos input {combo.input} is out of range [0, {input_positions})"
)
if not 0 <= int(combo.output) < int(output_positions):
raise ValueError(
f"run.combos output {combo.output} is out of range [0, {output_positions})"
)
pair = (int(combo.input), int(combo.output))
if pair in seen:
raise ValueError(f"run.combos contains duplicate combo {combo.input}:{combo.output}")
seen.add(pair)
def parse_combos_from_text(text: str) -> list[ComboModel]:
"""Parse UI combos string in `input:output,input:output` format."""
cleaned = text.strip()