labnotes 0.0.15__tar.gz → 0.0.16__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.15 → labnotes-0.0.16}/PKG-INFO +3 -2
- {labnotes-0.0.15 → labnotes-0.0.16}/README.md +2 -1
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/context.md +10 -1
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/run_experiment.py +4 -4
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/run_headless.py +2 -0
- labnotes-0.0.16/src/labnotes/runner/stop_then_kill.py +15 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tui/run_app.py +3 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/.gitignore +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/CHANGELOG.md +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/MIGRATIONS.md +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/pyproject.toml +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/cell_progress.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/experiments.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/init.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/models.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/open_experiments.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/open_runs.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/pivot_cells.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/read_design.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/read_note.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/run_columns.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/lock_path.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/start_experiment.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/server.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/stop_idle_kernels.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/study_progress.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/summarize_design.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/templates/macros.html +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.15 → labnotes-0.0.16}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: labnotes
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.16
|
|
4
4
|
Summary: Browse experiment designs, notes, and run data from a folder.
|
|
5
5
|
Project-URL: Repository, https://github.com/thekevinscott/labnotes
|
|
6
6
|
Author-email: Kevin Scott <me@thekevinscott.com>
|
|
@@ -98,7 +98,8 @@ line per event instead.
|
|
|
98
98
|
- `--concurrency N` runs N at a time (default 1).
|
|
99
99
|
- `-e PATH` reads another file instead of `experiment.toml`.
|
|
100
100
|
- Ctrl-C stops the running scripts and records their end. A second Ctrl-C
|
|
101
|
-
kills them.
|
|
101
|
+
kills them. Closing the terminal or sending SIGTERM stops them the same way,
|
|
102
|
+
then kills any still going 5 seconds later.
|
|
102
103
|
- A second `run` of the same experiment fails while the first holds the lock.
|
|
103
104
|
- It exits 1 if any run failed.
|
|
104
105
|
|
|
@@ -75,7 +75,8 @@ line per event instead.
|
|
|
75
75
|
- `--concurrency N` runs N at a time (default 1).
|
|
76
76
|
- `-e PATH` reads another file instead of `experiment.toml`.
|
|
77
77
|
- Ctrl-C stops the running scripts and records their end. A second Ctrl-C
|
|
78
|
-
kills them.
|
|
78
|
+
kills them. Closing the terminal or sending SIGTERM stops them the same way,
|
|
79
|
+
then kills any still going 5 seconds later.
|
|
79
80
|
- A second `run` of the same experiment fails while the first holds the lock.
|
|
80
81
|
- It exits 1 if any run failed.
|
|
81
82
|
|
|
@@ -58,6 +58,14 @@ Each param is appended as `--name value`, with the name as written (use
|
|
|
58
58
|
and tables as JSON. labnotes writes `run.json` (params, created, ended, exit
|
|
59
59
|
code), `stdout.log` and `stderr.log` to the run folder.
|
|
60
60
|
|
|
61
|
+
A script run by labnotes should:
|
|
62
|
+
|
|
63
|
+
- take each param as a `--name value` flag, parsing lists and tables from JSON;
|
|
64
|
+
- take its output folder as an argument, passed in `command` as `{run_dir}`, and write everything it produces there;
|
|
65
|
+
- exit non-zero when it fails, so the run counts as failed and runs again next time.
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
61
69
|
In a terminal, `run` shows a live table of runs (status and time) and stays
|
|
62
70
|
open when they finish; `q` quits. Elsewhere, or with `--no-tui`, it prints a
|
|
63
71
|
line per event instead.
|
|
@@ -65,7 +73,8 @@ line per event instead.
|
|
|
65
73
|
- `--concurrency N` runs N at a time (default 1).
|
|
66
74
|
- `-e PATH` reads another file instead of `experiment.toml`.
|
|
67
75
|
- Ctrl-C stops the running scripts and records their end. A second Ctrl-C
|
|
68
|
-
kills them.
|
|
76
|
+
kills them. Closing the terminal or sending SIGTERM stops them the same way,
|
|
77
|
+
then kills any still going 5 seconds later.
|
|
69
78
|
- A second `run` of the same experiment fails while the first holds the lock.
|
|
70
79
|
- It exits 1 if any run failed.
|
|
71
80
|
|
|
@@ -38,13 +38,13 @@ async def run_experiment(
|
|
|
38
38
|
def interrupt() -> None:
|
|
39
39
|
nonlocal stopping
|
|
40
40
|
plan.clear()
|
|
41
|
-
if stopping:
|
|
42
|
-
report({"event": "killing"})
|
|
43
|
-
signal_runs(signal.SIGKILL)
|
|
44
|
-
else:
|
|
41
|
+
if not stopping:
|
|
45
42
|
stopping = True
|
|
46
43
|
report({"event": "stopping"})
|
|
47
44
|
signal_runs(signal.SIGTERM)
|
|
45
|
+
elif running:
|
|
46
|
+
report({"event": "killing"})
|
|
47
|
+
signal_runs(signal.SIGKILL)
|
|
48
48
|
|
|
49
49
|
async def work() -> None:
|
|
50
50
|
while plan:
|
|
@@ -6,10 +6,12 @@ import click
|
|
|
6
6
|
|
|
7
7
|
from labnotes.models import Start
|
|
8
8
|
from labnotes.runner.describe_event import describe_event
|
|
9
|
+
from labnotes.runner.stop_then_kill import stop_then_kill
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def run_headless(start: Start) -> list[dict[str, object]]:
|
|
12
13
|
def listen(interrupt: Callable[[], None]) -> None:
|
|
13
14
|
asyncio.get_running_loop().add_signal_handler(signal.SIGINT, interrupt)
|
|
15
|
+
stop_then_kill(interrupt, signal.SIGTERM, signal.SIGHUP)
|
|
14
16
|
|
|
15
17
|
return asyncio.run(start(lambda event: click.echo(describe_event(event)), listen))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
|
|
4
|
+
GRACE_SECONDS = 5
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def stop_then_kill(interrupt: Callable[[], None], *signals: int) -> None:
|
|
8
|
+
loop = asyncio.get_running_loop()
|
|
9
|
+
|
|
10
|
+
def stop() -> None:
|
|
11
|
+
interrupt()
|
|
12
|
+
loop.call_later(GRACE_SECONDS, interrupt)
|
|
13
|
+
|
|
14
|
+
for signal_number in signals:
|
|
15
|
+
loop.add_signal_handler(signal_number, stop)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import signal
|
|
1
2
|
import time
|
|
2
3
|
from collections.abc import Callable
|
|
3
4
|
|
|
@@ -7,6 +8,7 @@ from textual.widgets import DataTable, Footer, Header, Static
|
|
|
7
8
|
|
|
8
9
|
from labnotes.models import Start
|
|
9
10
|
from labnotes.runner.describe_event import describe_event
|
|
11
|
+
from labnotes.runner.stop_then_kill import stop_then_kill
|
|
10
12
|
from labnotes.runner.param_args import param_args
|
|
11
13
|
from labnotes.tui.format_elapsed import format_elapsed
|
|
12
14
|
|
|
@@ -50,6 +52,7 @@ class RunApp(App[None]):
|
|
|
50
52
|
|
|
51
53
|
def listen(self, interrupt: Callable[[], None]) -> None:
|
|
52
54
|
self.interrupt = interrupt
|
|
55
|
+
stop_then_kill(interrupt, signal.SIGTERM, signal.SIGHUP)
|
|
53
56
|
|
|
54
57
|
def show_event(self, event: dict[str, object]) -> None:
|
|
55
58
|
table = self.query_one(DataTable)
|
|
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
|