labnotes 0.0.37__tar.gz → 0.0.39__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.37 → labnotes-0.0.39}/PKG-INFO +1 -1
  2. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/experiment_progress.py +2 -0
  3. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/summarize_config.py +3 -1
  4. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/templates/experiment.html +5 -4
  5. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tui/run_app.py +14 -9
  6. {labnotes-0.0.37 → labnotes-0.0.39}/.gitignore +0 -0
  7. {labnotes-0.0.37 → labnotes-0.0.39}/CHANGELOG.md +0 -0
  8. {labnotes-0.0.37 → labnotes-0.0.39}/MIGRATIONS.md +0 -0
  9. {labnotes-0.0.37 → labnotes-0.0.39}/README.md +0 -0
  10. {labnotes-0.0.37 → labnotes-0.0.39}/pyproject.toml +0 -0
  11. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/__init__.py +0 -0
  12. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/asset_url.py +0 -0
  13. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/cell_progress.py +0 -0
  14. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/check_counts.py +0 -0
  15. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/cli.py +0 -0
  16. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/context.md +0 -0
  17. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/context_guide.py +0 -0
  18. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/count_runs.py +0 -0
  19. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/create_app.py +0 -0
  20. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/create_experiment.py +0 -0
  21. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/data_html.py +0 -0
  22. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/default_config_text.py +0 -0
  23. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/default_counts.py +0 -0
  24. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/drain_watch.py +0 -0
  25. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/experiment_notes.py +0 -0
  26. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/experiment_runs.py +0 -0
  27. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/experiments.py +0 -0
  28. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/format_value.py +0 -0
  29. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/init.py +0 -0
  30. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/list_experiments.py +0 -0
  31. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/list_runs.py +0 -0
  32. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/load_config.py +0 -0
  33. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/load_experiment.py +0 -0
  34. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/models.py +0 -0
  35. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/notebook_kernel.py +0 -0
  36. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/output_html.py +0 -0
  37. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/parse_run_view.py +0 -0
  38. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/pivot_cells.py +0 -0
  39. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/print_rows.py +0 -0
  40. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/python_blocks.py +0 -0
  41. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/read_config.py +0 -0
  42. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/read_path.py +0 -0
  43. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/render_markdown.py +0 -0
  44. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/__init__.py +0 -0
  45. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/describe_event.py +0 -0
  46. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/execute_run.py +0 -0
  47. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/hold_folder.py +0 -0
  48. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/new_invocation_id.py +0 -0
  49. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/new_run_id.py +0 -0
  50. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/param_args.py +0 -0
  51. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/param_grid.py +0 -0
  52. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/plan_runs.py +0 -0
  53. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/read_experiment_config.py +0 -0
  54. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/run_experiment.py +0 -0
  55. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/run_folder.py +0 -0
  56. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/run_headless.py +0 -0
  57. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/runs_parent.py +0 -0
  58. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/shell_command.py +0 -0
  59. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/start_experiment.py +0 -0
  60. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/stop_then_kill.py +0 -0
  61. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/wait_for_group.py +0 -0
  62. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/runner/write_run_json.py +0 -0
  63. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/saved_outputs.py +0 -0
  64. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/serve_app.py +0 -0
  65. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/server.py +0 -0
  66. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/sort_href.py +0 -0
  67. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/sql_quote.py +0 -0
  68. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/static/labnotes.css +0 -0
  69. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/static/row-link.js +0 -0
  70. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/static/run-cell.js +0 -0
  71. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/static/view-toggle.js +0 -0
  72. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/stop_idle_kernels.py +0 -0
  73. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/__init__.py +0 -0
  74. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/experiment_rows.py +0 -0
  75. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/file_prefix.py +0 -0
  76. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/iso_time.py +0 -0
  77. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/list_experiment_runs.py +0 -0
  78. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/open_tables.py +0 -0
  79. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/path_glob.py +0 -0
  80. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/path_pattern.py +0 -0
  81. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/read_experiment.py +0 -0
  82. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/read_file.py +0 -0
  83. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/read_run.py +0 -0
  84. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tables/summarize_experiments.py +0 -0
  85. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/templates/base.html +0 -0
  86. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/templates/index.html +0 -0
  87. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/templates/macros.html +0 -0
  88. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tui/__init__.py +0 -0
  89. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tui/dim.py +0 -0
  90. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tui/format_elapsed.py +0 -0
  91. {labnotes-0.0.37 → labnotes-0.0.39}/src/labnotes/tui/run_tui.py +0 -0
  92. {labnotes-0.0.37 → labnotes-0.0.39}/testing-conventions.toml +0 -0
  93. {labnotes-0.0.37 → labnotes-0.0.39}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labnotes
3
- Version: 0.0.37
3
+ Version: 0.0.39
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>
@@ -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
  )
@@ -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>
@@ -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, "pending", "")
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, "running", format_elapsed(0))
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 = event["error"] or f"exited {event['exit_code']}"
126
- style = "red" if event["error"] or event["exit_code"] else ""
127
- if style:
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("deselected"))
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("pending"))
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, "pending", ""))]
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("skipped"))
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