pypeit.dashboard.runlock module
The single-run lock for the PypeIt Dashboard (design X1).
At most one PypeIt run (run_pypeit or pypeit_run_to_calibstep) may
be active at a time, and the Dashboard must refuse to launch a second. It
becomes “locked” in two situations:
a run the Dashboard launched is still in progress (driven by the
LauncherviaRunLock.set_dashboard_running()); anda run started outside the Dashboard is detected by watching the reduction
.logfile — PypeIt writes to it continuously while running, so a log whose modification time is recent means a run is in progress.
The mtime test (RunLock._is_recent()) is a pure, unit-testable function;
the polling QTimer only calls it. The lock emits
RunLock.lockChanged when it transitions, which the views connect to so
they can enable/disable their launch controls.
Generated by JXP and Claude.
- class pypeit.dashboard.runlock.RunLock(log_path=None, state_path=None, parent=None)[source]
Bases:
QObjectSingle-run lock with
.log-mtime external-run detection (design X1), and the live-monitoring change signal (design R14, Stage 5).The one polling timer serves both roles: it detects whether a run is active (the
.logmtime is recent) and, while active, whether the reduction state file has changed (its mtime advanced) — emittingstateChangedso the views can refresh live (S5-Q3).Generated by JXP and Claude.
- Parameters:
log_path (
str,pathlib.Path, optional) – The reduction.logfile to watch. IfNone, only Dashboard-launched runs lock (no external detection).state_path (
str,pathlib.Path, optional) – The*_state.jsonfile to watch for live updates. IfNone,stateChangednever fires.parent (
QObject, optional) – The Qt parent.
- Variables:
lockChanged (Signal) – Emitted with the new locked state (
bool) on each transition.stateChanged (Signal) – Emitted (no args) when the state file’s mtime advances while a run is active (Stage 5 live monitoring).
- ACTIVE_WINDOW_S = 10.0
A
.logmodified within this many seconds means a run is active (PypeIt writes to it continuously; a quiet log means it finished or stalled).
- POLL_MS = 2500
Polling cadence for the external-run + state-change check (S4-Q5/S5-Q2: ~2–3 s; one timer for both).
- _emit_if_changed(was_locked)[source]
Emit
lockChangedif the locked state differs fromwas.Generated by JXP and Claude.
- Parameters:
was_locked (
bool) – The locked state before the change.- Returns:
None.
- static _is_recent(mtime, now, window)[source]
Whether a file modified at
mtimecounts as “being written now”.Pure and unit-testable:
Truewhen the log was touched withinwindowseconds ofnow.Generated by JXP and Claude.
- _state_mtime()[source]
The state file’s modification time, or
Noneif absent/unreadable.Generated by JXP and Claude.
- Returns:
The
*_state.jsonmtime (epoch seconds).- Return type:
float or None
- is_locked()[source]
Whether a run is active (Dashboard-launched or external).
Generated by JXP and Claude.
- Returns:
True if the Dashboard should refuse to launch a run.
- Return type:
- lockChanged
Emitted with the new locked state (bool) whenever it changes.
- poll()[source]
Re-check the
.logmtime for an external run (emittinglockChangedon a transition) and the*_state.jsonmtime for a live update (emittingstateChangedwhile active, Stage 5).Generated by JXP and Claude.
- Returns:
None.
- set_dashboard_running(running)[source]
Record whether a run the Dashboard launched is in progress, emitting
lockChangedif the locked state changes.Generated by JXP and Claude.
- Parameters:
running (
bool) – True while our launched run is active.- Returns:
None.
- start()[source]
Start polling the
.logfor external runs (and check once now).Generated by JXP and Claude.
- Returns:
None.
- stateChanged
Emitted when the state file changes while a run is active (Stage 5).