labnotes 0.0.118__tar.gz → 0.0.119__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 (205) hide show
  1. {labnotes-0.0.118 → labnotes-0.0.119}/PKG-INFO +3 -1
  2. {labnotes-0.0.118 → labnotes-0.0.119}/README.md +2 -0
  3. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/context.md +8 -0
  4. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/daemon_app.py +2 -0
  5. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/remote_start.py +2 -0
  6. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/experiments.py +13 -2
  7. labnotes-0.0.119/src/labnotes/parse_subset.py +10 -0
  8. labnotes-0.0.119/src/labnotes/runner/check_subset.py +13 -0
  9. labnotes-0.0.119/src/labnotes/runner/in_subset.py +5 -0
  10. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/prepare_experiment.py +4 -0
  11. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/run_experiment.py +6 -1
  12. {labnotes-0.0.118 → labnotes-0.0.119}/testing-conventions.toml +4 -4
  13. {labnotes-0.0.118 → labnotes-0.0.119}/.gitignore +0 -0
  14. {labnotes-0.0.118 → labnotes-0.0.119}/CHANGELOG.md +0 -0
  15. {labnotes-0.0.118 → labnotes-0.0.119}/MIGRATIONS.md +0 -0
  16. {labnotes-0.0.118 → labnotes-0.0.119}/pyproject.toml +0 -0
  17. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/__init__.py +0 -0
  18. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/__main__.py +0 -0
  19. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/asset_url.py +0 -0
  20. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/check_counts.py +0 -0
  21. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/cli.py +0 -0
  22. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/compose_experiment.py +0 -0
  23. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/context_guide.py +0 -0
  24. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/count_groups.py +0 -0
  25. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/count_runs.py +0 -0
  26. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/create_app.py +0 -0
  27. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/create_experiment.py +0 -0
  28. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/create_note.py +0 -0
  29. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/__init__.py +0 -0
  30. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/control_run.py +0 -0
  31. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/daemon_client.py +0 -0
  32. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/daemon_running.py +0 -0
  33. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/daemon_server.py +0 -0
  34. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/describe_status.py +0 -0
  35. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/ensure_daemon.py +0 -0
  36. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/exit_when_idle.py +0 -0
  37. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/finalize_lost_runs.py +0 -0
  38. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/last_stderr.py +0 -0
  39. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/run_daemon.py +0 -0
  40. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/run_logs.py +0 -0
  41. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/serve_daemon.py +0 -0
  42. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/socket_path.py +0 -0
  43. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/stop_runs.py +0 -0
  44. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/watch_daemon.py +0 -0
  45. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon/watch_status.py +0 -0
  46. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/daemon_command.py +0 -0
  47. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/data_html.py +0 -0
  48. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/default_config_text.py +0 -0
  49. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/default_counts.py +0 -0
  50. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/drain_watch.py +0 -0
  51. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/experiment_notes.py +0 -0
  52. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/experiment_runs.py +0 -0
  53. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/file_changes.py +0 -0
  54. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/format_duration.py +0 -0
  55. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/format_started.py +0 -0
  56. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/format_value.py +0 -0
  57. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/grid_cell.py +0 -0
  58. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/group_runs.py +0 -0
  59. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/init.py +0 -0
  60. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/invocation_started.py +0 -0
  61. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/is_non_negative_int.py +0 -0
  62. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/is_non_negative_number.py +0 -0
  63. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/is_positive_int.py +0 -0
  64. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/list_experiments.py +0 -0
  65. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/list_runs.py +0 -0
  66. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/load_config.py +0 -0
  67. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/load_experiment.py +0 -0
  68. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/load_run.py +0 -0
  69. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/log.py +0 -0
  70. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/log_path.py +0 -0
  71. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/memory_interval.py +0 -0
  72. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/models.py +0 -0
  73. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/modes.py +0 -0
  74. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/nests_runs.py +0 -0
  75. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/note_path.py +0 -0
  76. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/notebook_kernel.py +0 -0
  77. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/output_html.py +0 -0
  78. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/parse_run_view.py +0 -0
  79. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/pivot_runs.py +0 -0
  80. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/print_rows.py +0 -0
  81. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/python_blocks.py +0 -0
  82. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/read_config.py +0 -0
  83. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/read_path.py +0 -0
  84. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/render_markdown.py +0 -0
  85. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/retries.py +0 -0
  86. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/run_command.py +0 -0
  87. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/run_control.py +0 -0
  88. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/run_output.py +0 -0
  89. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/run_status.py +0 -0
  90. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/__init__.py +0 -0
  91. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/describe_event.py +0 -0
  92. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/execute_run.py +0 -0
  93. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/exit_signal.py +0 -0
  94. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/hold_folder.py +0 -0
  95. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/invocation_meta.py +0 -0
  96. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/new_param_run_id.py +0 -0
  97. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/new_run_id.py +0 -0
  98. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/new_stamped_run_id.py +0 -0
  99. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/param_args.py +0 -0
  100. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/param_grid.py +0 -0
  101. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/param_run_name.py +0 -0
  102. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/plan_runs.py +0 -0
  103. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/read_experiment_config.py +0 -0
  104. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/record_memory.py +0 -0
  105. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/run_folder.py +0 -0
  106. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/run_headless.py +0 -0
  107. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/runs_parent.py +0 -0
  108. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/shell_command.py +0 -0
  109. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/signal_tree.py +0 -0
  110. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/stop_then_kill.py +0 -0
  111. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/wait_for_tree.py +0 -0
  112. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runner/write_run_json.py +0 -0
  113. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/runs_view_command.py +0 -0
  114. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/save_conflict_copy.py +0 -0
  115. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/save_note.py +0 -0
  116. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/saved_outputs.py +0 -0
  117. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/serve_app.py +0 -0
  118. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/server.py +0 -0
  119. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/shared_params.py +0 -0
  120. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/sort_href.py +0 -0
  121. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/sql_quote.py +0 -0
  122. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/elapsed.js +0 -0
  123. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/experiment.js +0 -0
  124. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/labnotes.css +0 -0
  125. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/local-time.js +0 -0
  126. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/new-note.js +0 -0
  127. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/note-edit.js +0 -0
  128. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/note-editor.js +0 -0
  129. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/row-link.js +0 -0
  130. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/run-cell.js +0 -0
  131. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/run-output.js +0 -0
  132. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/static/view-toggle.js +0 -0
  133. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/summarize_config.py +0 -0
  134. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/__init__.py +0 -0
  135. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/experiment_rows.py +0 -0
  136. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/experiment_run_ids.py +0 -0
  137. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/experiment_toml.py +0 -0
  138. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/experiments_ddl.py +0 -0
  139. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/file_prefix.py +0 -0
  140. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/file_text.py +0 -0
  141. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/iso_time.py +0 -0
  142. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/list_experiment_runs.py +0 -0
  143. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/note_text.py +0 -0
  144. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/open_tables.py +0 -0
  145. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/path_glob.py +0 -0
  146. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/path_pattern.py +0 -0
  147. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_blocks.py +0 -0
  148. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_experiment.py +0 -0
  149. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_file.py +0 -0
  150. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_log.py +0 -0
  151. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_memory.py +0 -0
  152. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_run.py +0 -0
  153. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/read_run_file.py +0 -0
  154. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/runs_columns.py +0 -0
  155. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tables/summarize_experiments.py +0 -0
  156. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/templates/base.html +0 -0
  157. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/templates/editor_imports.html +0 -0
  158. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/templates/experiment.html +0 -0
  159. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/templates/index.html +0 -0
  160. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/templates/note.html +0 -0
  161. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/templates/run.html +0 -0
  162. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/__init__.py +0 -0
  163. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/browse_app.py +0 -0
  164. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/browse_tui.py +0 -0
  165. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/check_view_response.py +0 -0
  166. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/config.py +0 -0
  167. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/dim.py +0 -0
  168. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/experiment_screen.py +0 -0
  169. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/experiments_screen.py +0 -0
  170. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/fill_table.py +0 -0
  171. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/format_cell.py +0 -0
  172. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/format_elapsed.py +0 -0
  173. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/group_cells.py +0 -0
  174. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/invocation_columns.py +0 -0
  175. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/invocation_rows.py +0 -0
  176. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/leave_prompt.py +0 -0
  177. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/log_block.py +0 -0
  178. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/log_blocks.py +0 -0
  179. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/native_rows.py +0 -0
  180. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/reload_on_change.py +0 -0
  181. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/run_app.py +0 -0
  182. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/run_cells.py +0 -0
  183. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/run_output.py +0 -0
  184. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/run_screen.py +0 -0
  185. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/run_tui.py +0 -0
  186. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/runs_table.py +0 -0
  187. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/runs_view.py +0 -0
  188. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/stopped_title.py +0 -0
  189. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/view_column.py +0 -0
  190. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/tui/view_process.py +0 -0
  191. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/utils/__init__.py +0 -0
  192. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/utils/format_bytes.py +0 -0
  193. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/utils/process_alive.py +0 -0
  194. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/utils/run_usage.py +0 -0
  195. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/utils/tree_rss.py +0 -0
  196. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/utils/tree_usage.py +0 -0
  197. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/view/__init__.py +0 -0
  198. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/view/answer.py +0 -0
  199. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/view/build.py +0 -0
  200. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/view/respond.py +0 -0
  201. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/view/serve.py +0 -0
  202. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/wait_for_note.py +0 -0
  203. {labnotes-0.0.118 → labnotes-0.0.119}/src/labnotes/watch_rows.py +0 -0
  204. {labnotes-0.0.118 → labnotes-0.0.119}/tests/integration/conftest.py +0 -0
  205. {labnotes-0.0.118 → labnotes-0.0.119}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labnotes
3
- Version: 0.0.118
3
+ Version: 0.0.119
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>
@@ -120,6 +120,8 @@ line per event instead.
120
120
 
121
121
  - `--concurrency N` runs N at a time (default 1).
122
122
  - `-e PATH` reads another file instead of `experiment.toml`.
123
+ - `--PARAM=VALUE` runs only the cells where that param has that value, like
124
+ `--model=small`.
123
125
  - With runs going, Ctrl-C asks first. Enter (or a second Ctrl-C) leaves them
124
126
  running. `s` stops the running scripts and records their end, then kills any
125
127
  still going 5 seconds later. Escape goes back. SIGTERM stops them like `s`.
@@ -95,6 +95,8 @@ line per event instead.
95
95
 
96
96
  - `--concurrency N` runs N at a time (default 1).
97
97
  - `-e PATH` reads another file instead of `experiment.toml`.
98
+ - `--PARAM=VALUE` runs only the cells where that param has that value, like
99
+ `--model=small`.
98
100
  - With runs going, Ctrl-C asks first. Enter (or a second Ctrl-C) leaves them
99
101
  running. `s` stops the running scripts and records their end, then kills any
100
102
  still going 5 seconds later. Escape goes back. SIGTERM stops them like `s`.
@@ -151,6 +151,14 @@ going. Elsewhere, it prints a line per event instead.
151
151
  in `experiment.toml` sets it, then `concurrency` under `[experiments]` in
152
152
  `.labnotes.toml`, then 1.
153
153
  - `-e PATH` reads another file instead of `experiment.toml`.
154
+ - `--PARAM=VALUE` runs only the cells where that param has that value, e.g.
155
+ `labnotes experiments NAME run --model=small`. PARAM must be a key in
156
+ `[params]` and VALUE one of its values, written as it shows in `runs`
157
+ (`true`, `2`); anything else is an error. One value per param; give several
158
+ params to narrow further (`--model=small --lang=en`). It changes only what
159
+ this `run` starts: counts, progress and `repeats` still cover the full
160
+ matrix, so a later plain `run` fills in the rest. Use it instead of editing
161
+ `experiment.toml` to run a slice.
154
162
  - `--timeout SECONDS` stops any one run still going after that many seconds:
155
163
  SIGTERM, then SIGKILL 5 seconds later. Its
156
164
  `run.json` gets `"error": "timed out after ..."` and `"ended_by": "timeout"`
@@ -78,6 +78,7 @@ def daemon_app(config: LabnotesConfig) -> Starlette:
78
78
  name,
79
79
  None if path is None else Path(str(path)),
80
80
  body.get("concurrency"), # type: ignore[arg-type]
81
+ body.get("only"), # type: ignore[arg-type]
81
82
  )
82
83
  except ValueError as error:
83
84
  return refuse(400, str(error))
@@ -103,6 +104,7 @@ def daemon_app(config: LabnotesConfig) -> Starlette:
103
104
  lambda event: record({**event, "experiment": name}),
104
105
  listen,
105
106
  body.get("timeout"), # type: ignore[arg-type]
107
+ only=body.get("only"), # type: ignore[arg-type]
106
108
  )
107
109
  # Clients hear why the session ended; the daemon keeps serving.
108
110
  except Exception as failure: # noqa: BLE001
@@ -16,6 +16,7 @@ def remote_start(
16
16
  experiment_config: Path | None,
17
17
  concurrency: int | None,
18
18
  timeout: float | None = None,
19
+ only: dict[str, str] | None = None,
19
20
  ) -> Start:
20
21
  async def start(report: Report, listen: Listen) -> list[dict[str, object]]:
21
22
  try:
@@ -46,6 +47,7 @@ def remote_start(
46
47
  else str(experiment_config.resolve()),
47
48
  "concurrency": concurrency,
48
49
  "timeout": timeout,
50
+ "only": only,
49
51
  },
50
52
  )
51
53
  if reply.status_code != 202:
@@ -8,6 +8,7 @@ from labnotes.create_experiment import create_experiment
8
8
  from labnotes.daemon.remote_start import remote_start
9
9
  from labnotes.utils.format_bytes import format_bytes
10
10
  from labnotes.load_config import load_config
11
+ from labnotes.parse_subset import parse_subset
11
12
  from labnotes.print_rows import print_rows
12
13
  from labnotes.read_config import CONFIG_FILE
13
14
  from labnotes.runner.run_headless import run_headless
@@ -20,7 +21,9 @@ BYTES = ("memory", "size")
20
21
 
21
22
  @click.command(
22
23
  help="List experiments, show one, list its runs, or run it."
23
- " `new [NAME]` creates one."
24
+ " `new [NAME]` creates one. With run, --PARAM=VALUE runs only the"
25
+ " matrix cells where that param has that value.",
26
+ context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
24
27
  )
25
28
  @click.argument("name", required=False)
26
29
  @click.argument("action", required=False, metavar="[runs|run]")
@@ -74,7 +77,13 @@ def experiments(
74
77
  click.echo(f"Created {path / 'experiment.toml'}")
75
78
  return
76
79
  case str(), "run":
77
- start = remote_start(config, name, experiment_config, concurrency, timeout)
80
+ try:
81
+ only = parse_subset(ctx.args)
82
+ except ValueError as error:
83
+ raise click.UsageError(str(error)) from error
84
+ start = remote_start(
85
+ config, name, experiment_config, concurrency, timeout, only
86
+ )
78
87
  try:
79
88
  if sys.stdout.isatty() and sys.stderr.isatty():
80
89
  results = run_tui(start, name)
@@ -92,6 +101,8 @@ def experiments(
92
101
  passed = len(results) - failed - retried
93
102
  click.echo(f"{passed} passed, {failed} failed.{again}")
94
103
  return
104
+ if ctx.args:
105
+ raise click.UsageError(f"Unexpected {ctx.args[0]}. --PARAM=VALUE needs run.")
95
106
  if action not in (None, "runs"):
96
107
  raise click.UsageError(f"Unknown action {action}. Use runs or run.")
97
108
  if output_format is None and sys.stdout.isatty() and sys.stderr.isatty():
@@ -0,0 +1,10 @@
1
+ def parse_subset(args: list[str]) -> dict[str, str]:
2
+ only: dict[str, str] = {}
3
+ for arg in args:
4
+ param, equals, value = arg.removeprefix("--").partition("=")
5
+ if not arg.startswith("--") or not equals or not param:
6
+ raise ValueError(f"Unexpected {arg}. Pick params with --PARAM=VALUE.")
7
+ if param in only:
8
+ raise ValueError(f"--{param} given twice. Pass one value per param.")
9
+ only[param] = value
10
+ return only
@@ -0,0 +1,13 @@
1
+ from labnotes.format_value import format_value
2
+
3
+
4
+ def check_subset(params: dict[str, list[object]], only: dict[str, str]) -> None:
5
+ for param, value in only.items():
6
+ if param not in params:
7
+ declared = ", ".join(params) or "none"
8
+ raise ValueError(f"No param {param}. Params: {declared}.")
9
+ values = [format_value(option) for option in params[param]]
10
+ if value not in values:
11
+ raise ValueError(
12
+ f"No value {value} for {param}. Values: {', '.join(values)}."
13
+ )
@@ -0,0 +1,5 @@
1
+ from labnotes.format_value import format_value
2
+
3
+
4
+ def in_subset(cell: dict[str, object], only: dict[str, str]) -> bool:
5
+ return all(format_value(cell[param]) == value for param, value in only.items())
@@ -1,6 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
3
  from labnotes.models import ExperimentConfig, LabnotesConfig
4
+ from labnotes.runner.check_subset import check_subset
4
5
  from labnotes.runner.read_experiment_config import read_experiment_config
5
6
  from labnotes.tables.file_text import file_text
6
7
 
@@ -10,6 +11,7 @@ async def prepare_experiment(
10
11
  name: str,
11
12
  experiment_config: Path | None,
12
13
  concurrency: int | None,
14
+ only: dict[str, str] | None = None,
13
15
  ) -> tuple[ExperimentConfig, int]:
14
16
  if config.experiment not in (None, name):
15
17
  raise ValueError(
@@ -29,4 +31,6 @@ async def prepare_experiment(
29
31
  config.retries,
30
32
  config.defaults,
31
33
  )
34
+ if only:
35
+ check_subset(experiment.params, only)
32
36
  return experiment, experiment.concurrency if concurrency is None else concurrency
@@ -13,6 +13,7 @@ from labnotes.models import (
13
13
  )
14
14
  from labnotes.retries import RETRY_EXIT_CODE, RETRY_SECONDS
15
15
  from labnotes.runner.execute_run import execute_run
16
+ from labnotes.runner.in_subset import in_subset
16
17
  from labnotes.runner.invocation_meta import invocation_meta
17
18
  from labnotes.runner.new_param_run_id import new_param_run_id
18
19
  from labnotes.runner.new_stamped_run_id import new_stamped_run_id
@@ -36,6 +37,7 @@ async def run_experiment(
36
37
  listen: Listen,
37
38
  timeout: float | None = None,
38
39
  retry_seconds: float = RETRY_SECONDS,
40
+ only: dict[str, str] | None = None,
39
41
  ) -> list[dict[str, object]]:
40
42
  meta = None
41
43
  if experiment.meta is not None:
@@ -52,7 +54,10 @@ async def run_experiment(
52
54
  def taken(run: str) -> bool:
53
55
  return run in planned or run in existing
54
56
 
55
- cells = plan_runs(param_grid(experiment.params), experiment.repeats, finished)
57
+ grid = [
58
+ cell for cell in param_grid(experiment.params) if in_subset(cell, only or {})
59
+ ]
60
+ cells = plan_runs(grid, experiment.repeats, finished)
56
61
  group = None
57
62
  match experiment.mode:
58
63
  case "adhoc" if len(cells) > 1:
@@ -25,13 +25,13 @@ reason = "quiet counts up by one from zero, so it reaches IDLE_EXIT_SECONDS befo
25
25
  [[python.exempt]]
26
26
  path = "src/labnotes/daemon/daemon_app.py"
27
27
  rules = ["mutation"]
28
- lines = [132]
28
+ lines = [134]
29
29
  reason = "start answers 202, 400, 409 or 500, so every status but 202 is above it: != equals >"
30
30
 
31
31
  [[python.exempt]]
32
32
  path = "src/labnotes/daemon/remote_start.py"
33
33
  rules = ["mutation"]
34
- lines = [49]
34
+ lines = [51]
35
35
  reason = "the daemon answers a run with 202, 400, 409 or 500, so every status but 202 is above it: != equals >"
36
36
 
37
37
  [[python.exempt]]
@@ -67,7 +67,7 @@ reason = "WorkerState members are singletons, so is equals =="
67
67
  [[python.exempt]]
68
68
  path = "src/labnotes/runner/run_experiment.py"
69
69
  rules = ["mutation"]
70
- lines = [188, 269]
70
+ lines = [193, 274]
71
71
  reason = "a retry is only scheduled below the budget and each one adds one, so tried never passes retries: >= equals ==; both sides are small ints, which CPython caches, so is equals =="
72
72
 
73
73
  [[python.exempt]]
@@ -79,5 +79,5 @@ reason = "exit_code is non-negative here; when bit 7 is set, - 128 equals ^ 128,
79
79
  [[python.exempt]]
80
80
  path = "src/labnotes/experiments.py"
81
81
  rules = ["mutation"]
82
- lines = [109]
82
+ lines = [120]
83
83
  reason = "click hands back the \"json\" choice literal itself, so is not equals !="
File without changes
File without changes
File without changes
File without changes
File without changes