pypeit.dashboard.runlock module
The single-run lock for the PypeIt Dashboard.
The lock is scoped to one reduction — the reduction directory the
dashboard was opened on — not to the file system or the machine as a whole:
at most one PypeIt run (run_pypeit or pypeit_run_to_calibstep)
should be active for that reduction at a time, and the Dashboard refuses
to launch a second. Reductions in other directories (or other dashboards
watching them) are unaffected.
The lock engages 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’s log file,
<redux_dir>/<pypeit_root>.log(seelog_path) — 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.
- class pypeit.dashboard.runlock.RunLock(log_path=None, state_path=None, parent=None)[source]
Bases:
QObjectSingle-run lock for one reduction directory, with log-mtime detection of externally launched runs and a live-monitoring change signal.
The lock is per reduction: it watches the one
<redux_dir>/<pypeit_root>.logand<redux_dir>/<pypeit_root>_state.jsonof the reduction the dashboard was opened on, so it neither sees nor blocks runs in other directories.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.- Parameters:
log_path (
str,pathlib.Path, optional) – The reduction’s<pypeit_root>.logfile to watch. IfNone, only Dashboard-launched runs lock (no external detection).state_path (
str,pathlib.Path, optional) – The reduction’s<pypeit_root>_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 (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 (ms) for the external-run + state-change check (one timer for both).
- _emit_if_changed(was_locked)[source]
Emit
lockChangedif the locked state differs fromwas_locked.- Parameters:
was_locked (
bool) – The locked state before the change.
- 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.
- _state_mtime()[source]
The state file’s modification time, or
Noneif absent/unreadable.- Returns:
The
*_state.jsonmtime (epoch seconds).- Return type:
floator None
- is_locked()[source]
Whether a run is active (Dashboard-launched or external).
- 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).
- set_dashboard_running(running)[source]
Record whether a run the Dashboard launched is in progress, emitting
lockChangedif the locked state changes.- Parameters:
running (
bool) – True while our launched run is active.
- stateChanged
Emitted when the state file changes while a run is active.