labnotes 0.0.38__tar.gz → 0.0.40__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.38 → labnotes-0.0.40}/PKG-INFO +1 -1
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/context.md +1 -1
- labnotes-0.0.40/src/labnotes/runner/new_stamped_run_id.py +9 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/run_experiment.py +3 -3
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tui/run_app.py +14 -9
- {labnotes-0.0.38 → labnotes-0.0.40}/.gitignore +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/CHANGELOG.md +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/MIGRATIONS.md +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/README.md +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/pyproject.toml +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/cell_progress.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/experiment_progress.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/experiments.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/init.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/models.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/pivot_cells.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/hold_folder.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/new_invocation_id.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/start_experiment.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/wait_for_group.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/server.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/stop_idle_kernels.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/templates/macros.html +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/testing-conventions.toml +0 -0
- {labnotes-0.0.38 → labnotes-0.0.40}/uv.lock +0 -0
|
@@ -61,7 +61,7 @@ that count fill a combination, so running again fills in what failed or never
|
|
|
61
61
|
ran.
|
|
62
62
|
`mode = "adhoc"` skips that: every `run` runs each combination `repeats` times
|
|
63
63
|
again, whatever is already on disk. The default is `mode = "fill"`.
|
|
64
|
-
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
64
|
+
Each run gets a new run folder, named for the UTC time it was planned (`20261020-000429-brave-fox`), so folder listings sort by start. `command` runs in a shell from the root, with
|
|
65
65
|
`{run_dir}` replaced by the run folder's absolute path. Pass it to the
|
|
66
66
|
script so it writes its outputs there.
|
|
67
67
|
Each param is appended as `--name value`, with the name as written (use
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from datetime import UTC, datetime
|
|
3
|
+
|
|
4
|
+
from labnotes.runner.new_run_id import new_run_id
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def new_stamped_run_id(taken: Callable[[str], bool]) -> str:
|
|
8
|
+
stamp = datetime.now(UTC).strftime("%Y%m%d-%H%M%S")
|
|
9
|
+
return f"{stamp}-" + new_run_id(lambda name: taken(f"{stamp}-{name}"))
|
|
@@ -13,7 +13,7 @@ from labnotes.models import (
|
|
|
13
13
|
)
|
|
14
14
|
from labnotes.runner.execute_run import execute_run
|
|
15
15
|
from labnotes.runner.new_invocation_id import new_invocation_id
|
|
16
|
-
from labnotes.runner.
|
|
16
|
+
from labnotes.runner.new_stamped_run_id import new_stamped_run_id
|
|
17
17
|
from labnotes.runner.param_grid import param_grid
|
|
18
18
|
from labnotes.runner.plan_runs import plan_runs
|
|
19
19
|
from labnotes.runner.run_folder import run_folder
|
|
@@ -49,7 +49,7 @@ async def run_experiment(
|
|
|
49
49
|
for params in plan_runs(
|
|
50
50
|
param_grid(experiment.params), experiment.repeats, finished
|
|
51
51
|
):
|
|
52
|
-
run =
|
|
52
|
+
run = new_stamped_run_id(taken)
|
|
53
53
|
planned.add(run)
|
|
54
54
|
plan.append((run, params))
|
|
55
55
|
runs = [{"run": run, "params": params} for run, params in plan]
|
|
@@ -131,7 +131,7 @@ async def run_experiment(
|
|
|
131
131
|
def retry(run: str) -> None:
|
|
132
132
|
if stopping.is_set() or run not in ended:
|
|
133
133
|
return
|
|
134
|
-
again =
|
|
134
|
+
again = new_stamped_run_id(taken)
|
|
135
135
|
planned.add(again)
|
|
136
136
|
plan.append((again, ended[run]))
|
|
137
137
|
report({"event": "retried", "run": run, "retry": again, "params": ended[run]})
|
|
@@ -17,6 +17,8 @@ from labnotes.tui.format_elapsed import format_elapsed
|
|
|
17
17
|
|
|
18
18
|
COLUMNS = ("run", "params", "status", "time")
|
|
19
19
|
OTHER_STREAM = {"stdout": "stderr", "stderr": "stdout"}
|
|
20
|
+
PENDING, RUNNING, PASSED, FAILED = "○", "◐", "✓", "✗"
|
|
21
|
+
SKIPPED, DESELECTED = "–", "⊘"
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class RunApp(App[None]):
|
|
@@ -101,7 +103,7 @@ class RunApp(App[None]):
|
|
|
101
103
|
case "planned":
|
|
102
104
|
for planned in event["runs"]: # type: ignore[attr-defined]
|
|
103
105
|
args = " ".join(param_args(planned["params"]))
|
|
104
|
-
cells = (planned["run"], args,
|
|
106
|
+
cells = (planned["run"], args, PENDING, "")
|
|
105
107
|
self.cells[planned["run"]] = [*map(dim, cells)]
|
|
106
108
|
self.pending.add(planned["run"])
|
|
107
109
|
self.redraw(table.cursor_row)
|
|
@@ -118,13 +120,16 @@ class RunApp(App[None]):
|
|
|
118
120
|
if run == self.next_run:
|
|
119
121
|
self.show("")
|
|
120
122
|
args = " ".join(param_args(event["params"])) # type: ignore[arg-type]
|
|
121
|
-
cells = (run, args,
|
|
123
|
+
cells = (run, args, RUNNING, format_elapsed(0))
|
|
122
124
|
for column, cell in zip(COLUMNS, cells):
|
|
123
125
|
self.set_cell(run, column, cell)
|
|
124
126
|
case "ended":
|
|
125
|
-
outcome =
|
|
126
|
-
style = "
|
|
127
|
-
if
|
|
127
|
+
outcome = PASSED
|
|
128
|
+
style = ""
|
|
129
|
+
if event["error"] or event["exit_code"]:
|
|
130
|
+
reason = event["error"] or f"exited {event['exit_code']}"
|
|
131
|
+
outcome = f"{FAILED} {reason}"
|
|
132
|
+
style = "red"
|
|
128
133
|
self.failed.add(run)
|
|
129
134
|
self.ended.add(run)
|
|
130
135
|
self.set_cell(run, "status", Text(str(outcome), style=style))
|
|
@@ -138,18 +143,18 @@ class RunApp(App[None]):
|
|
|
138
143
|
self.next_run = run
|
|
139
144
|
case "deselected":
|
|
140
145
|
self.pending.discard(run)
|
|
141
|
-
self.set_cell(run, "status", dim(
|
|
146
|
+
self.set_cell(run, "status", dim(DESELECTED))
|
|
142
147
|
self.reorder(event, table.cursor_row)
|
|
143
148
|
self.show(describe_event(event))
|
|
144
149
|
case "reselected":
|
|
145
150
|
self.pending.add(run)
|
|
146
|
-
self.set_cell(run, "status", dim(
|
|
151
|
+
self.set_cell(run, "status", dim(PENDING))
|
|
147
152
|
self.reorder(event, table.cursor_row)
|
|
148
153
|
self.show(describe_event(event))
|
|
149
154
|
case "retried":
|
|
150
155
|
again = str(event["retry"])
|
|
151
156
|
args = " ".join(param_args(event["params"])) # type: ignore[arg-type]
|
|
152
|
-
self.cells[again] = [*map(dim, (again, args,
|
|
157
|
+
self.cells[again] = [*map(dim, (again, args, PENDING, ""))]
|
|
153
158
|
self.pending.add(again)
|
|
154
159
|
self.redraw(table.cursor_row)
|
|
155
160
|
self.show(describe_event(event))
|
|
@@ -161,7 +166,7 @@ class RunApp(App[None]):
|
|
|
161
166
|
self.show(describe_event(event))
|
|
162
167
|
case "stopping":
|
|
163
168
|
for pending in self.pending:
|
|
164
|
-
self.set_cell(pending, "status", dim(
|
|
169
|
+
self.set_cell(pending, "status", dim(SKIPPED))
|
|
165
170
|
self.show(describe_event(event))
|
|
166
171
|
case _:
|
|
167
172
|
self.show(describe_event(event))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|