labnotes 0.0.20__tar.gz → 0.0.21__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.20 → labnotes-0.0.21}/PKG-INFO +1 -1
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/context.md +2 -1
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/execute_run.py +7 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/run_experiment.py +4 -5
- labnotes-0.0.21/src/labnotes/runner/wait_for_group.py +11 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/.gitignore +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/CHANGELOG.md +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/MIGRATIONS.md +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/README.md +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/pyproject.toml +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/cell_progress.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/experiment_progress.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/experiments.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/init.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/models.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/pivot_cells.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/lock_path.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/start_experiment.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/server.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/stop_idle_kernels.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/templates/macros.html +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.20 → labnotes-0.0.21}/uv.lock +0 -0
|
@@ -73,7 +73,8 @@ A script run by labnotes should:
|
|
|
73
73
|
|
|
74
74
|
- take each param as a `--name value` flag, parsing lists and tables from JSON;
|
|
75
75
|
- take its output folder as an argument, passed in `command` as `{run_dir}`, and write everything it produces there;
|
|
76
|
-
- exit non-zero when it fails, so the run counts as failed and runs again next time
|
|
76
|
+
- exit non-zero when it fails, so the run counts as failed and runs again next time;
|
|
77
|
+
- stop any background process it starts before it exits; the run ends when `command` exits.
|
|
77
78
|
|
|
78
79
|
Runs can take a long time. Start `run` in the background, then check on it with `labnotes experiments foo runs`; a run with no `ended` is still going.
|
|
79
80
|
|
|
@@ -3,6 +3,7 @@ import time
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from labnotes.runner.shell_command import shell_command
|
|
6
|
+
from labnotes.runner.wait_for_group import wait_for_group
|
|
6
7
|
from labnotes.runner.write_run_json import write_run_json
|
|
7
8
|
from labnotes.tables.iso_time import iso_time
|
|
8
9
|
|
|
@@ -13,6 +14,7 @@ async def execute_run(
|
|
|
13
14
|
command: str,
|
|
14
15
|
params: dict[str, object],
|
|
15
16
|
running: set[asyncio.subprocess.Process],
|
|
17
|
+
stopping: asyncio.Event,
|
|
16
18
|
) -> dict[str, object]:
|
|
17
19
|
run: dict[str, object] = {
|
|
18
20
|
"params": params,
|
|
@@ -42,6 +44,11 @@ async def execute_run(
|
|
|
42
44
|
running.add(process)
|
|
43
45
|
try:
|
|
44
46
|
run["exit_code"] = await process.wait()
|
|
47
|
+
# The shell can exit on SIGTERM before what it started. Once
|
|
48
|
+
# stopping, the run stays killable until its whole group is
|
|
49
|
+
# gone. A normal exit ends the run even if helpers linger.
|
|
50
|
+
if stopping.is_set():
|
|
51
|
+
await wait_for_group(process.pid)
|
|
45
52
|
finally:
|
|
46
53
|
running.discard(process)
|
|
47
54
|
run["ended"] = iso_time(time.time())
|
|
@@ -32,7 +32,7 @@ async def run_experiment(
|
|
|
32
32
|
report({"event": "planned", "runs": len(plan), "concurrency": concurrency})
|
|
33
33
|
running: set[asyncio.subprocess.Process] = set()
|
|
34
34
|
results: list[dict[str, object]] = []
|
|
35
|
-
stopping =
|
|
35
|
+
stopping = asyncio.Event()
|
|
36
36
|
|
|
37
37
|
def signal_runs(signal_number: int) -> None:
|
|
38
38
|
for process in running:
|
|
@@ -40,10 +40,9 @@ async def run_experiment(
|
|
|
40
40
|
os.killpg(process.pid, signal_number)
|
|
41
41
|
|
|
42
42
|
def interrupt() -> None:
|
|
43
|
-
nonlocal stopping
|
|
44
43
|
plan.clear()
|
|
45
|
-
if not stopping:
|
|
46
|
-
stopping
|
|
44
|
+
if not stopping.is_set():
|
|
45
|
+
stopping.set()
|
|
47
46
|
report({"event": "stopping"})
|
|
48
47
|
signal_runs(signal.SIGTERM)
|
|
49
48
|
elif running:
|
|
@@ -60,7 +59,7 @@ async def run_experiment(
|
|
|
60
59
|
folder.mkdir(parents=True)
|
|
61
60
|
report({"event": "started", "run": run, "params": params})
|
|
62
61
|
result = await execute_run(
|
|
63
|
-
config.root, folder, experiment.command, params, running
|
|
62
|
+
config.root, folder, experiment.command, params, running, stopping
|
|
64
63
|
)
|
|
65
64
|
report({"event": "ended", "run": run, **result})
|
|
66
65
|
results.append(result)
|
|
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
|