labnotes 0.0.36__tar.gz → 0.0.38__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.
Files changed (93) hide show
  1. {labnotes-0.0.36 → labnotes-0.0.38}/PKG-INFO +1 -1
  2. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/context.md +2 -1
  3. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/experiment_progress.py +2 -0
  4. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/run_experiment.py +8 -1
  5. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/summarize_config.py +3 -1
  6. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/templates/experiment.html +5 -4
  7. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tui/run_app.py +3 -0
  8. {labnotes-0.0.36 → labnotes-0.0.38}/.gitignore +0 -0
  9. {labnotes-0.0.36 → labnotes-0.0.38}/CHANGELOG.md +0 -0
  10. {labnotes-0.0.36 → labnotes-0.0.38}/MIGRATIONS.md +0 -0
  11. {labnotes-0.0.36 → labnotes-0.0.38}/README.md +0 -0
  12. {labnotes-0.0.36 → labnotes-0.0.38}/pyproject.toml +0 -0
  13. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/__init__.py +0 -0
  14. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/asset_url.py +0 -0
  15. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/cell_progress.py +0 -0
  16. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/check_counts.py +0 -0
  17. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/cli.py +0 -0
  18. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/context_guide.py +0 -0
  19. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/count_runs.py +0 -0
  20. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/create_app.py +0 -0
  21. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/create_experiment.py +0 -0
  22. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/data_html.py +0 -0
  23. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/default_config_text.py +0 -0
  24. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/default_counts.py +0 -0
  25. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/drain_watch.py +0 -0
  26. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/experiment_notes.py +0 -0
  27. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/experiment_runs.py +0 -0
  28. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/experiments.py +0 -0
  29. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/format_value.py +0 -0
  30. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/init.py +0 -0
  31. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/list_experiments.py +0 -0
  32. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/list_runs.py +0 -0
  33. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/load_config.py +0 -0
  34. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/load_experiment.py +0 -0
  35. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/models.py +0 -0
  36. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/notebook_kernel.py +0 -0
  37. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/output_html.py +0 -0
  38. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/parse_run_view.py +0 -0
  39. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/pivot_cells.py +0 -0
  40. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/print_rows.py +0 -0
  41. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/python_blocks.py +0 -0
  42. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/read_config.py +0 -0
  43. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/read_path.py +0 -0
  44. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/render_markdown.py +0 -0
  45. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/__init__.py +0 -0
  46. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/describe_event.py +0 -0
  47. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/execute_run.py +0 -0
  48. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/hold_folder.py +0 -0
  49. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/new_invocation_id.py +0 -0
  50. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/new_run_id.py +0 -0
  51. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/param_args.py +0 -0
  52. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/param_grid.py +0 -0
  53. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/plan_runs.py +0 -0
  54. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/read_experiment_config.py +0 -0
  55. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/run_folder.py +0 -0
  56. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/run_headless.py +0 -0
  57. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/runs_parent.py +0 -0
  58. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/shell_command.py +0 -0
  59. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/start_experiment.py +0 -0
  60. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/stop_then_kill.py +0 -0
  61. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/wait_for_group.py +0 -0
  62. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/runner/write_run_json.py +0 -0
  63. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/saved_outputs.py +0 -0
  64. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/serve_app.py +0 -0
  65. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/server.py +0 -0
  66. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/sort_href.py +0 -0
  67. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/sql_quote.py +0 -0
  68. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/static/labnotes.css +0 -0
  69. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/static/row-link.js +0 -0
  70. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/static/run-cell.js +0 -0
  71. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/static/view-toggle.js +0 -0
  72. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/stop_idle_kernels.py +0 -0
  73. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/__init__.py +0 -0
  74. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/experiment_rows.py +0 -0
  75. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/file_prefix.py +0 -0
  76. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/iso_time.py +0 -0
  77. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/list_experiment_runs.py +0 -0
  78. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/open_tables.py +0 -0
  79. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/path_glob.py +0 -0
  80. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/path_pattern.py +0 -0
  81. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/read_experiment.py +0 -0
  82. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/read_file.py +0 -0
  83. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/read_run.py +0 -0
  84. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tables/summarize_experiments.py +0 -0
  85. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/templates/base.html +0 -0
  86. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/templates/index.html +0 -0
  87. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/templates/macros.html +0 -0
  88. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tui/__init__.py +0 -0
  89. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tui/dim.py +0 -0
  90. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tui/format_elapsed.py +0 -0
  91. {labnotes-0.0.36 → labnotes-0.0.38}/src/labnotes/tui/run_tui.py +0 -0
  92. {labnotes-0.0.36 → labnotes-0.0.38}/testing-conventions.toml +0 -0
  93. {labnotes-0.0.36 → labnotes-0.0.38}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labnotes
3
- Version: 0.0.36
3
+ Version: 0.0.38
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>
@@ -100,7 +100,8 @@ Escape clears it. `D` deselects every pending run the filter shows. `k` stops th
100
100
  running run under the cursor; `k` again kills it. `+` and
101
101
  `-` change how many run at once; lowering it lets running runs
102
102
  finish. Enter on a run follows its `stdout.log`; `e` switches to
103
- `stderr.log` and back, and Escape returns to the table. `q` quits. Elsewhere, or with `--no-tui`, it prints a
103
+ `stderr.log` and back, and Escape returns to the table. An `adhoc` experiment that
104
+ plans a single run opens straight on its output. `q` quits. Elsewhere, or with `--no-tui`, it prints a
104
105
  line per event instead.
105
106
 
106
107
  - `--concurrency N` runs N at a time to start with (default 1).
@@ -19,6 +19,8 @@ async def experiment_progress(
19
19
  grouped = await count_runs(tables, source, completed_run, group_by=list(varies))
20
20
  cells = cell_progress(varies, grouped)
21
21
  progress["cells"] = cells
22
+ if summary["target"] is None:
23
+ return progress
22
24
  progress["filled"] = sum(
23
25
  min(cast(int, cell["completed"]), cast(int, runs_per_cell)) for cell in cells
24
26
  )
@@ -53,7 +53,14 @@ async def run_experiment(
53
53
  planned.add(run)
54
54
  plan.append((run, params))
55
55
  runs = [{"run": run, "params": params} for run, params in plan]
56
- report({"event": "planned", "runs": runs, "concurrency": concurrency})
56
+ report(
57
+ {
58
+ "event": "planned",
59
+ "runs": runs,
60
+ "concurrency": concurrency,
61
+ "mode": experiment.mode,
62
+ }
63
+ )
57
64
  running: dict[str, set[asyncio.subprocess.Process]] = {}
58
65
  stopped: set[str] = set()
59
66
  results: list[dict[str, object]] = []
@@ -15,12 +15,14 @@ def summarize_config(config: dict[str, object] | None) -> dict[str, object]:
15
15
  cells = prod(len(values) for values in varies.values())
16
16
  command = config.get("command")
17
17
  counts = config.get("counts")
18
+ adhoc = config.get("mode") == "adhoc"
18
19
  return {
19
20
  "fixed": {},
20
21
  "varies": varies,
21
22
  "cell_count": cells,
22
23
  "runs_per_cell": repeats,
23
- "target": cells * repeats if repeats is not None else None,
24
+ "target": cells * repeats if repeats is not None and not adhoc else None,
24
25
  "completed_run": counts if isinstance(counts, str) else DEFAULT_COUNTS,
26
+ "mode": "adhoc" if adhoc else "fill",
25
27
  "other": {} if command is None else {"command": command},
26
28
  }
@@ -32,7 +32,7 @@
32
32
  <div class="figure">
33
33
  <div class="figure-label">Cells</div>
34
34
  <div class="figure-value">{{ e.cell_count }}</div>
35
- <div class="figure-note">{% if e.runs_per_cell %}<span class="num">{{ e.runs_per_cell }}</span> runs each{% else %}no experiment.toml{% endif %}</div>
35
+ <div class="figure-note">{% if e.mode == "adhoc" %}ad-hoc, <span class="num">{{ e.runs_per_cell }}</span> runs each time{% elif e.runs_per_cell %}<span class="num">{{ e.runs_per_cell }}</span> runs each{% else %}no experiment.toml{% endif %}</div>
36
36
  </div>
37
37
  </section>
38
38
 
@@ -90,10 +90,11 @@
90
90
  <tr>
91
91
  {% for label in row.labels %}<th scope="row" class="label">{{ label | value }}</th>{% endfor %}
92
92
  {% for cell in row.cells %}
93
- {% set done = e.runs_per_cell and cell.completed >= e.runs_per_cell %}
93
+ {% set goal = e.runs_per_cell if e.mode == "fill" %}
94
+ {% set done = goal and cell.completed >= goal %}
94
95
  <td class="cell{{ ' done' if done }}{{ ' empty' if not cell.runs }}" title="{{ cell['values'].items() | map('join', ' = ') | join(', ') }}: {{ cell.completed }} complete of {{ cell.runs }} recorded">
95
- <span class="num">{{ cell.completed }}{% if e.runs_per_cell %}<span class="of">/{{ e.runs_per_cell }}</span>{% endif %}</span>
96
- {% if e.runs_per_cell %}{{ meter(cell.completed, e.runs_per_cell) }}{% endif %}
96
+ <span class="num">{{ cell.completed }}{% if goal %}<span class="of">/{{ goal }}</span>{% endif %}</span>
97
+ {% if goal %}{{ meter(cell.completed, goal) }}{% endif %}
97
98
  </td>
98
99
  {% endfor %}
99
100
  </tr>
@@ -107,6 +107,9 @@ class RunApp(App[None]):
107
107
  self.redraw(table.cursor_row)
108
108
  self.show_concurrency(event)
109
109
  self.show(describe_event(event))
110
+ match event["mode"], event["runs"]:
111
+ case "adhoc", [only]:
112
+ self.view(only["run"], "stdout") # type: ignore[index]
110
113
  case "started":
111
114
  self.idle = False
112
115
  self.pending.discard(run)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes