labnotes 0.0.80__tar.gz → 0.0.81__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 (145) hide show
  1. {labnotes-0.0.80 → labnotes-0.0.81}/PKG-INFO +3 -2
  2. {labnotes-0.0.80 → labnotes-0.0.81}/README.md +2 -1
  3. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/context.md +2 -1
  4. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/remote_start.py +11 -1
  5. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tui/run_app.py +5 -1
  6. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tui/run_tui.py +2 -0
  7. {labnotes-0.0.80 → labnotes-0.0.81}/testing-conventions.toml +1 -1
  8. {labnotes-0.0.80 → labnotes-0.0.81}/.gitignore +0 -0
  9. {labnotes-0.0.80 → labnotes-0.0.81}/CHANGELOG.md +0 -0
  10. {labnotes-0.0.80 → labnotes-0.0.81}/MIGRATIONS.md +0 -0
  11. {labnotes-0.0.80 → labnotes-0.0.81}/pyproject.toml +0 -0
  12. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/__init__.py +0 -0
  13. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/__main__.py +0 -0
  14. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/asset_url.py +0 -0
  15. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/check_counts.py +0 -0
  16. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/cli.py +0 -0
  17. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/context_guide.py +0 -0
  18. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/count_groups.py +0 -0
  19. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/count_runs.py +0 -0
  20. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/create_app.py +0 -0
  21. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/create_experiment.py +0 -0
  22. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/create_note.py +0 -0
  23. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/__init__.py +0 -0
  24. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/control_run.py +0 -0
  25. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/daemon_app.py +0 -0
  26. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/daemon_client.py +0 -0
  27. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/daemon_running.py +0 -0
  28. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/daemon_server.py +0 -0
  29. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/describe_status.py +0 -0
  30. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/ensure_daemon.py +0 -0
  31. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/exit_when_idle.py +0 -0
  32. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/run_daemon.py +0 -0
  33. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/run_logs.py +0 -0
  34. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/serve_daemon.py +0 -0
  35. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/socket_path.py +0 -0
  36. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/stop_runs.py +0 -0
  37. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/watch_daemon.py +0 -0
  38. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon/watch_status.py +0 -0
  39. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/daemon_command.py +0 -0
  40. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/data_html.py +0 -0
  41. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/default_config_text.py +0 -0
  42. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/default_counts.py +0 -0
  43. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/drain_watch.py +0 -0
  44. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/experiment_notes.py +0 -0
  45. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/experiment_runs.py +0 -0
  46. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/experiments.py +0 -0
  47. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/file_changes.py +0 -0
  48. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/format_duration.py +0 -0
  49. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/format_started.py +0 -0
  50. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/format_value.py +0 -0
  51. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/group_runs.py +0 -0
  52. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/init.py +0 -0
  53. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/invocation_started.py +0 -0
  54. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/is_positive_int.py +0 -0
  55. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/list_experiments.py +0 -0
  56. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/list_runs.py +0 -0
  57. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/load_config.py +0 -0
  58. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/load_experiment.py +0 -0
  59. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/load_run.py +0 -0
  60. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/models.py +0 -0
  61. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/modes.py +0 -0
  62. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/nests_runs.py +0 -0
  63. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/note_path.py +0 -0
  64. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/notebook_kernel.py +0 -0
  65. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/output_html.py +0 -0
  66. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/parse_run_view.py +0 -0
  67. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/print_rows.py +0 -0
  68. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/python_blocks.py +0 -0
  69. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/read_config.py +0 -0
  70. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/read_path.py +0 -0
  71. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/render_markdown.py +0 -0
  72. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/run_command.py +0 -0
  73. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/run_control.py +0 -0
  74. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/run_output.py +0 -0
  75. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/run_status.py +0 -0
  76. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/__init__.py +0 -0
  77. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/describe_event.py +0 -0
  78. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/execute_run.py +0 -0
  79. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/hold_folder.py +0 -0
  80. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/new_param_run_id.py +0 -0
  81. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/new_run_id.py +0 -0
  82. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/new_stamped_run_id.py +0 -0
  83. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/param_args.py +0 -0
  84. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/param_grid.py +0 -0
  85. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/param_run_name.py +0 -0
  86. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/plan_runs.py +0 -0
  87. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/prepare_experiment.py +0 -0
  88. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/read_experiment_config.py +0 -0
  89. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/run_experiment.py +0 -0
  90. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/run_folder.py +0 -0
  91. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/run_headless.py +0 -0
  92. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/runs_parent.py +0 -0
  93. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/shell_command.py +0 -0
  94. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/signal_tree.py +0 -0
  95. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/stop_then_kill.py +0 -0
  96. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/wait_for_tree.py +0 -0
  97. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/runner/write_run_json.py +0 -0
  98. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/save_conflict_copy.py +0 -0
  99. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/save_note.py +0 -0
  100. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/saved_outputs.py +0 -0
  101. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/serve_app.py +0 -0
  102. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/server.py +0 -0
  103. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/shared_params.py +0 -0
  104. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/sort_href.py +0 -0
  105. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/sql_quote.py +0 -0
  106. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/experiment.js +0 -0
  107. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/labnotes.css +0 -0
  108. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/local-time.js +0 -0
  109. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/new-note.js +0 -0
  110. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/note-edit.js +0 -0
  111. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/note-editor.js +0 -0
  112. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/row-link.js +0 -0
  113. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/run-cell.js +0 -0
  114. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/run-output.js +0 -0
  115. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/static/view-toggle.js +0 -0
  116. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/summarize_config.py +0 -0
  117. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/__init__.py +0 -0
  118. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/experiment_rows.py +0 -0
  119. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/experiment_run_ids.py +0 -0
  120. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/file_prefix.py +0 -0
  121. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/file_text.py +0 -0
  122. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/iso_time.py +0 -0
  123. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/list_experiment_runs.py +0 -0
  124. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/note_text.py +0 -0
  125. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/open_tables.py +0 -0
  126. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/path_glob.py +0 -0
  127. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/path_pattern.py +0 -0
  128. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/read_experiment.py +0 -0
  129. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/read_file.py +0 -0
  130. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/read_log.py +0 -0
  131. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/read_run.py +0 -0
  132. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tables/summarize_experiments.py +0 -0
  133. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/templates/base.html +0 -0
  134. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/templates/editor_imports.html +0 -0
  135. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/templates/experiment.html +0 -0
  136. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/templates/index.html +0 -0
  137. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/templates/note.html +0 -0
  138. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/templates/run.html +0 -0
  139. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tui/__init__.py +0 -0
  140. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tui/dim.py +0 -0
  141. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tui/format_elapsed.py +0 -0
  142. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/tui/runs_table.py +0 -0
  143. {labnotes-0.0.80 → labnotes-0.0.81}/src/labnotes/wait_for_note.py +0 -0
  144. {labnotes-0.0.80 → labnotes-0.0.81}/tests/integration/conftest.py +0 -0
  145. {labnotes-0.0.80 → labnotes-0.0.81}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labnotes
3
- Version: 0.0.80
3
+ Version: 0.0.81
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>
@@ -113,7 +113,8 @@ line per event instead.
113
113
  kills them. Closing the terminal or sending SIGTERM stops them the same way,
114
114
  then kills any still going 5 seconds later.
115
115
  - A second `run` of the same experiment fails while the first holds the lock.
116
- - It exits 0 even if runs fail; the summary line counts failures.
116
+ - It exits 0 even if runs fail; the summary line counts failures. If it can't
117
+ start or reach the daemon, it prints the cause on one line and exits 1.
117
118
 
118
119
  `labnotes server` serves a local site at http://127.0.0.1:8000 from the same
119
120
  `.labnotes.toml`: a table of experiments, and a page per experiment with its
@@ -89,7 +89,8 @@ line per event instead.
89
89
  kills them. Closing the terminal or sending SIGTERM stops them the same way,
90
90
  then kills any still going 5 seconds later.
91
91
  - A second `run` of the same experiment fails while the first holds the lock.
92
- - It exits 0 even if runs fail; the summary line counts failures.
92
+ - It exits 0 even if runs fail; the summary line counts failures. If it can't
93
+ start or reach the daemon, it prints the cause on one line and exits 1.
93
94
 
94
95
  `labnotes server` serves a local site at http://127.0.0.1:8000 from the same
95
96
  `.labnotes.toml`: a table of experiments, and a page per experiment with its
@@ -130,6 +130,7 @@ going. Elsewhere, it prints a line per event instead.
130
130
  running experiment: `kill`, `retry`, `run_next` or `toggle` a run,
131
131
  `set_concurrency` to a number, `interrupt` or `finish`.
132
132
  - A second `run` of the same experiment fails while the first is going.
133
- - It exits 0 even if runs fail; the summary line counts failures.
133
+ - It exits 0 even if runs fail; the summary line counts failures. If it can't
134
+ start or reach the daemon, it prints the cause on one line and exits 1.
134
135
 
135
136
  `uvx labnotes server` serves the experiments, their markdown files and their runs as a local site, read from the same `.labnotes.toml`. An experiment's page shows its `experiment.toml` on one line, then a Runs tab with a table of its runs and a Notebooks tab with one tab per markdown file. Clicking a run opens its `stdout.log` and `stderr.log` together, followed as they're written until the run ends.
@@ -17,6 +17,13 @@ def remote_start(
17
17
  concurrency: int | None,
18
18
  ) -> Start:
19
19
  async def start(report: Report, listen: Listen) -> list[dict[str, object]]:
20
+ try:
21
+ return await follow(report, listen)
22
+ except (OSError, httpx2.TransportError) as error:
23
+ cause = str(error) or type(error).__name__
24
+ raise ValueError(f"Can't reach the labnotes daemon: {cause}") from error
25
+
26
+ async def follow(report: Report, listen: Listen) -> list[dict[str, object]]:
20
27
  await ensure_daemon(config)
21
28
  sending: set[asyncio.Task[httpx2.Response]] = set()
22
29
  results: list[dict[str, object]] = []
@@ -25,7 +32,10 @@ def remote_start(
25
32
  client.stream("GET", "/events") as response,
26
33
  ):
27
34
  events = aiter(httpx2.EventSource(response))
28
- connected: dict[str, object] = (await anext(events)).json() # type: ignore[assignment]
35
+ first = await anext(events, None)
36
+ if first is None:
37
+ raise ValueError("Lost the labnotes daemon.")
38
+ connected: dict[str, object] = first.json() # type: ignore[assignment]
29
39
  reply = await client.post(
30
40
  f"/experiments/{name}/run",
31
41
  json={
@@ -47,6 +47,7 @@ class RunApp(App[None]):
47
47
  self.start = start
48
48
  self.title = title
49
49
  self.results: list[dict[str, object]] = []
50
+ self.error: Exception | None = None
50
51
  self.controls = Controls(
51
52
  lambda: None,
52
53
  lambda run: None,
@@ -100,7 +101,10 @@ class RunApp(App[None]):
100
101
  self.run_worker(self.drive())
101
102
 
102
103
  async def drive(self) -> None:
103
- self.results = await self.start(self.show_event, self.listen)
104
+ try:
105
+ self.results = await self.start(self.show_event, self.listen)
106
+ except Exception as error:
107
+ self.error = error
104
108
  self.exit()
105
109
 
106
110
  def listen(self, controls: Controls) -> None:
@@ -5,4 +5,6 @@ from labnotes.tui.run_app import RunApp
5
5
  def run_tui(start: Start, title: str) -> list[dict[str, object]]:
6
6
  app = RunApp(start, title)
7
7
  app.run()
8
+ if app.error is not None:
9
+ raise app.error
8
10
  return app.results
@@ -37,7 +37,7 @@ reason = "start answers 202, 400, 409 or 500, so every status but 202 is above i
37
37
  [[python.exempt]]
38
38
  path = "src/labnotes/daemon/remote_start.py"
39
39
  rules = ["mutation"]
40
- lines = [39]
40
+ lines = [49]
41
41
  reason = "the daemon answers a run with 202, 400, 409 or 500, so every status but 202 is above it: != equals >"
42
42
 
43
43
  [[python.exempt]]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes