labnotes 0.1.2__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.2 → labnotes-0.2.0}/PKG-INFO +1 -1
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/context.md +7 -9
- labnotes-0.2.0/src/labnotes/runner/check_hook_placeholders.py +12 -0
- labnotes-0.2.0/src/labnotes/runner/fill_experiment_env.py +23 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/placeholders.py +0 -1
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/run_experiment.py +15 -15
- labnotes-0.1.2/src/labnotes/runner/fill_experiment_env.py +0 -34
- labnotes-0.1.2/src/labnotes/runner/hook_dirs.py +0 -21
- {labnotes-0.1.2 → labnotes-0.2.0}/.gitignore +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/CHANGELOG.md +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/MIGRATIONS.md +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/README.md +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/pyproject.toml +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/__init__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/__main__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/cli.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/compose_experiment.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/count_groups.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/create_app.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/create_note.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/data_html.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/experiments.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/file_changes.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/format_duration.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/format_started.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/format_value.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/get_state.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/grid_cell.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/group_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/init.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/invocation_started.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/is_non_negative_int.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/is_non_negative_number.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/is_positive_int.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/load_config.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/load_run.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/log.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/log_path.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/memory_interval.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/models.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/modes.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/nests_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/note_path.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/output_html.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/parse_subset.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/pivot_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/read_config.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/read_path.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/retries.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/run_output.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/cgroup_memory.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/check_args.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/check_subset.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/container_cgroup.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/container_memory.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/docker_output.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/exit_signal.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/fill_dirs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/finalize_lost_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/flag_name.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/in_subset.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/invocation_hook.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/invocation_meta.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/new_param_run_id.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/param_run_name.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/prepare_experiment.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/project_snapshot.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/record_memory.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/run_git.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/signal_tree.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/start_experiment.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/wait_for_tree.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/runs_view_command.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/save_conflict_copy.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/save_note.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/server.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/set_state.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/shared_params.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/state_path.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/elapsed.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/experiment.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/local-time.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/new-note.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/note-edit.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/note-editor.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/run-output.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/experiment_run_ids.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/experiment_toml.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/experiments_ddl.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/file_text.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/note_text.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_blocks.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_log.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_memory.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/read_run_file.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/runs_columns.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/templates/editor_imports.html +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/templates/note.html +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/templates/run.html +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/browse_app.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/browse_tui.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/check_view_response.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/config.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/experiment_screen.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/experiments_screen.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/fill_table.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/format_cell.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/group_cells.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/invocation_columns.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/invocation_rows.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/leave_prompt.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/log_block.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/log_blocks.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/native_rows.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/reload_on_change.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/run_cells.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/run_output.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/run_screen.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/runs_view.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/stopped_title.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/view_column.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/tui/view_process.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/utils/__init__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/utils/format_bytes.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/utils/process_alive.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/utils/run_usage.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/utils/tree_rss.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/utils/tree_usage.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/view/__init__.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/view/answer.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/view/build.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/view/respond.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/view/serve.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/wait_for_note.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/src/labnotes/watch_rows.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/testing-conventions.toml +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/tests/conftest.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/tests/e2e/conftest.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/tests/integration/conftest.py +0 -0
- {labnotes-0.1.2 → labnotes-0.2.0}/uv.lock +0 -0
|
@@ -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
|
|
@@ -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
|
+
)
|
|
@@ -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}
|
|
@@ -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
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|