labnotes 0.0.16__tar.gz → 0.0.17__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.16 → labnotes-0.0.17}/PKG-INFO +5 -1
- {labnotes-0.0.16 → labnotes-0.0.17}/README.md +4 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/context.md +4 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/experiments.py +1 -2
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/models.py +1 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/read_experiment_config.py +7 -4
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/start_experiment.py +3 -2
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/open_tables.py +4 -1
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/summarize_experiments.py +2 -1
- {labnotes-0.0.16 → labnotes-0.0.17}/.gitignore +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/CHANGELOG.md +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/MIGRATIONS.md +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/pyproject.toml +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/cell_progress.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/init.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/open_experiments.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/open_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/pivot_cells.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/read_design.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/read_note.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/run_columns.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/lock_path.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/run_experiment.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/server.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/stop_idle_kernels.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/study_progress.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/summarize_design.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/templates/macros.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.17}/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.17
|
|
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>
|
|
@@ -73,6 +73,7 @@ Each takes `--format table` (the default) or `--format json`.
|
|
|
73
73
|
experiments folder:
|
|
74
74
|
|
|
75
75
|
```toml
|
|
76
|
+
name = "Model and effort"
|
|
76
77
|
command = "uv run scripts/study.py --output {run_dir}"
|
|
77
78
|
repeats = 5
|
|
78
79
|
|
|
@@ -81,6 +82,9 @@ model = ["opus", "sonnet"]
|
|
|
81
82
|
effort = ["low", "high"]
|
|
82
83
|
```
|
|
83
84
|
|
|
85
|
+
`name` is optional: a display name for the experiment, shown in the live view
|
|
86
|
+
and as `display_name` in `experiments`. The folder name stays the key, so
|
|
87
|
+
renaming the experiment means editing `name`.
|
|
84
88
|
Each combination of `[params]` runs `repeats` times, round-robin. Only runs
|
|
85
89
|
that exit 0 count, so running again fills in what failed or never ran.
|
|
86
90
|
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
@@ -50,6 +50,7 @@ Each takes `--format table` (the default) or `--format json`.
|
|
|
50
50
|
experiments folder:
|
|
51
51
|
|
|
52
52
|
```toml
|
|
53
|
+
name = "Model and effort"
|
|
53
54
|
command = "uv run scripts/study.py --output {run_dir}"
|
|
54
55
|
repeats = 5
|
|
55
56
|
|
|
@@ -58,6 +59,9 @@ model = ["opus", "sonnet"]
|
|
|
58
59
|
effort = ["low", "high"]
|
|
59
60
|
```
|
|
60
61
|
|
|
62
|
+
`name` is optional: a display name for the experiment, shown in the live view
|
|
63
|
+
and as `display_name` in `experiments`. The folder name stays the key, so
|
|
64
|
+
renaming the experiment means editing `name`.
|
|
61
65
|
Each combination of `[params]` runs `repeats` times, round-robin. Only runs
|
|
62
66
|
that exit 0 count, so running again fills in what failed or never ran.
|
|
63
67
|
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
@@ -40,6 +40,7 @@ Each takes `--format table` (the default) or `--format json`; use `--format json
|
|
|
40
40
|
experiments folder:
|
|
41
41
|
|
|
42
42
|
```toml
|
|
43
|
+
name = "Model and effort"
|
|
43
44
|
command = "uv run scripts/study.py --output {run_dir}"
|
|
44
45
|
repeats = 5
|
|
45
46
|
|
|
@@ -48,6 +49,9 @@ model = ["opus", "sonnet"]
|
|
|
48
49
|
effort = ["low", "high"]
|
|
49
50
|
```
|
|
50
51
|
|
|
52
|
+
`name` is optional: a display name for the experiment, shown in the live view
|
|
53
|
+
and as `display_name` in `experiments`. The folder name stays the key, so
|
|
54
|
+
renaming the experiment means editing `name`.
|
|
51
55
|
Each combination of `[params]` runs `repeats` times, round-robin. Only runs
|
|
52
56
|
that exit 0 count, so running again fills in what failed or never ran.
|
|
53
57
|
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import sys
|
|
3
|
-
from functools import partial
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
|
|
6
5
|
import click
|
|
@@ -60,7 +59,7 @@ def experiments(
|
|
|
60
59
|
match name, action:
|
|
61
60
|
case str(), "run":
|
|
62
61
|
live = sys.stdout.isatty() and sys.stderr.isatty() and not no_tui
|
|
63
|
-
drive =
|
|
62
|
+
drive = run_tui if live else lambda start, title: run_headless(start)
|
|
64
63
|
try:
|
|
65
64
|
results = start_experiment(
|
|
66
65
|
config, name, experiment_config, concurrency, drive
|
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
from labnotes.models import ExperimentConfig
|
|
6
6
|
|
|
7
|
-
SETTINGS = {"command", "repeats", "params"}
|
|
7
|
+
SETTINGS = {"name", "command", "repeats", "params"}
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def read_experiment_config(path: Path) -> ExperimentConfig:
|
|
@@ -16,6 +16,9 @@ def read_experiment_config(path: Path) -> ExperimentConfig:
|
|
|
16
16
|
unknown = sorted(values.keys() - SETTINGS)
|
|
17
17
|
if unknown:
|
|
18
18
|
raise ValueError(f"{path}: unknown keys {', '.join(unknown)}")
|
|
19
|
+
name = values.get("name")
|
|
20
|
+
if name is not None and (not isinstance(name, str) or not name.strip()):
|
|
21
|
+
raise ValueError(f"{path}: name must be a string")
|
|
19
22
|
command = values.get("command")
|
|
20
23
|
if not isinstance(command, str) or not command.strip():
|
|
21
24
|
raise ValueError(f"{path}: command must be a string")
|
|
@@ -25,11 +28,11 @@ def read_experiment_config(path: Path) -> ExperimentConfig:
|
|
|
25
28
|
params = values.get("params", {})
|
|
26
29
|
if not isinstance(params, dict):
|
|
27
30
|
raise ValueError(f"{path}: params must be a table, like [params]")
|
|
28
|
-
for
|
|
31
|
+
for param, options in params.items():
|
|
29
32
|
if not isinstance(options, list) or not options:
|
|
30
|
-
raise ValueError(f"{path}: params.{
|
|
33
|
+
raise ValueError(f"{path}: params.{param} must be a non-empty list")
|
|
31
34
|
try:
|
|
32
35
|
json.dumps(params)
|
|
33
36
|
except TypeError as error:
|
|
34
37
|
raise ValueError(f"{path}: params can't hold dates or times") from error
|
|
35
|
-
return ExperimentConfig(command, repeats, params)
|
|
38
|
+
return ExperimentConfig(command, repeats, params, name)
|
|
@@ -15,7 +15,7 @@ def start_experiment(
|
|
|
15
15
|
name: str,
|
|
16
16
|
experiment_config: Path | None,
|
|
17
17
|
concurrency: int,
|
|
18
|
-
drive: Callable[[Start], list[dict[str, object]]],
|
|
18
|
+
drive: Callable[[Start, str], list[dict[str, object]]],
|
|
19
19
|
) -> list[dict[str, object]]:
|
|
20
20
|
if experiment_config is None:
|
|
21
21
|
folder = config.experiments.replace("{experiment}", name)
|
|
@@ -27,6 +27,7 @@ def start_experiment(
|
|
|
27
27
|
lock.parent.mkdir(parents=True, exist_ok=True)
|
|
28
28
|
try:
|
|
29
29
|
with FileLock(lock, blocking=False):
|
|
30
|
-
|
|
30
|
+
start = partial(run_experiment, config, name, experiment, concurrency)
|
|
31
|
+
return drive(start, experiment.name or name)
|
|
31
32
|
except Timeout as error:
|
|
32
33
|
raise ValueError(f"{name} is already running ({lock} is held).") from error
|
|
@@ -12,7 +12,10 @@ from labnotes.tables.read_run import read_run
|
|
|
12
12
|
EXPERIMENTS = """
|
|
13
13
|
CREATE TABLE experiment_configs (experiment TEXT PRIMARY KEY, config TEXT);
|
|
14
14
|
CREATE VIEW experiments AS
|
|
15
|
-
SELECT
|
|
15
|
+
SELECT
|
|
16
|
+
names.name,
|
|
17
|
+
coalesce(experiment_configs.config ->> 'name', names.name) AS display_name,
|
|
18
|
+
experiment_configs.config
|
|
16
19
|
FROM (
|
|
17
20
|
SELECT experiment AS name FROM experiment_configs
|
|
18
21
|
UNION SELECT experiment FROM files
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|