labnotes 0.0.44__tar.gz → 0.0.46__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.44 → labnotes-0.0.46}/PKG-INFO +1 -1
- {labnotes-0.0.44 → labnotes-0.0.46}/pyproject.toml +1 -1
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/context.md +3 -1
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/experiments.py +3 -4
- labnotes-0.0.46/src/labnotes/is_positive_int.py +2 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/models.py +2 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/read_config.py +11 -2
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/read_path.py +1 -1
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/read_experiment_config.py +8 -4
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/start_experiment.py +6 -2
- {labnotes-0.0.44 → labnotes-0.0.46}/.gitignore +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/CHANGELOG.md +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/MIGRATIONS.md +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/README.md +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/cell_progress.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/experiment_progress.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/init.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/modes.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/pivot_cells.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/hold_folder.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/new_invocation_id.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/run_experiment.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/wait_for_group.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/server.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/stop_idle_kernels.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/templates/macros.html +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/testing-conventions.toml +0 -0
- {labnotes-0.0.44 → labnotes-0.0.46}/uv.lock +0 -0
|
@@ -106,7 +106,9 @@ finish. Enter on a run follows its `stdout.log`; `e` switches to
|
|
|
106
106
|
plans a single run opens straight on its output. `q` quits. Elsewhere, or with `--no-tui`, it prints a
|
|
107
107
|
line per event instead.
|
|
108
108
|
|
|
109
|
-
- `--concurrency N` runs N at a time to start with
|
|
109
|
+
- `--concurrency N` runs N at a time to start with. Without it, `concurrency`
|
|
110
|
+
in `experiment.toml` sets it, then `concurrency` under `[experiments]` in
|
|
111
|
+
`.labnotes.toml`, then 1.
|
|
110
112
|
- `-e PATH` reads another file instead of `experiment.toml`.
|
|
111
113
|
- Ctrl-C stops the running scripts and records their end. A second Ctrl-C
|
|
112
114
|
kills them. Closing the terminal or sending SIGTERM stops them the same way,
|
|
@@ -30,9 +30,8 @@ from labnotes.tui.run_tui import run_tui
|
|
|
30
30
|
@click.option(
|
|
31
31
|
"--concurrency",
|
|
32
32
|
type=click.IntRange(min=1),
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
help="With run: how many runs at once.",
|
|
33
|
+
help="With run: how many runs at once. Overrides experiment.toml and"
|
|
34
|
+
" .labnotes.toml; 1 if none sets it.",
|
|
36
35
|
)
|
|
37
36
|
@click.option(
|
|
38
37
|
"-e",
|
|
@@ -51,7 +50,7 @@ def experiments(
|
|
|
51
50
|
name: str | None,
|
|
52
51
|
action: str | None,
|
|
53
52
|
output_format: str,
|
|
54
|
-
concurrency: int,
|
|
53
|
+
concurrency: int | None,
|
|
55
54
|
experiment_config: Path | None,
|
|
56
55
|
no_tui: bool,
|
|
57
56
|
) -> None:
|
|
@@ -40,6 +40,7 @@ class LabnotesConfig:
|
|
|
40
40
|
files: str
|
|
41
41
|
runs: str
|
|
42
42
|
mode: str = DEFAULT_MODE
|
|
43
|
+
concurrency: int = 1
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
@dataclass(frozen=True)
|
|
@@ -50,3 +51,4 @@ class ExperimentConfig:
|
|
|
50
51
|
name: str | None = None
|
|
51
52
|
counts: str = DEFAULT_COUNTS
|
|
52
53
|
mode: str = DEFAULT_MODE
|
|
54
|
+
concurrency: int = 1
|
|
@@ -2,6 +2,7 @@ import tomllib
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
4
|
from labnotes.models import LabnotesConfig
|
|
5
|
+
from labnotes.is_positive_int import is_positive_int
|
|
5
6
|
from labnotes.modes import DEFAULT_MODE, MODES
|
|
6
7
|
from labnotes.read_path import DEFAULT_PATHS, read_path
|
|
7
8
|
|
|
@@ -20,8 +21,16 @@ def read_config(path: Path) -> LabnotesConfig:
|
|
|
20
21
|
paths = {
|
|
21
22
|
table: read_path(path, table, values.get(table, {})) for table in DEFAULT_PATHS
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
experiments = values.get("experiments", {})
|
|
25
|
+
mode = experiments.get("mode", DEFAULT_MODE)
|
|
24
26
|
if mode not in MODES:
|
|
25
27
|
raise ValueError(f"{path}: [experiments] mode must be fill or adhoc")
|
|
28
|
+
concurrency = experiments.get("concurrency", 1)
|
|
29
|
+
if not is_positive_int(concurrency):
|
|
30
|
+
raise ValueError(
|
|
31
|
+
f"{path}: [experiments] concurrency must be a positive integer"
|
|
32
|
+
)
|
|
26
33
|
path = path.resolve()
|
|
27
|
-
return LabnotesConfig(
|
|
34
|
+
return LabnotesConfig(
|
|
35
|
+
path, path.parent, **paths, mode=mode, concurrency=concurrency
|
|
36
|
+
)
|
|
@@ -12,7 +12,7 @@ PLACEHOLDERS = {
|
|
|
12
12
|
"runs": {"experiment", "run"},
|
|
13
13
|
}
|
|
14
14
|
# Keys other readers own, so the path check lets them through.
|
|
15
|
-
OTHER_KEYS = {"experiments": {"mode"}}
|
|
15
|
+
OTHER_KEYS = {"experiments": {"mode", "concurrency"}}
|
|
16
16
|
PLACEHOLDER = re.compile(r"\{([^}]*)\}")
|
|
17
17
|
|
|
18
18
|
|
|
@@ -4,12 +4,13 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
from labnotes.default_counts import DEFAULT_COUNTS
|
|
6
6
|
from labnotes.models import ExperimentConfig
|
|
7
|
+
from labnotes.is_positive_int import is_positive_int
|
|
7
8
|
from labnotes.modes import MODES
|
|
8
9
|
|
|
9
|
-
SETTINGS = {"name", "command", "repeats", "params", "counts", "mode"}
|
|
10
|
+
SETTINGS = {"name", "command", "repeats", "params", "counts", "mode", "concurrency"}
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
def read_experiment_config(path: Path, mode: str) -> ExperimentConfig:
|
|
13
|
+
def read_experiment_config(path: Path, mode: str, concurrency: int) -> ExperimentConfig:
|
|
13
14
|
try:
|
|
14
15
|
with path.open("rb") as file:
|
|
15
16
|
values = tomllib.load(file)
|
|
@@ -25,7 +26,7 @@ def read_experiment_config(path: Path, mode: str) -> ExperimentConfig:
|
|
|
25
26
|
if not isinstance(command, str) or not command.strip():
|
|
26
27
|
raise ValueError(f"{path}: command must be a string")
|
|
27
28
|
repeats = values.get("repeats", 1)
|
|
28
|
-
if
|
|
29
|
+
if not is_positive_int(repeats):
|
|
29
30
|
raise ValueError(f"{path}: repeats must be a positive integer")
|
|
30
31
|
params = values.get("params", {})
|
|
31
32
|
if not isinstance(params, dict):
|
|
@@ -43,4 +44,7 @@ def read_experiment_config(path: Path, mode: str) -> ExperimentConfig:
|
|
|
43
44
|
mode = values.get("mode", mode)
|
|
44
45
|
if mode not in MODES:
|
|
45
46
|
raise ValueError(f"{path}: mode must be fill or adhoc")
|
|
46
|
-
|
|
47
|
+
concurrency = values.get("concurrency", concurrency)
|
|
48
|
+
if not is_positive_int(concurrency):
|
|
49
|
+
raise ValueError(f"{path}: concurrency must be a positive integer")
|
|
50
|
+
return ExperimentConfig(command, repeats, params, name, counts, mode, concurrency)
|
|
@@ -13,7 +13,7 @@ def start_experiment(
|
|
|
13
13
|
config: LabnotesConfig,
|
|
14
14
|
name: str,
|
|
15
15
|
experiment_config: Path | None,
|
|
16
|
-
concurrency: int,
|
|
16
|
+
concurrency: int | None,
|
|
17
17
|
drive: Callable[[Start, str], list[dict[str, object]]],
|
|
18
18
|
) -> list[dict[str, object]]:
|
|
19
19
|
if experiment_config is None:
|
|
@@ -21,7 +21,11 @@ def start_experiment(
|
|
|
21
21
|
experiment_config = config.root / folder / "experiment.toml"
|
|
22
22
|
if not experiment_config.is_file():
|
|
23
23
|
raise ValueError(f"No experiment.toml for {name} at {experiment_config}.")
|
|
24
|
-
experiment = read_experiment_config(
|
|
24
|
+
experiment = read_experiment_config(
|
|
25
|
+
experiment_config, config.mode, config.concurrency
|
|
26
|
+
)
|
|
27
|
+
if concurrency is None:
|
|
28
|
+
concurrency = experiment.concurrency
|
|
25
29
|
runs = runs_parent(config.root, config.runs, name)
|
|
26
30
|
runs.mkdir(parents=True, exist_ok=True)
|
|
27
31
|
try:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|