labnotes 0.1.1__tar.gz → 0.2.0__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.
- {labnotes-0.1.1 → labnotes-0.2.0}/PKG-INFO +3 -2
- {labnotes-0.1.1 → labnotes-0.2.0}/README.md +2 -1
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/context.md +11 -11
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/experiments.py +2 -1
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/parse_subset.py +3 -5
- labnotes-0.2.0/src/labnotes/runner/check_hook_placeholders.py +12 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/check_subset.py +7 -6
- labnotes-0.2.0/src/labnotes/runner/fill_experiment_env.py +23 -0
- labnotes-0.2.0/src/labnotes/runner/in_subset.py +5 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/placeholders.py +0 -1
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/prepare_experiment.py +1 -1
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/run_experiment.py +16 -16
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/start_experiment.py +1 -1
- labnotes-0.1.1/src/labnotes/runner/fill_experiment_env.py +0 -34
- labnotes-0.1.1/src/labnotes/runner/hook_dirs.py +0 -21
- labnotes-0.1.1/src/labnotes/runner/in_subset.py +0 -5
- {labnotes-0.1.1 → labnotes-0.2.0}/.gitignore +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/CHANGELOG.md +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/MIGRATIONS.md +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/pyproject.toml +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/__init__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/__main__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/cli.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/compose_experiment.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/count_groups.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/create_app.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/create_note.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/data_html.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/file_changes.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/format_duration.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/format_started.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/format_value.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/get_state.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/grid_cell.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/group_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/init.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/invocation_started.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/is_non_negative_int.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/is_non_negative_number.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/is_positive_int.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/load_config.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/load_run.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/log.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/log_path.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/memory_interval.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/models.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/modes.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/nests_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/note_path.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/output_html.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/pivot_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/read_config.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/read_path.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/retries.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/run_output.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/cgroup_memory.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/check_args.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/container_cgroup.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/container_memory.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/docker_output.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/exit_signal.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/fill_dirs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/finalize_lost_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/flag_name.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/invocation_hook.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/invocation_meta.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/new_param_run_id.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/param_run_name.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/project_snapshot.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/record_memory.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/run_git.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/signal_tree.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/wait_for_tree.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/runs_view_command.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/save_conflict_copy.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/save_note.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/server.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/set_state.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/shared_params.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/state_path.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/elapsed.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/experiment.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/local-time.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/new-note.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/note-edit.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/note-editor.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/run-output.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/experiment_run_ids.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/experiment_toml.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/experiments_ddl.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/file_text.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/note_text.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_blocks.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_log.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_memory.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/read_run_file.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/runs_columns.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/templates/editor_imports.html +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/templates/note.html +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/templates/run.html +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/browse_app.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/browse_tui.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/check_view_response.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/config.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/experiment_screen.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/experiments_screen.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/fill_table.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/format_cell.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/group_cells.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/invocation_columns.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/invocation_rows.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/leave_prompt.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/log_block.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/log_blocks.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/native_rows.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/reload_on_change.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/run_cells.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/run_output.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/run_screen.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/runs_view.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/stopped_title.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/view_column.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/tui/view_process.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/utils/__init__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/utils/format_bytes.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/utils/process_alive.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/utils/run_usage.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/utils/tree_rss.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/utils/tree_usage.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/view/__init__.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/view/answer.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/view/build.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/view/respond.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/view/serve.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/wait_for_note.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/src/labnotes/watch_rows.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/testing-conventions.toml +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/tests/conftest.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/tests/e2e/conftest.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/tests/integration/conftest.py +0 -0
- {labnotes-0.1.1 → labnotes-0.2.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: labnotes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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>
|
|
@@ -121,7 +121,8 @@ line per event instead.
|
|
|
121
121
|
- `--concurrency N` runs N at a time (default 1).
|
|
122
122
|
- `-e PATH` reads another file instead of `experiment.toml`.
|
|
123
123
|
- `--PARAM=VALUE` runs only the cells where that param has that value, like
|
|
124
|
-
`--model=small`.
|
|
124
|
+
`--model=small`. Repeat a param to run several values:
|
|
125
|
+
`--model=small --model=large`.
|
|
125
126
|
- With runs going, Ctrl-C asks first. Enter (or a second Ctrl-C) stops the running scripts and records their end,
|
|
126
127
|
then kills any still going 5 seconds later. Escape goes back. SIGTERM and
|
|
127
128
|
SIGHUP stop them the same way.
|
|
@@ -96,7 +96,8 @@ line per event instead.
|
|
|
96
96
|
- `--concurrency N` runs N at a time (default 1).
|
|
97
97
|
- `-e PATH` reads another file instead of `experiment.toml`.
|
|
98
98
|
- `--PARAM=VALUE` runs only the cells where that param has that value, like
|
|
99
|
-
`--model=small`.
|
|
99
|
+
`--model=small`. Repeat a param to run several values:
|
|
100
|
+
`--model=small --model=large`.
|
|
100
101
|
- With runs going, Ctrl-C asks first. Enter (or a second Ctrl-C) stops the running scripts and records their end,
|
|
101
102
|
then kills any still going 5 seconds later. Escape goes back. SIGTERM and
|
|
102
103
|
SIGHUP stop them the same way.
|
|
@@ -102,19 +102,17 @@ the value from the start, even if the code changed while they waited.
|
|
|
102
102
|
commands run once per `run` from the root: setup before the first run starts,
|
|
103
103
|
teardown after the last one ends, even if runs failed, were stopped, or setup
|
|
104
104
|
failed (so teardown must cope with a partial setup). A failing setup starts no
|
|
105
|
-
run; a failing teardown fails the invocation.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
several runs there is no shared folder, so `{invocation_dir}` in a hook fails.
|
|
109
|
-
`{run_dir}` is never filled in hooks; use `{invocation_dir}` instead. An
|
|
110
|
-
unavailable placeholder fails before anything starts.
|
|
105
|
+
run; a failing teardown fails the invocation. Hooks and `meta` get no folder
|
|
106
|
+
placeholders: `{run_dir}` or `{invocation_dir}` in one fails before anything
|
|
107
|
+
starts. Share values through state instead.
|
|
111
108
|
Setup can call `labnotes.set_state({"container": "abc"})`; runs and teardown read the
|
|
112
109
|
dict with `labnotes.get_state()`. Writes merge by top-level key, replacing an
|
|
113
110
|
existing value without dropping other keys. Values must be JSON serializable;
|
|
114
111
|
reading before any write returns `{}`. Runs can only read: `set_state` raises
|
|
115
112
|
`RuntimeError` there. Both functions raise outside an invocation and in `meta`.
|
|
116
113
|
Labnotes gives setup/teardown `LABNOTES_STATE` and runs `LABNOTES_RUN_STATE`,
|
|
117
|
-
pointing to `
|
|
114
|
+
pointing to `state.json` in the multi-run adhoc group folder or the lone run's
|
|
115
|
+
folder, or, without a shared folder, a temp
|
|
118
116
|
file kept through all runs and teardown and then removed. Queued runs and retries
|
|
119
117
|
read the same file after setup finishes. `meta` receives neither state variable;
|
|
120
118
|
state is never copied into `run.json`.
|
|
@@ -125,8 +123,8 @@ children and set their own hook and run variables.
|
|
|
125
123
|
provides shared values; experiment values replace them by name. Variables in
|
|
126
124
|
the environment that starts `labnotes experiments NAME run` win over both,
|
|
127
125
|
including inline assignments. Values can use raw `{run_dir}` and
|
|
128
|
-
`{invocation_dir}` placeholders.
|
|
129
|
-
|
|
126
|
+
`{invocation_dir}` placeholders. Hooks and meta get neither, so values using
|
|
127
|
+
one are left out of their environment; runs still get them.
|
|
130
128
|
`LABNOTES_*` names are reserved for labnotes.
|
|
131
129
|
A run counts when it exited 0 and its `run.json` doesn't hold
|
|
132
130
|
`"excluded": true`, so excluding a run by hand means adding that key; the next
|
|
@@ -192,8 +190,10 @@ going. Elsewhere, it prints a line per event instead.
|
|
|
192
190
|
- `--PARAM=VALUE` runs only the cells where that param has that value, e.g.
|
|
193
191
|
`labnotes experiments NAME run --model=small`. PARAM must be a key in
|
|
194
192
|
`[params]` and VALUE one of its values, written as it shows in `runs`
|
|
195
|
-
(`true`, `2`); anything else is an error.
|
|
196
|
-
|
|
193
|
+
(`true`, `2`); anything else is an error. Repeat a param to run any of
|
|
194
|
+
several values (`--model=small --model=large`); give several params to
|
|
195
|
+
narrow further (`--model=small --lang=en`). Values are never split on
|
|
196
|
+
commas. It changes only what
|
|
197
197
|
this `run` starts: counts, progress and `repeats` still cover the full
|
|
198
198
|
matrix, so a later plain `run` fills in the rest. Use it instead of editing
|
|
199
199
|
`experiment.toml` to run a slice.
|
|
@@ -33,7 +33,8 @@ class PassthroughCommand(click.Command):
|
|
|
33
33
|
cls=PassthroughCommand,
|
|
34
34
|
help="List experiments, show one, list its runs, or run it."
|
|
35
35
|
" `new [NAME]` creates one. With run, --PARAM=VALUE runs only the"
|
|
36
|
-
" matrix cells where that param has that value
|
|
36
|
+
" matrix cells where that param has that value (repeat it for several"
|
|
37
|
+
" values), and anything after --"
|
|
37
38
|
" is appended to every run's command and recorded in run.json, so never"
|
|
38
39
|
" pass secrets there.",
|
|
39
40
|
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
def parse_subset(args: list[str]) -> dict[str, str]:
|
|
2
|
-
only: dict[str, str] = {}
|
|
1
|
+
def parse_subset(args: list[str]) -> dict[str, list[str]]:
|
|
2
|
+
only: dict[str, list[str]] = {}
|
|
3
3
|
for arg in args:
|
|
4
4
|
param, equals, value = arg.removeprefix("--").partition("=")
|
|
5
5
|
if not arg.startswith("--") or not equals or not param:
|
|
6
6
|
raise ValueError(f"Unexpected {arg}. Pick params with --PARAM=VALUE.")
|
|
7
|
-
|
|
8
|
-
raise ValueError(f"--{param} given twice. Pass one value per param.")
|
|
9
|
-
only[param] = value
|
|
7
|
+
only.setdefault(param, []).append(value)
|
|
10
8
|
return only
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from labnotes.runner.placeholders import PLACEHOLDERS
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def check_hook_placeholders(hooks: dict[str, str | None]) -> None:
|
|
5
|
+
for hook, command in hooks.items():
|
|
6
|
+
for name in PLACEHOLDERS:
|
|
7
|
+
if command is not None and f"{{{name}}}" in command:
|
|
8
|
+
raise ValueError(
|
|
9
|
+
f"{hook} command {command} uses {{{name}}}; setup, teardown, "
|
|
10
|
+
"and meta get no folder placeholders. "
|
|
11
|
+
"Share values with set_state() and get_state()."
|
|
12
|
+
)
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from labnotes.format_value import format_value
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
def check_subset(params: dict[str, list[object]], only: dict[str, str]) -> None:
|
|
5
|
-
for param,
|
|
4
|
+
def check_subset(params: dict[str, list[object]], only: dict[str, list[str]]) -> None:
|
|
5
|
+
for param, wanted in only.items():
|
|
6
6
|
if param not in params:
|
|
7
7
|
declared = ", ".join(params) or "none"
|
|
8
8
|
raise ValueError(f"No param {param}. Params: {declared}.")
|
|
9
9
|
values = [format_value(option) for option in params[param]]
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
for value in wanted:
|
|
11
|
+
if value not in values:
|
|
12
|
+
raise ValueError(
|
|
13
|
+
f"No value {value} for {param}. Values: {', '.join(values)}."
|
|
14
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
|
|
3
|
+
from labnotes.runner.fill_dirs import fill_dirs
|
|
4
|
+
from labnotes.runner.placeholders import PLACEHOLDERS
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def fill_experiment_env(
|
|
8
|
+
configured: Mapping[str, str],
|
|
9
|
+
inherited: Mapping[str, str],
|
|
10
|
+
dirs: Mapping[str, str],
|
|
11
|
+
) -> dict[str, str]:
|
|
12
|
+
caller = {
|
|
13
|
+
key: value
|
|
14
|
+
for key, value in inherited.items()
|
|
15
|
+
if not key.startswith("LABNOTES_")
|
|
16
|
+
}
|
|
17
|
+
filled = {
|
|
18
|
+
key: fill_dirs(value, dirs, quote=False)
|
|
19
|
+
for key, value in configured.items()
|
|
20
|
+
if key not in caller
|
|
21
|
+
and all(name in dirs for name in PLACEHOLDERS if f"{{{name}}}" in value)
|
|
22
|
+
}
|
|
23
|
+
return {**filled, **caller}
|
|
@@ -13,7 +13,7 @@ async def prepare_experiment(
|
|
|
13
13
|
name: str,
|
|
14
14
|
experiment_config: Path | None,
|
|
15
15
|
concurrency: int | None,
|
|
16
|
-
only: dict[str, str] | None = None,
|
|
16
|
+
only: dict[str, list[str]] | None = None,
|
|
17
17
|
args: list[str] | None = None,
|
|
18
18
|
setup: str | None = None,
|
|
19
19
|
teardown: str | None = None,
|
|
@@ -16,10 +16,10 @@ from labnotes.models import (
|
|
|
16
16
|
Report,
|
|
17
17
|
)
|
|
18
18
|
from labnotes.retries import RETRY_EXIT_CODE, RETRY_SECONDS
|
|
19
|
+
from labnotes.runner.check_hook_placeholders import check_hook_placeholders
|
|
19
20
|
from labnotes.runner.execute_run import execute_run
|
|
20
21
|
from labnotes.runner.fill_experiment_env import fill_experiment_env
|
|
21
22
|
from labnotes.runner.fill_dirs import fill_dirs
|
|
22
|
-
from labnotes.runner.hook_dirs import hook_dirs
|
|
23
23
|
from labnotes.runner.in_subset import in_subset
|
|
24
24
|
from labnotes.runner.invocation_hook import invocation_hook
|
|
25
25
|
from labnotes.runner.invocation_meta import invocation_meta
|
|
@@ -47,7 +47,7 @@ async def run_experiment(
|
|
|
47
47
|
listen: Listen,
|
|
48
48
|
timeout: float | None = None,
|
|
49
49
|
retry_seconds: float = RETRY_SECONDS,
|
|
50
|
-
only: dict[str, str] | None = None,
|
|
50
|
+
only: dict[str, list[str]] | None = None,
|
|
51
51
|
args: list[str] | None = None,
|
|
52
52
|
environment: dict[str, str] | None = None,
|
|
53
53
|
snapshot: ProjectSnapshot | None = None,
|
|
@@ -101,21 +101,21 @@ async def run_experiment(
|
|
|
101
101
|
"teardown": experiment.teardown,
|
|
102
102
|
"meta": experiment.meta,
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
check_hook_placeholders(hooks)
|
|
105
105
|
hook_env = {
|
|
106
|
-
hook: fill_experiment_env(
|
|
107
|
-
experiment.env, inherited, dirs, hook=hook, runs=len(plan)
|
|
108
|
-
)
|
|
106
|
+
hook: fill_experiment_env(experiment.env, inherited, {})
|
|
109
107
|
for hook, command in hooks.items()
|
|
110
108
|
if command is not None
|
|
111
109
|
}
|
|
112
110
|
meta = None
|
|
113
111
|
if experiment.meta is not None:
|
|
114
|
-
meta = await invocation_meta(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
meta = await invocation_meta(command_root, experiment.meta, hook_env["meta"])
|
|
113
|
+
invocation_dir = group_dir
|
|
114
|
+
match run_dirs:
|
|
115
|
+
case [run_dir]:
|
|
116
|
+
invocation_dir = run_dir
|
|
117
|
+
if invocation_dir is not None:
|
|
118
|
+
Path(invocation_dir).mkdir(parents=True, exist_ok=True)
|
|
119
119
|
runs = [{"run": run, "params": params} for run, params in plan]
|
|
120
120
|
report(
|
|
121
121
|
{
|
|
@@ -248,7 +248,7 @@ async def run_experiment(
|
|
|
248
248
|
if snapshot is not None and snapshot.sha is not None:
|
|
249
249
|
(folder / "git-sha.txt").write_text(snapshot.sha + "\n")
|
|
250
250
|
(folder / "git-diff.patch").write_bytes(snapshot.diff or b"")
|
|
251
|
-
run_invocation_dir =
|
|
251
|
+
run_invocation_dir = invocation_dir or str(folder.resolve())
|
|
252
252
|
report({"event": "started", "run": run, "params": params, "folder": folder})
|
|
253
253
|
running[run] = set()
|
|
254
254
|
trees[run] = set()
|
|
@@ -303,14 +303,14 @@ async def run_experiment(
|
|
|
303
303
|
await invocation_hook(
|
|
304
304
|
command_root,
|
|
305
305
|
"teardown",
|
|
306
|
-
|
|
306
|
+
experiment.teardown,
|
|
307
307
|
hook_env["teardown"],
|
|
308
308
|
)
|
|
309
309
|
|
|
310
310
|
listen(Controls(interrupt, set_concurrency, kill, finish))
|
|
311
311
|
with (
|
|
312
|
-
nullcontext(
|
|
313
|
-
if
|
|
312
|
+
nullcontext(invocation_dir)
|
|
313
|
+
if invocation_dir is not None
|
|
314
314
|
else TemporaryDirectory(prefix="labnotes-state-")
|
|
315
315
|
) as state_dir:
|
|
316
316
|
state_file = Path(state_dir) / "state.json"
|
|
@@ -324,7 +324,7 @@ async def run_experiment(
|
|
|
324
324
|
await invocation_hook(
|
|
325
325
|
command_root,
|
|
326
326
|
"setup",
|
|
327
|
-
|
|
327
|
+
experiment.setup,
|
|
328
328
|
hook_env["setup"],
|
|
329
329
|
)
|
|
330
330
|
fill()
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
from collections.abc import Mapping
|
|
2
|
-
|
|
3
|
-
from labnotes.runner.fill_dirs import fill_dirs
|
|
4
|
-
from labnotes.runner.placeholders import HOOK_PLACEHOLDERS, PLACEHOLDERS
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def fill_experiment_env(
|
|
8
|
-
configured: Mapping[str, str],
|
|
9
|
-
inherited: Mapping[str, str],
|
|
10
|
-
dirs: Mapping[str, str],
|
|
11
|
-
*,
|
|
12
|
-
hook: str | None = None,
|
|
13
|
-
runs: int = 1,
|
|
14
|
-
) -> dict[str, str]:
|
|
15
|
-
caller = {
|
|
16
|
-
key: value
|
|
17
|
-
for key, value in inherited.items()
|
|
18
|
-
if not key.startswith("LABNOTES_")
|
|
19
|
-
}
|
|
20
|
-
filled: dict[str, str] = {}
|
|
21
|
-
for key, value in configured.items():
|
|
22
|
-
if key in caller:
|
|
23
|
-
continue
|
|
24
|
-
used = [name for name in PLACEHOLDERS if f"{{{name}}}" in value]
|
|
25
|
-
if hook is not None and any(name not in HOOK_PLACEHOLDERS for name in used):
|
|
26
|
-
continue
|
|
27
|
-
for name in used:
|
|
28
|
-
if name not in dirs:
|
|
29
|
-
raise ValueError(
|
|
30
|
-
f"{hook} env.{key} uses {{{name}}}, but this invocation plans "
|
|
31
|
-
f"{runs} runs. {{{name}}} needs exactly one run in this mode."
|
|
32
|
-
)
|
|
33
|
-
filled[key] = fill_dirs(value, dirs, quote=False)
|
|
34
|
-
return {**filled, **caller}
|
|
@@ -1,21 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|