labnotes 0.0.84__tar.gz → 0.0.85__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {labnotes-0.0.84 → labnotes-0.0.85}/PKG-INFO +1 -1
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/context.md +4 -2
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/models.py +1 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/run_control.py +2 -1
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/describe_event.py +4 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/run_experiment.py +12 -1
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/run_app.py +79 -4
- {labnotes-0.0.84 → labnotes-0.0.85}/.gitignore +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/CHANGELOG.md +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/MIGRATIONS.md +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/README.md +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/pyproject.toml +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/__main__.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/count_groups.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/create_note.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/__init__.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/control_run.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/daemon_app.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/daemon_client.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/daemon_running.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/daemon_server.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/describe_status.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/ensure_daemon.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/exit_when_idle.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/remote_start.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/run_daemon.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/run_logs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/serve_daemon.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/socket_path.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/stop_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/watch_daemon.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon/watch_status.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/daemon_command.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/experiments.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/file_changes.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/format_duration.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/format_started.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/group_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/init.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/invocation_started.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/is_positive_int.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/load_run.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/modes.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/nests_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/note_path.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/run_command.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/run_output.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/run_status.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/hold_folder.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/new_param_run_id.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/param_run_name.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/prepare_experiment.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/signal_tree.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/wait_for_tree.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/save_conflict_copy.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/save_note.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/server.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/shared_params.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/elapsed.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/experiment.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/local-time.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/new-note.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/note-edit.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/note-editor.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/run-output.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/experiment_run_ids.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/file_text.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/note_text.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/read_log.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/templates/editor_imports.html +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/templates/note.html +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/templates/run.html +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/browse_app.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/browse_tui.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/experiment_screen.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/experiments_screen.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/group_cells.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/invocation_columns.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/invocation_rows.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/run_cells.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/src/labnotes/wait_for_note.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/testing-conventions.toml +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/tests/integration/conftest.py +0 -0
- {labnotes-0.0.84 → labnotes-0.0.85}/uv.lock +0 -0
|
@@ -100,7 +100,8 @@ open when they finish. Failed runs show their status in red; `f` hides or shows
|
|
|
100
100
|
runs it again under a new id. `j` and `k` move the cursor, `g` and `G` jump to the
|
|
101
101
|
first and last row. Runs not started yet show grayed as `pending`, and as
|
|
102
102
|
`skipped` once stopped. Move the cursor to a pending run and press `n` to run it
|
|
103
|
-
next.
|
|
103
|
+
next. `m` grabs a pending run; `j` and `k` move it through the queue, Enter or `m`
|
|
104
|
+
drops it, Escape puts it back. Space deselects a pending run so it won't run; Space again puts it back at
|
|
104
105
|
the end of the queue. `/` filters rows by params text; Enter keeps the filter,
|
|
105
106
|
Escape clears it. `D` deselects every pending run the filter shows. `x` stops the
|
|
106
107
|
running run under the cursor; `x` again kills it. `+` and
|
|
@@ -129,7 +130,8 @@ going. Elsewhere, it prints a line per event instead.
|
|
|
129
130
|
waits for a daemon when none is up. `--json` prints one JSON object per line.
|
|
130
131
|
Following doesn't keep the daemon up.
|
|
131
132
|
- `labnotes run control NAME ACTION [ARG]` sends one live-view control to a
|
|
132
|
-
running experiment: `kill`, `retry`, `run_next` or `toggle` a run,
|
|
133
|
+
running experiment: `kill`, `retry`, `run_next` or `toggle` a run, `move` a
|
|
134
|
+
run to a place in the queue counted from 0,
|
|
133
135
|
`set_concurrency` to a number, `interrupt` or `finish`.
|
|
134
136
|
- A second `run` of the same experiment fails while the first is going.
|
|
135
137
|
- It exits 0 even if runs fail; the summary line counts failures. If it can't
|
|
@@ -18,7 +18,8 @@ PARAMS = {
|
|
|
18
18
|
name="control",
|
|
19
19
|
help=(
|
|
20
20
|
"Send one control to an experiment's runs, as the live view's keys do. "
|
|
21
|
-
"kill, retry, run_next and toggle take a run;
|
|
21
|
+
"kill, retry, run_next and toggle take a run; move a run and its new place "
|
|
22
|
+
"in the queue, from 0; set_concurrency a number; "
|
|
22
23
|
"interrupt and finish nothing."
|
|
23
24
|
),
|
|
24
25
|
)
|
|
@@ -14,6 +14,10 @@ def describe_event(event: dict[str, object]) -> str:
|
|
|
14
14
|
return f"{event['run']} {outcome}"
|
|
15
15
|
case "queued":
|
|
16
16
|
return f"{event['run']} runs next."
|
|
17
|
+
case "moved":
|
|
18
|
+
pending: list[str] = event["pending"] # type: ignore[assignment]
|
|
19
|
+
place = pending.index(str(event["run"])) + 1
|
|
20
|
+
return f"{event['run']} moved to {place} of {len(pending)} in the queue."
|
|
17
21
|
case "deselected":
|
|
18
22
|
return f"{event['run']} deselected."
|
|
19
23
|
case "reselected":
|
|
@@ -125,6 +125,13 @@ async def run_experiment(
|
|
|
125
125
|
plan.insert(0, entry)
|
|
126
126
|
arrange("queued", run)
|
|
127
127
|
|
|
128
|
+
def move(run: str, place: int) -> None:
|
|
129
|
+
entry = find(plan, run)
|
|
130
|
+
if entry is not None:
|
|
131
|
+
plan.remove(entry)
|
|
132
|
+
plan.insert(max(0, place), entry)
|
|
133
|
+
arrange("moved", run)
|
|
134
|
+
|
|
128
135
|
def toggle(run: str) -> None:
|
|
129
136
|
if stopping.is_set():
|
|
130
137
|
return
|
|
@@ -202,7 +209,11 @@ async def run_experiment(
|
|
|
202
209
|
ended[run] = params
|
|
203
210
|
results.append(result)
|
|
204
211
|
|
|
205
|
-
listen(
|
|
212
|
+
listen(
|
|
213
|
+
Controls(
|
|
214
|
+
interrupt, run_next, set_concurrency, toggle, kill, retry, finish, move
|
|
215
|
+
)
|
|
216
|
+
)
|
|
206
217
|
fill()
|
|
207
218
|
await done.wait()
|
|
208
219
|
await asyncio.gather(*started)
|
|
@@ -23,6 +23,8 @@ PENDING, PASSED, FAILED = "○", "✓", "✗"
|
|
|
23
23
|
SPINNER = "|/-\\"
|
|
24
24
|
SKIPPED, DESELECTED = "–", "⊘"
|
|
25
25
|
VIEWING_ACTIONS = {"leave", "quit", "interrupt", "command_palette"}
|
|
26
|
+
GRABBED_ACTIONS = {"shift", "drop", "put_back"}
|
|
27
|
+
GRABBING_ACTIONS = {*GRABBED_ACTIONS, "grab", "quit", "interrupt", "command_palette"}
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
class RunApp(App[None]):
|
|
@@ -30,6 +32,11 @@ class RunApp(App[None]):
|
|
|
30
32
|
BINDINGS = [
|
|
31
33
|
Binding("ctrl+c", "interrupt", "Stop runs"),
|
|
32
34
|
Binding("n", "run_next", "Run next"),
|
|
35
|
+
Binding("m", "grab", "Move"),
|
|
36
|
+
Binding("j,down", "shift(1)", priority=True),
|
|
37
|
+
Binding("k,up", "shift(-1)", priority=True),
|
|
38
|
+
Binding("enter", "drop", "Drop", priority=True),
|
|
39
|
+
Binding("escape", "put_back", "Put back"),
|
|
33
40
|
Binding("space", "toggle_run", "Deselect"),
|
|
34
41
|
Binding("D", "deselect_shown", "Deselect shown"),
|
|
35
42
|
Binding("x", "kill_run", "Stop run"),
|
|
@@ -56,6 +63,7 @@ class RunApp(App[None]):
|
|
|
56
63
|
lambda run: None,
|
|
57
64
|
lambda run: None,
|
|
58
65
|
lambda: None,
|
|
66
|
+
lambda run, place: None,
|
|
59
67
|
)
|
|
60
68
|
self.concurrency = 1
|
|
61
69
|
self.idle = False
|
|
@@ -70,6 +78,8 @@ class RunApp(App[None]):
|
|
|
70
78
|
self.hiding = False
|
|
71
79
|
self.folders: dict[str, Path] = {}
|
|
72
80
|
self.viewing: str | None = None
|
|
81
|
+
self.grabbed: str | None = None
|
|
82
|
+
self.grabbed_from: list[str] = []
|
|
73
83
|
self.offsets: dict[str, int]
|
|
74
84
|
self.decoders = {
|
|
75
85
|
stream: codecs.getincrementaldecoder("utf-8")(errors="replace")
|
|
@@ -129,6 +139,8 @@ class RunApp(App[None]):
|
|
|
129
139
|
case "adhoc", [only]:
|
|
130
140
|
self.view(only["run"]) # type: ignore[index]
|
|
131
141
|
case "started":
|
|
142
|
+
if run == self.grabbed:
|
|
143
|
+
self.action_put_back()
|
|
132
144
|
self.idle = False
|
|
133
145
|
self.pending.discard(run)
|
|
134
146
|
self.started[run] = time.monotonic()
|
|
@@ -158,10 +170,10 @@ class RunApp(App[None]):
|
|
|
158
170
|
del self.started[run]
|
|
159
171
|
self.redraw(table.cursor_row)
|
|
160
172
|
case "queued":
|
|
161
|
-
self.
|
|
162
|
-
table.move_cursor(row=table.get_row_index(run))
|
|
163
|
-
self.show(describe_event(event))
|
|
173
|
+
self.reposition(event, run)
|
|
164
174
|
self.next_run = run
|
|
175
|
+
case "moved":
|
|
176
|
+
self.reposition(event, run)
|
|
165
177
|
case "deselected":
|
|
166
178
|
self.pending.discard(run)
|
|
167
179
|
self.set_cell(run, "status", dim(DESELECTED))
|
|
@@ -198,7 +210,14 @@ class RunApp(App[None]):
|
|
|
198
210
|
passed = len(self.ended) - failed
|
|
199
211
|
self.show(f"{passed} passed, {failed} failed. q to quit.")
|
|
200
212
|
|
|
213
|
+
def reposition(self, event: dict[str, object], run: str) -> None:
|
|
214
|
+
table = self.query_one(DataTable)
|
|
215
|
+
self.reorder(event, table.cursor_row)
|
|
216
|
+
table.move_cursor(row=table.get_row_index(run))
|
|
217
|
+
self.show(describe_event(event))
|
|
218
|
+
|
|
201
219
|
def reorder(self, event: dict[str, object], row: int) -> None:
|
|
220
|
+
self.release()
|
|
202
221
|
waiting: list[str] = [*event["pending"], *event["held"]] # type: ignore[misc]
|
|
203
222
|
for run in waiting:
|
|
204
223
|
self.cells[run] = self.cells.pop(run)
|
|
@@ -220,6 +239,10 @@ class RunApp(App[None]):
|
|
|
220
239
|
table.update_cell(run, column, cell, update_width=True)
|
|
221
240
|
|
|
222
241
|
def check_action(self, action: str, parameters: tuple[object, ...]) -> bool:
|
|
242
|
+
if self.grabbed is not None:
|
|
243
|
+
return action in GRABBING_ACTIONS
|
|
244
|
+
if action in GRABBED_ACTIONS:
|
|
245
|
+
return False
|
|
223
246
|
return self.viewing is None or action in VIEWING_ACTIONS
|
|
224
247
|
|
|
225
248
|
def show_concurrency(self, event: dict[str, object]) -> None:
|
|
@@ -262,6 +285,57 @@ class RunApp(App[None]):
|
|
|
262
285
|
if (run := self.cursor_run()) is not None:
|
|
263
286
|
self.controls.run_next(run)
|
|
264
287
|
|
|
288
|
+
def queue(self) -> list[str]:
|
|
289
|
+
return [run for run in self.cells if run in self.pending]
|
|
290
|
+
|
|
291
|
+
def action_grab(self) -> None:
|
|
292
|
+
if self.grabbed is not None:
|
|
293
|
+
self.action_drop()
|
|
294
|
+
return
|
|
295
|
+
run = self.cursor_run()
|
|
296
|
+
if run not in self.pending:
|
|
297
|
+
return
|
|
298
|
+
self.grabbed = run
|
|
299
|
+
self.grabbed_from = list(self.cells)
|
|
300
|
+
self.refresh_bindings()
|
|
301
|
+
self.show(f"Moving {run}. j/k moves it, Enter drops it, Escape puts it back.")
|
|
302
|
+
|
|
303
|
+
def action_shift(self, step: int) -> None:
|
|
304
|
+
run = str(self.grabbed)
|
|
305
|
+
queue = self.queue()
|
|
306
|
+
place = queue.index(run) + step
|
|
307
|
+
if place not in range(len(queue)):
|
|
308
|
+
return
|
|
309
|
+
order = list(self.cells)
|
|
310
|
+
here, there = order.index(run), order.index(queue[place])
|
|
311
|
+
order[here], order[there] = order[there], order[here]
|
|
312
|
+
self.cells = {key: self.cells[key] for key in order}
|
|
313
|
+
self.redraw_on(run)
|
|
314
|
+
|
|
315
|
+
def action_drop(self) -> None:
|
|
316
|
+
run = str(self.grabbed)
|
|
317
|
+
self.release()
|
|
318
|
+
self.show("")
|
|
319
|
+
self.controls.move(run, self.queue().index(run))
|
|
320
|
+
|
|
321
|
+
def action_put_back(self) -> None:
|
|
322
|
+
run = str(self.grabbed)
|
|
323
|
+
self.release()
|
|
324
|
+
places = {key: place for place, key in enumerate(self.grabbed_from)}
|
|
325
|
+
ordered = sorted(self.cells, key=lambda key: places.get(key, len(places)))
|
|
326
|
+
self.cells = {key: self.cells[key] for key in ordered}
|
|
327
|
+
self.redraw_on(run)
|
|
328
|
+
self.show("")
|
|
329
|
+
|
|
330
|
+
def release(self) -> None:
|
|
331
|
+
self.grabbed = None
|
|
332
|
+
self.refresh_bindings()
|
|
333
|
+
|
|
334
|
+
def redraw_on(self, run: str) -> None:
|
|
335
|
+
table = self.query_one(DataTable)
|
|
336
|
+
self.redraw(table.cursor_row)
|
|
337
|
+
table.move_cursor(row=table.get_row_index(run))
|
|
338
|
+
|
|
265
339
|
def action_toggle_run(self) -> None:
|
|
266
340
|
if (run := self.cursor_run()) is not None:
|
|
267
341
|
self.controls.toggle(run)
|
|
@@ -294,7 +368,8 @@ class RunApp(App[None]):
|
|
|
294
368
|
field.focus()
|
|
295
369
|
|
|
296
370
|
def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
|
|
297
|
-
self.
|
|
371
|
+
if self.grabbed is None:
|
|
372
|
+
self.view(str(event.row_key.value))
|
|
298
373
|
|
|
299
374
|
def view(self, run: str) -> None:
|
|
300
375
|
self.viewing = run
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|