spacr.qt.widgets.sweep_runs¶
Display regression runs and parameter-sweep trials in one Runs tab.
The panel shares the main regression screen’s results and figure surfaces. Selecting a row loads that run’s results and replaces the figures beside the tab. Ordinary runs, refits, and sweep trials use the same columns so their settings, status, output folder, and figures can be compared directly.
Runs are recorded when they start and updated when they finish. Saved sweep tables can be loaded alongside in-session records; switching rows announces a single active run to every dependent view.
NOTHING ON THIS TAB TOUCHES A RUN FOLDER FROM THE GUI THREAD. Measured on one
workstation: one os.path.exists on a path under
/nas_mnt – an autofs mount whose share was asleep – had NOT
RETURNED AFTER TWENTY SECONDS. Every row here carries a folder the user
chose, and this panel used to walk, stat, read and delete those folders in
the click that asked for it: the chooser’s start directory, the sweep table
read on a tab change, describe_folder’s os.walk inside the delete
confirmation, shutil.rmtree after it, and workspace.has_workspace
while the row menu was being built. Each of those is a frozen application
with no traceback for as long as the mount takes to wake – reported as
“opening map barcodes crashes spacr”, as hover flicker, and as glimpses of
other screens. They run on a spacr.qt.job_runner.JobRunner now, and
the one bare existence question left – which folder to open the chooser in
– is answered from spacr.qt.path_probe’s cache.
Classes¶
One row per RUN -- the sweep's trials and this session's own. |
Functions¶
|
One sentence about what a save did, for the panel's own note. |
|
|
|
Write a workspace bundle for each of |
Module Contents¶
- class spacr.qt.widgets.sweep_runs.SweepRunsPanel(parent=None, *, threaded: bool | None = None)[source]¶
Bases:
PySide6.QtWidgets.QWidgetOne row per RUN – the sweep’s trials and this session’s own.
- Variables:
trial_activated – emitted with a run’s row, as a dict, whenever a view should be showing that run. The older of the two names for that one event – see
loaded_run_changed.loaded – emitted with the number of rows shown.
- Parameters:
parent – parent widget.
threaded – whether the folder reads, walks and deletes go to a worker.
Nonedecides by asking whether a person is waiting on the calling thread (_should_thread()), which is what the application wants and what a test does not: unthreaded, every job runs inline and the methods below still return what they found.
Build the panel listing a sweep’s previous runs.
Two runners, because one of them is cancelled: a tab change can ask for the sweep table again while the last read is still out, and cancelling that read must not also abandon whatever else is in flight.
- Parameters:
parent – parent widget, or
None.threaded – read on a worker thread;
Nonefollows the process default.
- closeEvent(event)[source]¶
Stop background work and unlink before going away.
- Parameters:
event – the Qt close event.
- delete_runs_from_disk(records, confirm=None) int[source]¶
Delete the run FOLDERS, then take the rows off the table.
NOT RECOVERABLE, so it takes a confirmation naming the folder and saying what is in it, and there is no undo offered – an undo that cannot honour itself is worse than none.
- Parameters:
records – run-row mappings whose distinct, existing
folderpaths are candidates for deletion. A running record refuses the whole operation.confirm – called with the message and the list of folders; returns True to go ahead. Defaults to a modal question. Injected rather than assumed so a headless test can drive the real method instead of a copy of it.
- Returns:
how many folders were deleted, or
_DELETION_STARTEDwhen the work went to a worker and the count is not knowable yet. Nothing the user sees changes – the same question is asked and the same sentence written, a moment later.
- static describe_folder(folder: str) str[source]¶
What is in a run folder, in the words a decision needs.
“12 figures, 4 CSVs, 31 MB”. A user deciding whether to destroy an overnight fit needs to see WHAT they are destroying, and a folder path alone is not that.
WORKER ONLY – it walks the whole run folder and stats every file in it. Never call it from menu-build or paint code.
- Parameters:
folder – path of the run folder to walk; an empty or missing folder gives
"nothing on disk".
- eventFilter(watched, event)[source]¶
Delete on the selection removes it FROM THE LIST.
The safe half on the bare key, per the design. Deleting from disk is a separate, explicitly-worded choice and is not something a keystroke can reach.
- Parameters:
watched – the object the event was sent to; only the run table is handled here.
event – the filtered event; a Delete or Backspace
KeyPresson the run table removes the selected rows, and anything else goes to the base class.
- load(folder) bool[source]¶
Read
sweep_results.csvfrom a sweep’s destination folder.THE READ IS NOT DONE HERE. This is reached from a tab change (
AppScreen._on_results_tab_changed) with the sweep destination the user typed, and both theisfileand theread_csvblock for as long as that folder takes to answer – which on one/nas_mntwas twenty seconds of frozen application. The path work below is pure string manipulation; everything that touches the disk goes to a worker and comes back to_table_arrived().- Parameters:
folder – the sweep destination folder, or a path ending in
.csvnaming the results file itself;~is expanded and an empty value returnsFalse.- Returns:
whether the tab now shows a row – or, when the read went to a worker, whether it was started. The row count arrives with the
loadedsignal either way.
- load_run_from_disk(folder: str = '') bool[source]¶
Open a results folder and make that run active.
- Parameters:
folder (str, optional) – Run directory. An empty value opens a directory chooser.
- Returns:
bool –
Truewhen a valid run was opened.
Notes
Saved settings are restored beside the results so imported and current-session runs use the same table columns.
The search under the chosen folder runs on a worker: it is an
os.walkof somewhere the user just pointed at, which is the one place a sleeping network mount is guaranteed to be reached. Threaded,Truemeans the search was started and the row appears when it answers.
- load_this_run(record) bool[source]¶
Load a run and announce it even when it is already selected.
- Parameters:
record (mapping) – Run record containing a resolvable row key.
- Returns:
bool –
Truewhen the record was accepted and announced.
Notes
Unlike
set_loaded_run(), this method deliberately reloads the current selection. This lets an explicit user action resynchronize the run list and results view.
- loaded_run() dict | None[source]¶
The run every view on this screen is describing, or
None.Read off the composed frame rather than off the recorded dict, so a sweep trial and a session run answer the same way – which is the whole reason they share one table.
- photograph_shown()[source]¶
The still currently painted under the table, or
None.Public because “is the still on screen” is what a caller and a test both want, and reading
isVisible()off a widget that has never been shown answers a different question.
- record_run(label: str, source: str = SOURCE_RUN, settings=None, folder: str = '') int[source]¶
Put a run of the module on the table, and return its handle.
Recorded when the run STARTS, for the reason the figure grid marks its section then: a run that fails, or that is still going, is a fact worth seeing rather than a gap. Its row says
runninguntilupdate_run()is told otherwise – notok, because a row claiming ok is a row a click will try to open results from.- Parameters:
label – user-visible run name stored in the new row.
settings – the dict the run was started with. Only
RUN_SETTING_COLUMNSare copied out of it, and they are the sweep’s own setting columns – which is what makes a run and a trial two rows of one table rather than two tables.
- remove_runs(records) int[source]¶
Take rows off the table. THE FOLDERS ON DISK ARE UNTOUCHED.
The safe half, and the default gesture. It needs no confirmation because it is recoverable –
reload()reads the folder again – and the status line says exactly that rather than leaving the user to discover it.- Parameters:
records – run row dicts to take off the table, matched by folder or else by name (and by
trial_idin the sweep table);Noneremoves nothing.- Returns:
how many rows left the table.
- selected_runs() list[source]¶
Every selected row as a dict, in the order the table shows them.
Read back through the FRAME for the same reason
selected_trial()is: the table holds display strings, and a folder path is not something to reconstruct from one.
- selected_trial() dict | None[source]¶
The selected row as a dict, or
None.Read back through the FRAME, not off the table’s cells: the table holds display strings, and a trial re-run from
"0.05"instead of 0.05 is not the trial that was recorded.
- set_frame(frame, source: str = '') bool[source]¶
Point the panel at a table of runs.
- Parameters:
frame – the runs, or None to clear.
- set_loaded_run(key) bool[source]¶
Make
keythe loaded run.keyis a folder or a run name.- Parameters:
key – the run’s folder (
~is expanded and made absolute for matching) or its name;Noneor an empty string returnsFalse.- Returns:
True when a row matched. False rather than a blank mark for a run this table does not hold – a tick against nothing is worse than none, because it reads as an answer.
- set_photo_provider(provider) None[source]¶
Tell this panel where a run’s still comes from.
- Parameters:
provider –
folder -> QPixmap or None.
- the_load_failed(why: str = '') bool[source]¶
The run that was just announced could not be shown: undo the mark.
A mark on a run whose results are not visible leaves the run list and results view out of sync. Restore the previous mark so the list names the run that remains on screen.
- Parameters:
why – Reason added to the status line.
- Returns:
Whether the mark moved back.
- the_load_succeeded() None[source]¶
Finalize the selection after an asynchronous run load succeeds.
Records the loaded run as the current stable selection. A later failure callback for an older request therefore cannot move the selection back.
- update_run(handle: int, **fields) bool[source]¶
Change a recorded run’s row – its status, folder, seconds.
Returns False for a handle this panel never issued, rather than inventing a row: a run whose panel was rebuilt underneath it is a stale handle, and a phantom row is worse than a missing one.
- Parameters:
handle – the handle returned when the run was recorded; an unknown handle returns
False.
- spacr.qt.widgets.sweep_runs.describe_saved_states(saved, failures) str[source]¶
One sentence about what a save did, for the panel’s own note.
- Parameters:
saved – the run folders whose state was saved.
failures –
(path, reason)pairs for runs that did not save; the first three are named.
- spacr.qt.widgets.sweep_runs.ordered_columns(frame) list[source]¶
PREFERRED_COLUMNSthat this frame has, then everything else.Ordering, not filtering. A column nobody thought to list is still worth seeing – it is in the CSV, and hiding it means the user has to leave the application to read their own results.
- Parameters:
frame – the frame whose columns are ordered;
Nonereturns an empty list.
- spacr.qt.widgets.sweep_runs.save_run_states(folders, app_key: str = '') tuple[source]¶
Write a workspace bundle for each of
folders.WORKER ONLY –
SweepRunsPanel._apply_run_menu()submits it. Theisdirbelow and the write after it are both on a folder the user chose, and doing either in the menu’s own click is the freeze the module docstring describes.ASKED FOR, SO IT IS WRITTEN.
workspace.save_for_runreturns None when theruns/save_workspacepreference is off, which is right for the automatic save at the end of a run and wrong here: a user who chose “Save the state” from a menu has asked, and a menu item that silently does nothing is worse than one that is absent. The mode is forced on for this call only, and the preference is not written.- Parameters:
folders – run folders to save.
- Returns:
(saved, failures)– the folders that got a bundle, and(folder, reason)for those that did not. One folder failing does not stop the others, and every failure is NAMED: a count of “3 of 5” with no names is a report the user cannot act on.