labnotes 0.0.129__tar.gz → 0.0.130__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 (216) hide show
  1. {labnotes-0.0.129 → labnotes-0.0.130}/PKG-INFO +1 -1
  2. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/context.md +13 -10
  3. labnotes-0.0.129/src/labnotes/runner/fill_ids.py → labnotes-0.0.130/src/labnotes/runner/fill_dirs.py +2 -2
  4. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/fill_experiment_env.py +10 -7
  5. labnotes-0.0.130/src/labnotes/runner/hook_dirs.py +21 -0
  6. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/run_experiment.py +32 -23
  7. labnotes-0.0.129/src/labnotes/runner/hook_ids.py +0 -14
  8. {labnotes-0.0.129 → labnotes-0.0.130}/.gitignore +0 -0
  9. {labnotes-0.0.129 → labnotes-0.0.130}/CHANGELOG.md +0 -0
  10. {labnotes-0.0.129 → labnotes-0.0.130}/MIGRATIONS.md +0 -0
  11. {labnotes-0.0.129 → labnotes-0.0.130}/README.md +0 -0
  12. {labnotes-0.0.129 → labnotes-0.0.130}/pyproject.toml +0 -0
  13. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/__init__.py +0 -0
  14. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/__main__.py +0 -0
  15. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/asset_url.py +0 -0
  16. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/check_counts.py +0 -0
  17. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/cli.py +0 -0
  18. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/compose_experiment.py +0 -0
  19. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/context_guide.py +0 -0
  20. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/count_groups.py +0 -0
  21. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/count_runs.py +0 -0
  22. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/create_app.py +0 -0
  23. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/create_experiment.py +0 -0
  24. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/create_note.py +0 -0
  25. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/__init__.py +0 -0
  26. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/control_run.py +0 -0
  27. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/daemon_app.py +0 -0
  28. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/daemon_client.py +0 -0
  29. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/daemon_running.py +0 -0
  30. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/daemon_server.py +0 -0
  31. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/describe_status.py +0 -0
  32. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/ensure_daemon.py +0 -0
  33. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/exit_when_idle.py +0 -0
  34. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/finalize_lost_runs.py +0 -0
  35. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/last_stderr.py +0 -0
  36. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/remote_start.py +0 -0
  37. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/run_daemon.py +0 -0
  38. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/run_logs.py +0 -0
  39. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/serve_daemon.py +0 -0
  40. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/socket_path.py +0 -0
  41. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/stop_runs.py +0 -0
  42. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/watch_daemon.py +0 -0
  43. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon/watch_status.py +0 -0
  44. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/daemon_command.py +0 -0
  45. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/data_html.py +0 -0
  46. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/default_config_text.py +0 -0
  47. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/default_counts.py +0 -0
  48. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/drain_watch.py +0 -0
  49. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/experiment_notes.py +0 -0
  50. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/experiment_runs.py +0 -0
  51. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/experiments.py +0 -0
  52. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/file_changes.py +0 -0
  53. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/format_duration.py +0 -0
  54. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/format_started.py +0 -0
  55. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/format_value.py +0 -0
  56. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/grid_cell.py +0 -0
  57. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/group_runs.py +0 -0
  58. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/init.py +0 -0
  59. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/invocation_started.py +0 -0
  60. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/is_non_negative_int.py +0 -0
  61. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/is_non_negative_number.py +0 -0
  62. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/is_positive_int.py +0 -0
  63. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/list_experiments.py +0 -0
  64. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/list_runs.py +0 -0
  65. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/load_config.py +0 -0
  66. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/load_experiment.py +0 -0
  67. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/load_run.py +0 -0
  68. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/log.py +0 -0
  69. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/log_path.py +0 -0
  70. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/memory_interval.py +0 -0
  71. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/models.py +0 -0
  72. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/modes.py +0 -0
  73. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/nests_runs.py +0 -0
  74. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/note_path.py +0 -0
  75. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/notebook_kernel.py +0 -0
  76. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/output_html.py +0 -0
  77. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/parse_run_view.py +0 -0
  78. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/parse_subset.py +0 -0
  79. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/pivot_runs.py +0 -0
  80. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/print_rows.py +0 -0
  81. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/python_blocks.py +0 -0
  82. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/read_config.py +0 -0
  83. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/read_path.py +0 -0
  84. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/render_markdown.py +0 -0
  85. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/retries.py +0 -0
  86. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/run_command.py +0 -0
  87. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/run_control.py +0 -0
  88. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/run_output.py +0 -0
  89. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/run_status.py +0 -0
  90. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/__init__.py +0 -0
  91. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/cgroup_memory.py +0 -0
  92. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/check_args.py +0 -0
  93. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/check_subset.py +0 -0
  94. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/container_cgroup.py +0 -0
  95. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/container_memory.py +0 -0
  96. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/describe_event.py +0 -0
  97. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/docker_output.py +0 -0
  98. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/execute_run.py +0 -0
  99. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/exit_signal.py +0 -0
  100. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/flag_name.py +0 -0
  101. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/hold_folder.py +0 -0
  102. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/in_subset.py +0 -0
  103. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/invocation_hook.py +0 -0
  104. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/invocation_meta.py +0 -0
  105. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/new_param_run_id.py +0 -0
  106. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/new_run_id.py +0 -0
  107. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/new_stamped_run_id.py +0 -0
  108. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/param_args.py +0 -0
  109. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/param_grid.py +0 -0
  110. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/param_run_name.py +0 -0
  111. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/plan_runs.py +0 -0
  112. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/prepare_experiment.py +0 -0
  113. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/read_experiment_config.py +0 -0
  114. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/record_memory.py +0 -0
  115. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/run_folder.py +0 -0
  116. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/run_headless.py +0 -0
  117. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/runs_parent.py +0 -0
  118. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/shell_command.py +0 -0
  119. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/signal_tree.py +0 -0
  120. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/stop_then_kill.py +0 -0
  121. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/wait_for_tree.py +0 -0
  122. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runner/write_run_json.py +0 -0
  123. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/runs_view_command.py +0 -0
  124. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/save_conflict_copy.py +0 -0
  125. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/save_note.py +0 -0
  126. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/saved_outputs.py +0 -0
  127. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/serve_app.py +0 -0
  128. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/server.py +0 -0
  129. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/shared_params.py +0 -0
  130. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/sort_href.py +0 -0
  131. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/sql_quote.py +0 -0
  132. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/elapsed.js +0 -0
  133. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/experiment.js +0 -0
  134. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/labnotes.css +0 -0
  135. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/local-time.js +0 -0
  136. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/new-note.js +0 -0
  137. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/note-edit.js +0 -0
  138. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/note-editor.js +0 -0
  139. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/row-link.js +0 -0
  140. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/run-cell.js +0 -0
  141. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/run-output.js +0 -0
  142. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/static/view-toggle.js +0 -0
  143. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/summarize_config.py +0 -0
  144. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/__init__.py +0 -0
  145. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/experiment_rows.py +0 -0
  146. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/experiment_run_ids.py +0 -0
  147. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/experiment_toml.py +0 -0
  148. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/experiments_ddl.py +0 -0
  149. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/file_prefix.py +0 -0
  150. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/file_text.py +0 -0
  151. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/iso_time.py +0 -0
  152. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/list_experiment_runs.py +0 -0
  153. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/note_text.py +0 -0
  154. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/open_tables.py +0 -0
  155. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/path_glob.py +0 -0
  156. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/path_pattern.py +0 -0
  157. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_blocks.py +0 -0
  158. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_experiment.py +0 -0
  159. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_file.py +0 -0
  160. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_log.py +0 -0
  161. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_memory.py +0 -0
  162. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_run.py +0 -0
  163. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/read_run_file.py +0 -0
  164. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/runs_columns.py +0 -0
  165. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tables/summarize_experiments.py +0 -0
  166. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/templates/base.html +0 -0
  167. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/templates/editor_imports.html +0 -0
  168. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/templates/experiment.html +0 -0
  169. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/templates/index.html +0 -0
  170. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/templates/note.html +0 -0
  171. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/templates/run.html +0 -0
  172. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/__init__.py +0 -0
  173. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/browse_app.py +0 -0
  174. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/browse_tui.py +0 -0
  175. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/check_view_response.py +0 -0
  176. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/config.py +0 -0
  177. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/dim.py +0 -0
  178. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/experiment_screen.py +0 -0
  179. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/experiments_screen.py +0 -0
  180. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/fill_table.py +0 -0
  181. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/format_cell.py +0 -0
  182. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/format_elapsed.py +0 -0
  183. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/group_cells.py +0 -0
  184. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/invocation_columns.py +0 -0
  185. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/invocation_rows.py +0 -0
  186. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/leave_prompt.py +0 -0
  187. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/log_block.py +0 -0
  188. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/log_blocks.py +0 -0
  189. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/native_rows.py +0 -0
  190. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/reload_on_change.py +0 -0
  191. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/run_app.py +0 -0
  192. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/run_cells.py +0 -0
  193. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/run_output.py +0 -0
  194. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/run_screen.py +0 -0
  195. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/run_tui.py +0 -0
  196. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/runs_table.py +0 -0
  197. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/runs_view.py +0 -0
  198. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/stopped_title.py +0 -0
  199. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/view_column.py +0 -0
  200. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/tui/view_process.py +0 -0
  201. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/utils/__init__.py +0 -0
  202. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/utils/format_bytes.py +0 -0
  203. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/utils/process_alive.py +0 -0
  204. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/utils/run_usage.py +0 -0
  205. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/utils/tree_rss.py +0 -0
  206. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/utils/tree_usage.py +0 -0
  207. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/view/__init__.py +0 -0
  208. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/view/answer.py +0 -0
  209. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/view/build.py +0 -0
  210. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/view/respond.py +0 -0
  211. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/view/serve.py +0 -0
  212. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/wait_for_note.py +0 -0
  213. {labnotes-0.0.129 → labnotes-0.0.130}/src/labnotes/watch_rows.py +0 -0
  214. {labnotes-0.0.129 → labnotes-0.0.130}/testing-conventions.toml +0 -0
  215. {labnotes-0.0.129 → labnotes-0.0.130}/tests/integration/conftest.py +0 -0
  216. {labnotes-0.0.129 → labnotes-0.0.130}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labnotes
3
- Version: 0.0.129
3
+ Version: 0.0.130
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>
@@ -72,10 +72,9 @@ Each run gets a new run folder. In `matrix` mode it is named for the UTC time it
72
72
  its folder the same way. One that plans more gets one folder named that way, and its runs nest
73
73
  inside it (`runs/20261020-000429-brave-fox/quiet-river`); the run id is that path under `runs/`. Either way, folder listings sort by start. `command` runs in a shell from the root, with
74
74
  `{run_dir}` replaced by the run folder's absolute path. Pass it to the
75
- script so it writes its outputs there. `{run_id}` becomes the run id, and
76
- `{invocation_id}` an id every run of one `run` command shares: the run id when
77
- it plans one run, else the adhoc invocation folder's name, or in `matrix` mode a
78
- stamped id that names no folder. All three are shell-quoted.
75
+ script so it writes its outputs there. `{invocation_dir}` is the shared adhoc
76
+ group folder's absolute path when several runs are planned; otherwise it equals
77
+ each run's `{run_dir}`. Both placeholders are shell-quoted.
79
78
  Each param is appended as `--name value`, with the name as written (use
80
79
  `source-language` for a `--source-language` flag), booleans as 0 or 1, and lists
81
80
  and tables as JSON. labnotes writes `run.json` (params, `command`, created,
@@ -96,16 +95,20 @@ the value from the start, even if the code changed while they waited.
96
95
  commands run once per `run` from the root: setup before the first run starts,
97
96
  teardown after the last one ends, even if runs failed, were stopped, or setup
98
97
  failed (so teardown must cope with a partial setup). A failing setup starts no
99
- run; a failing teardown fails the invocation. Both get `{invocation_id}`, and
100
- `{run_id}` only when one run is planned; otherwise `{run_id}` there fails the
101
- invocation before anything starts.
98
+ run; a failing teardown fails the invocation. Both get `{invocation_dir}` only:
99
+ the shared folder for a multi-run adhoc invocation, or the run folder when one
100
+ run is planned. That folder exists before setup starts. In matrix mode with
101
+ several runs there is no shared folder, so `{invocation_dir}` in a hook fails.
102
+ `{run_dir}` is never filled in hooks; use `{invocation_dir}` instead. An
103
+ unavailable placeholder fails before anything starts.
102
104
  `[env]` in `experiment.toml` sets string environment values for `command`,
103
105
  `meta`, `setup`, and `teardown`. `[experiment.env]` in `.labnotes.toml`
104
106
  provides shared values; experiment values replace them by name. Variables in
105
107
  the environment that starts `labnotes experiments NAME run` win over both,
106
- including inline assignments. Values can use raw `{run_dir}`, `{run_id}` and
107
- `{invocation_id}` placeholders. In hooks and meta, `{run_id}` and `{run_dir}`
108
- require exactly one planned run. `LABNOTES_*` names are reserved for labnotes.
108
+ including inline assignments. Values can use raw `{run_dir}` and
109
+ `{invocation_dir}` placeholders. In hooks and meta, only `{invocation_dir}` is
110
+ available, and it requires one planned run in matrix mode.
111
+ `LABNOTES_*` names are reserved for labnotes.
109
112
  A run counts when it exited 0 and its `run.json` doesn't hold
110
113
  `"excluded": true`, so excluding a run by hand means adding that key; the next
111
114
  `run` replaces it. Other keys you add to `run.json` are kept and show in `run`.
@@ -2,7 +2,7 @@ import shlex
2
2
  from collections.abc import Mapping
3
3
 
4
4
 
5
- def fill_ids(command: str, ids: Mapping[str, str], *, quote: bool = True) -> str:
6
- for name, value in ids.items():
5
+ def fill_dirs(command: str, dirs: Mapping[str, str], *, quote: bool = True) -> str:
6
+ for name, value in dirs.items():
7
7
  command = command.replace(f"{{{name}}}", shlex.quote(value) if quote else value)
8
8
  return command
@@ -1,12 +1,12 @@
1
1
  from collections.abc import Mapping
2
2
 
3
- from labnotes.runner.fill_ids import fill_ids
3
+ from labnotes.runner.fill_dirs import fill_dirs
4
4
 
5
5
 
6
6
  def fill_experiment_env(
7
7
  configured: Mapping[str, str],
8
8
  inherited: Mapping[str, str],
9
- ids: Mapping[str, str],
9
+ dirs: Mapping[str, str],
10
10
  *,
11
11
  hook: str | None = None,
12
12
  runs: int = 1,
@@ -20,12 +20,15 @@ def fill_experiment_env(
20
20
  for key, value in configured.items():
21
21
  if key in caller:
22
22
  continue
23
- for name in ("run_dir", "run_id"):
24
- if f"{{{name}}}" in value and name not in ids:
23
+ if hook is not None and "{run_dir}" in value:
24
+ raise ValueError(
25
+ f"{hook} env.{key} uses {{run_dir}}; use {{invocation_dir}} instead."
26
+ )
27
+ for name in ("run_dir", "invocation_dir"):
28
+ if f"{{{name}}}" in value and name not in dirs:
25
29
  raise ValueError(
26
30
  f"{hook} env.{key} uses {{{name}}}, but this invocation plans "
27
- f"{runs} runs. {{{name}}} needs exactly one; "
28
- "use {invocation_id} instead."
31
+ f"{runs} runs. {{{name}}} needs exactly one run in this mode."
29
32
  )
30
- filled[key] = fill_ids(value, ids, quote=False)
33
+ filled[key] = fill_dirs(value, dirs, quote=False)
31
34
  return {**filled, **caller}
@@ -0,0 +1,21 @@
1
+ def hook_dirs(
2
+ hooks: dict[str, str | None], invocation_dir: str | None, run_dirs: list[str]
3
+ ) -> dict[str, str]:
4
+ match run_dirs:
5
+ case [run_dir]:
6
+ invocation_dir = invocation_dir or run_dir
7
+ available = {"invocation_dir": invocation_dir} if invocation_dir is not None else {}
8
+ for hook, command in hooks.items():
9
+ if command is None:
10
+ continue
11
+ if "{run_dir}" in command:
12
+ raise ValueError(
13
+ f"{hook} command {command} uses {{run_dir}}; "
14
+ "use {invocation_dir} instead."
15
+ )
16
+ if "{invocation_dir}" in command and invocation_dir is None:
17
+ raise ValueError(
18
+ f"{hook} command {command} uses {{invocation_dir}}, but this "
19
+ f"invocation plans {len(run_dirs)} runs and has no shared folder."
20
+ )
21
+ return available
@@ -2,6 +2,7 @@ import asyncio
2
2
  import json
3
3
  import os
4
4
  import signal
5
+ from pathlib import Path
5
6
 
6
7
  import psutil
7
8
 
@@ -15,8 +16,8 @@ from labnotes.models import (
15
16
  from labnotes.retries import RETRY_EXIT_CODE, RETRY_SECONDS
16
17
  from labnotes.runner.execute_run import execute_run
17
18
  from labnotes.runner.fill_experiment_env import fill_experiment_env
18
- from labnotes.runner.fill_ids import fill_ids
19
- from labnotes.runner.hook_ids import hook_ids
19
+ from labnotes.runner.fill_dirs import fill_dirs
20
+ from labnotes.runner.hook_dirs import hook_dirs
20
21
  from labnotes.runner.in_subset import in_subset
21
22
  from labnotes.runner.invocation_hook import invocation_hook
22
23
  from labnotes.runner.invocation_meta import invocation_meta
@@ -80,27 +81,24 @@ async def run_experiment(
80
81
  run = new_id(params)
81
82
  planned.add(run)
82
83
  plan.append((run, params))
83
- hook_run_dir: str | None
84
- match plan:
85
- case [(invocation, _)]:
86
- hook_run_dir = str(
87
- run_folder(config.root, config.runs, name, invocation).resolve()
88
- )
89
- case _:
90
- invocation = group or new_stamped_run_id(taken)
91
- hook_run_dir = None
92
- planned.add(invocation)
84
+ run_dirs = [
85
+ str(run_folder(config.root, config.runs, name, run).resolve())
86
+ for run, _ in plan
87
+ ]
88
+ group_dir = (
89
+ str(run_folder(config.root, config.runs, name, group).resolve())
90
+ if group is not None
91
+ else None
92
+ )
93
93
  hooks = {
94
94
  "setup": experiment.setup,
95
95
  "teardown": experiment.teardown,
96
96
  "meta": experiment.meta,
97
97
  }
98
- ids = hook_ids(hooks, invocation, [run for run, _ in plan])
99
- if hook_run_dir is not None:
100
- ids["run_dir"] = hook_run_dir
98
+ dirs = hook_dirs(hooks, group_dir, run_dirs)
101
99
  hook_env = {
102
100
  hook: fill_experiment_env(
103
- experiment.env, inherited, ids, hook=hook, runs=len(plan)
101
+ experiment.env, inherited, dirs, hook=hook, runs=len(plan)
104
102
  )
105
103
  for hook, command in hooks.items()
106
104
  if command is not None
@@ -108,8 +106,10 @@ async def run_experiment(
108
106
  meta = None
109
107
  if experiment.meta is not None:
110
108
  meta = await invocation_meta(
111
- config.root, fill_ids(experiment.meta, ids), hook_env["meta"]
109
+ config.root, fill_dirs(experiment.meta, dirs), hook_env["meta"]
112
110
  )
111
+ if dirs:
112
+ Path(dirs["invocation_dir"]).mkdir(parents=True, exist_ok=True)
113
113
  runs = [{"run": run, "params": params} for run, params in plan]
114
114
  report(
115
115
  {
@@ -238,14 +238,21 @@ async def run_experiment(
238
238
 
239
239
  async def start(run: str, params: dict[str, object]) -> None:
240
240
  folder = run_folder(config.root, config.runs, name, run)
241
- folder.mkdir(parents=True)
241
+ folder.mkdir(parents=True, exist_ok=True)
242
+ run_invocation_dir = group_dir or str(folder.resolve())
242
243
  report({"event": "started", "run": run, "params": params, "folder": folder})
243
244
  running[run] = set()
244
245
  trees[run] = set()
245
246
  result = await execute_run(
246
247
  config.root,
247
248
  folder,
248
- fill_ids(experiment.command, {"run_id": run, "invocation_id": invocation}),
249
+ fill_dirs(
250
+ experiment.command,
251
+ {
252
+ "run_dir": str(folder.resolve()),
253
+ "invocation_dir": run_invocation_dir,
254
+ },
255
+ ),
249
256
  params,
250
257
  running[run],
251
258
  stopping,
@@ -262,8 +269,7 @@ async def run_experiment(
262
269
  inherited,
263
270
  {
264
271
  "run_dir": str(folder.resolve()),
265
- "run_id": run,
266
- "invocation_id": invocation,
272
+ "invocation_dir": run_invocation_dir,
267
273
  },
268
274
  ),
269
275
  )
@@ -282,7 +288,7 @@ async def run_experiment(
282
288
  await invocation_hook(
283
289
  config.root,
284
290
  "teardown",
285
- fill_ids(experiment.teardown, ids),
291
+ fill_dirs(experiment.teardown, dirs),
286
292
  hook_env["teardown"],
287
293
  )
288
294
 
@@ -292,7 +298,10 @@ async def run_experiment(
292
298
  if experiment.setup is not None:
293
299
  report({"event": "setting up"})
294
300
  await invocation_hook(
295
- config.root, "setup", fill_ids(experiment.setup, ids), hook_env["setup"]
301
+ config.root,
302
+ "setup",
303
+ fill_dirs(experiment.setup, dirs),
304
+ hook_env["setup"],
296
305
  )
297
306
  fill()
298
307
  await done.wait()
@@ -1,14 +0,0 @@
1
- def hook_ids(
2
- hooks: dict[str, str | None], invocation: str, runs: list[str]
3
- ) -> dict[str, str]:
4
- match runs:
5
- case [run]:
6
- return {"run_id": run, "invocation_id": invocation}
7
- for hook, command in hooks.items():
8
- if command is not None and "{run_id}" in command:
9
- raise ValueError(
10
- f"{hook} command {command} uses {{run_id}}, but this invocation plans "
11
- f"{len(runs)} runs. {{run_id}} needs exactly one; "
12
- "use {invocation_id} instead."
13
- )
14
- return {"invocation_id": invocation}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes