refactor: standardize codebase formatting, optimize import orders, and update GUI resolution to 1080p

This commit is contained in:
jack
2026-06-18 13:13:47 -07:00
parent 8ad2a9b972
commit 66942d250d
32 changed files with 453 additions and 120 deletions
+3 -3
View File
@@ -1,12 +1,12 @@
# ===== Models Sub-package =====
from pygui.backend.models.data_model import TemperatureTableModel
from pygui.backend.models.frame import Frame
from pygui.backend.models.frame_player import FramePlayer, frames_from_wafer_data
from pygui.backend.models.frame_stats import Stats, compute_stats
from pygui.backend.models.session_model import SessionModel, SessionUpdate
from pygui.backend.models.data_model import TemperatureTableModel
from pygui.backend.models.sensor_editor import SensorEditor
from pygui.backend.models.threshold_classifier import ThresholdConfig, classify, resolve_bounds
from pygui.backend.models.session_model import SessionModel, SessionUpdate
from pygui.backend.models.stability_detector import StabilityDetector
from pygui.backend.models.threshold_classifier import ThresholdConfig, classify, resolve_bounds
__all__ = [
"Frame", "FramePlayer", "frames_from_wafer_data",
+1
View File
@@ -1,4 +1,5 @@
from __future__ import annotations
from dataclasses import dataclass
+13 -11
View File
@@ -1,7 +1,9 @@
from __future__ import annotations
from __future__ import annotations
from pygui.backend.models.frame import Frame
from pygui.backend.wafer.zwafer_models import ZWaferData
def frames_from_wafer_data(data: ZWaferData, records) -> list[Frame]:
"""Build Frames from parsed DataRecords (records = list[DataRecord].)"""
return [Frame(seq=i, time=r.time, values=list(r.values)) for i, r in enumerate(records)]
@@ -10,36 +12,36 @@ class FramePlayer:
def __init__(self) -> None:
self._frames: list[Frame] =[]
self._i =0
def load(self, frames: list[Frame]) -> "FramePlayer":
self._frames = frames
self._i = 0
return self
@property
def total(self) -> int:
return len(self._frames)
@property
def index(self) -> int:
return self._i
return self._i
@property
def at_end(self) -> bool:
return self._i >= len(self._frames) -1
def current(self) -> Frame | None:
if not self._frames:
return None
return self._frames[self._i]
def _clamp(self, i:int):
return max(0, min(i, len(self._frames) - 1)) if self._frames else 0
def step(self, delta: int) -> "FramePlayer":
self._i = self._clamp(self._i + delta)
return self
def seek(self, i: int) -> "FramePlayer":
self._i = self._clamp(i)
return self
@@ -48,4 +50,4 @@ class FramePlayer:
"""Wall-clock ms until the next frame based on recorded timestamps; 0 if at end."""
if self._i + 1 >= len(self._frames):
return 0.0
return (self._frames[self._i + 1].time - self._frames[self._i].time) * 1000.0
return (self._frames[self._i + 1].time - self._frames[self._i].time) * 1000.0
+1
View File
@@ -1,6 +1,7 @@
"""Per-frame descriptive statistics"""
from __future__ import annotations
import math
from dataclasses import dataclass
+9 -9
View File
@@ -7,16 +7,16 @@ class SensorEditor:
def __init__(self) -> None:
self._replacements: dict[int, float] = {}
self._offsets: dict[int, float] = {}
def set_replacement(self, index: int, value: float) -> None:
"""Force sensor `index` to read `value` for every frame this session."""
self._replacements[index] = value
def set_offset(self, index: int, value: float) -> None:
"""Shift sensor `index` by `delta` (applied after any replacement)."""
self._offsets[index] = value
def clear(self, index: int | None = None) -> None:
"""Remove overrides. Pass an index to clear one sensor; omit to clear all."""
if index is None:
@@ -27,16 +27,16 @@ class SensorEditor:
self._offsets.pop(index, None)
def has_overrides(self) -> bool:
return bool(self._replacements or self._offsets)
def active_indices(self) -> list[int]:
"""Return sorted sensor indices that have any override."""
return sorted(set(self._replacements) | set(self._offsets))
def apply(self, values: list[float]) -> list[float]:
"""Return a new list wit all overrides applied (original unchanged)"""
if not self.has_overrides():
return list(values)
return list(values)
result = list(values)
for i in range(len(result)):
v = result[i]
@@ -45,4 +45,4 @@ class SensorEditor:
if i in self._offsets:
v += self._offsets[i]
result[i] = v
return result
return result
+8 -6
View File
@@ -1,4 +1,5 @@
from __future__ import annotations
from dataclasses import dataclass
from pygui.backend.models.frame import Frame
@@ -6,6 +7,7 @@ from pygui.backend.models.frame_stats import Stats, compute_stats
from pygui.backend.models.stability_detector import StabilityDetector
from pygui.backend.models.threshold_classifier import ThresholdConfig, classify, resolve_bounds
@dataclass(frozen=True)
class SessionUpdate:
seq: int
@@ -15,18 +17,18 @@ class SessionUpdate:
state: str
target: float
margin: float
class SessionModel:
def __init__(self, thresholds: ThresholdConfig | None = None) -> None:
self._config = thresholds or ThresholdConfig()
self._stability = StabilityDetector()
def set_thresholds(self, config: ThresholdConfig) -> None:
self._config = config
def reset(self) -> None:
self._stability.reset()
def process(self, frame: Frame) -> SessionUpdate:
stats = compute_stats(frame.values)
target, margin = resolve_bounds(frame.values, self._config)
@@ -34,6 +36,6 @@ class SessionModel:
# State always track the user's process set_point, even in auto-color mode.
state = self._stability.update(stats.avg, frame.time, self._config.set_point)
return SessionUpdate(
seq=frame.seq, values=frame.values, bands=bands,
seq=frame.seq, values=frame.values, bands=bands,
stats=stats, state=state, target=target, margin=margin,
)
)
@@ -1,5 +1,6 @@
"""Detect process state (Idle, Ramp, Set) from the running average temp"""
from __future__ import annotations
from typing import Optional
STATE_IDLE = "idle"
@@ -7,28 +8,27 @@ STATE_RAMP = "ramp"
STATE_SET = "set"
class StabilityDetector:
def __init__(self, idle_below: float = 50.0, tolerance: float = 1.0,
class StabilityDetector:
def __init__(self, idle_below: float = 50.0, tolerance: float = 1.0,
settle_seconds: float = 10.0) -> None:
self._idle_below = idle_below
self._tolerance = tolerance
self._settle_seconds = settle_seconds
self._near_since: Optional[float] = None # When avg entered the +- tolerance band
def reset(self) -> None:
self._near_since = None
def update(self, avg: float, time: float, set_point: float) ->str:
if avg < self._idle_below:
self._near_since = None
return STATE_IDLE
if abs(avg - set_point) <= self._tolerance:
if self._near_since is None:
self._near_since = time
self._near_since = time
if time - self._near_since >= self._settle_seconds:
return STATE_SET
return STATE_RAMP
self._near_since = None
return STATE_RAMP
@@ -4,11 +4,12 @@ Auto mode derives target=mean, margin=1
"""
from __future__ import annotations
import math
from dataclasses import dataclass
BAND_IN = "in_range"
BAND_HIGH = "high"
BAND_HIGH = "high"
BAND_LOW = "low"
@@ -39,4 +40,4 @@ def classify(value: float, target: float, margin: float) -> str:
def classify_all(values: list[float], cfg: ThresholdConfig) -> list[str]:
target, margin = resolve_bounds(values, cfg)
return [classify(v, target, margin)for v in values ]
return [classify(v, target, margin)for v in values ]