labnotes 0.0.117__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.
- {labnotes-0.0.117 → labnotes-0.0.119}/PKG-INFO +3 -1
- {labnotes-0.0.117 → labnotes-0.0.119}/README.md +2 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/context.md +9 -1
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/daemon_app.py +2 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/remote_start.py +2 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/experiments.py +13 -2
- labnotes-0.0.119/src/labnotes/grid_cell.py +21 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/load_experiment.py +15 -0
- labnotes-0.0.119/src/labnotes/parse_subset.py +10 -0
- labnotes-0.0.119/src/labnotes/pivot_runs.py +43 -0
- labnotes-0.0.119/src/labnotes/runner/check_subset.py +13 -0
- labnotes-0.0.119/src/labnotes/runner/in_subset.py +5 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/prepare_experiment.py +4 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/run_experiment.py +6 -1
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/labnotes.css +22 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/templates/experiment.html +40 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/testing-conventions.toml +5 -5
- {labnotes-0.0.117 → labnotes-0.0.119}/.gitignore +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/CHANGELOG.md +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/MIGRATIONS.md +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/pyproject.toml +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/__main__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/compose_experiment.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/count_groups.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/create_note.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/control_run.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/daemon_client.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/daemon_running.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/daemon_server.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/describe_status.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/ensure_daemon.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/exit_when_idle.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/finalize_lost_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/last_stderr.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/run_daemon.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/run_logs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/serve_daemon.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/socket_path.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/stop_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/watch_daemon.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon/watch_status.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/daemon_command.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/file_changes.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/format_duration.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/format_started.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/group_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/init.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/invocation_started.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/is_non_negative_int.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/is_non_negative_number.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/is_positive_int.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/load_run.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/log.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/log_path.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/memory_interval.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/models.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/modes.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/nests_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/note_path.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/retries.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/run_command.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/run_control.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/run_output.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/run_status.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/exit_signal.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/hold_folder.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/invocation_meta.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/new_param_run_id.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/param_run_name.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/record_memory.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/signal_tree.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/wait_for_tree.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/runs_view_command.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/save_conflict_copy.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/save_note.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/server.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/shared_params.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/elapsed.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/experiment.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/local-time.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/new-note.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/note-edit.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/note-editor.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/run-output.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/experiment_run_ids.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/experiment_toml.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/experiments_ddl.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/file_text.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/note_text.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_blocks.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_log.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_memory.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/read_run_file.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/runs_columns.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/templates/editor_imports.html +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/templates/note.html +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/templates/run.html +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/browse_app.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/browse_tui.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/check_view_response.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/config.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/experiment_screen.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/experiments_screen.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/fill_table.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/format_cell.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/group_cells.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/invocation_columns.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/invocation_rows.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/leave_prompt.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/log_block.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/log_blocks.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/native_rows.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/reload_on_change.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/run_cells.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/run_output.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/run_screen.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/runs_view.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/stopped_title.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/view_column.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/tui/view_process.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/utils/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/utils/format_bytes.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/utils/process_alive.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/utils/run_usage.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/utils/tree_rss.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/utils/tree_usage.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/view/__init__.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/view/answer.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/view/build.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/view/respond.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/view/serve.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/wait_for_note.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/src/labnotes/watch_rows.py +0 -0
- {labnotes-0.0.117 → labnotes-0.0.119}/tests/integration/conftest.py +0 -0
- {labnotes-0.0.117 → 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.
|
|
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"`
|
|
@@ -180,4 +188,4 @@ going. Elsewhere, it prints a line per event instead.
|
|
|
180
188
|
was retried counts as retried, not failed. If it can't
|
|
181
189
|
start or reach the daemon, it prints the cause on one line and exits 1.
|
|
182
190
|
|
|
183
|
-
`uvx labnotes server` serves the experiments, their markdown files and their runs as a local site, read from the same `.labnotes.toml`. An experiment's page shows its `experiment.toml` on one line, then a Runs tab with a table of its runs and a Notebooks tab with one tab per markdown file. Clicking a run opens its `stdout.log` and `stderr.log` together, followed as they're written until the run ends.
|
|
191
|
+
`uvx labnotes server` serves the experiments, their markdown files and their runs as a local site, read from the same `.labnotes.toml`. An experiment's page shows its `experiment.toml` on one line, then a Runs tab with a table of its runs and a Notebooks tab with one tab per markdown file. For a matrix experiment, the Runs tab also has a grid (`?view=grid`): one cell per combination of the params that vary, with how many runs count toward `repeats`. Clicking a run opens its `stdout.log` and `stderr.log` together, followed as they're written until the run ends.
|
|
@@ -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
|
-
|
|
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,21 @@
|
|
|
1
|
+
from typing import TypedDict
|
|
2
|
+
from urllib.parse import urlencode
|
|
3
|
+
|
|
4
|
+
from labnotes.format_value import format_value
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Cell(TypedDict):
|
|
8
|
+
values: dict[str, object]
|
|
9
|
+
runs: object
|
|
10
|
+
completed: object
|
|
11
|
+
href: str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def grid_cell(values: dict[str, object], counts: dict[str, object]) -> Cell:
|
|
15
|
+
filters = [(f"f.{key}", format_value(value)) for key, value in values.items()]
|
|
16
|
+
return {
|
|
17
|
+
"values": values,
|
|
18
|
+
"runs": counts.get("runs", 0),
|
|
19
|
+
"completed": counts.get("completed", 0),
|
|
20
|
+
"href": f"?{urlencode(filters)}#runs",
|
|
21
|
+
}
|
|
@@ -17,6 +17,7 @@ from labnotes.list_runs import list_runs
|
|
|
17
17
|
from labnotes.models import QueryParams
|
|
18
18
|
from labnotes.nests_runs import nests_runs
|
|
19
19
|
from labnotes.parse_run_view import parse_run_view
|
|
20
|
+
from labnotes.pivot_runs import pivot_runs
|
|
20
21
|
from labnotes.python_blocks import python_blocks
|
|
21
22
|
from labnotes.render_markdown import render_markdown
|
|
22
23
|
from labnotes.runs_view_command import runs_view_command
|
|
@@ -65,6 +66,19 @@ async def load_experiment(
|
|
|
65
66
|
if nested
|
|
66
67
|
else None
|
|
67
68
|
)
|
|
69
|
+
matrix = summary["mode"] == "matrix"
|
|
70
|
+
gridded = matrix and params.getlist("view")[-1:] == ["grid"]
|
|
71
|
+
axes = {key: varies[key] for key in choices if len(varies[key]) > 1}
|
|
72
|
+
grid = (
|
|
73
|
+
pivot_runs(
|
|
74
|
+
axes,
|
|
75
|
+
await count_runs(
|
|
76
|
+
tables, source, str(summary["completed_run"]), group_by=list(axes)
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
if gridded
|
|
80
|
+
else None
|
|
81
|
+
)
|
|
68
82
|
return {
|
|
69
83
|
"name": row["name"],
|
|
70
84
|
"display_name": row["display_name"],
|
|
@@ -86,6 +100,7 @@ async def load_experiment(
|
|
|
86
100
|
"runs_list": runs,
|
|
87
101
|
"runs_live": await daemon_running(root),
|
|
88
102
|
"run_groups": groups,
|
|
103
|
+
"run_grid": grid,
|
|
89
104
|
"run_columns": shown,
|
|
90
105
|
"run_view": view,
|
|
91
106
|
"run_choices": choices,
|
|
@@ -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,43 @@
|
|
|
1
|
+
from itertools import product
|
|
2
|
+
from typing import TypedDict
|
|
3
|
+
|
|
4
|
+
from labnotes.grid_cell import Cell, grid_cell
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Row(TypedDict):
|
|
8
|
+
labels: list[object]
|
|
9
|
+
cells: list[Cell]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Grid(TypedDict):
|
|
13
|
+
row_keys: list[str]
|
|
14
|
+
column_key: str | None
|
|
15
|
+
columns: list[object]
|
|
16
|
+
rows: list[Row]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _key(value: object) -> object:
|
|
20
|
+
return int(value) if isinstance(value, bool) else value
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def pivot_runs(axes: dict[str, list[object]], counts: list[dict[str, object]]) -> Grid:
|
|
24
|
+
by_cell = {tuple(_key(row[key]) for key in axes): row for row in counts}
|
|
25
|
+
row_keys = [*axes]
|
|
26
|
+
column_key = row_keys.pop() if row_keys else None
|
|
27
|
+
columns: list[object] = [None] if column_key is None else axes[column_key]
|
|
28
|
+
rows: list[Row] = []
|
|
29
|
+
for labels in product(*(axes[key] for key in row_keys)):
|
|
30
|
+
cells = []
|
|
31
|
+
for column in columns:
|
|
32
|
+
values: dict[str, object] = dict(zip(row_keys, labels))
|
|
33
|
+
if column_key is not None:
|
|
34
|
+
values[column_key] = column
|
|
35
|
+
found = by_cell.get(tuple(_key(values[key]) for key in axes), {})
|
|
36
|
+
cells.append(grid_cell(values, found))
|
|
37
|
+
rows.append({"labels": list(labels), "cells": cells})
|
|
38
|
+
return {
|
|
39
|
+
"row_keys": row_keys,
|
|
40
|
+
"column_key": column_key,
|
|
41
|
+
"columns": columns,
|
|
42
|
+
"rows": rows,
|
|
43
|
+
}
|
|
@@ -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
|
+
)
|
|
@@ -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
|
-
|
|
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:
|
|
@@ -217,6 +217,22 @@ h3 {
|
|
|
217
217
|
.new-note { font: inherit; color: var(--ink-2); background: none; border: 0; padding: 0 0.2rem; cursor: pointer; }
|
|
218
218
|
.new-note:hover { color: var(--ink); }
|
|
219
219
|
|
|
220
|
+
/* Runs grid: counted runs per combination of the params that vary. */
|
|
221
|
+
.runs-grid { border-collapse: separate; border-spacing: 3px; font-size: 0.86rem; }
|
|
222
|
+
.runs-grid th { font-family: var(--mono); font-size: 0.8rem; font-weight: 500; color: var(--ink-2); text-align: left; white-space: nowrap; padding: 0 0.75rem 0.3rem; }
|
|
223
|
+
.runs-grid thead th { vertical-align: bottom; }
|
|
224
|
+
.runs-grid th.label { color: var(--ink-3); }
|
|
225
|
+
.runs-grid th.axis { font-family: var(--sans); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); border-bottom: 1px solid var(--rule); }
|
|
226
|
+
.grid-cell { min-width: 6rem; padding: 0; background: var(--surface); border: 1px solid var(--rule); border-radius: 7px; }
|
|
227
|
+
.grid-cell a { display: block; padding: 0.5rem 0.7rem 0.6rem; color: var(--ink); text-decoration: none; }
|
|
228
|
+
.grid-cell:hover { border-color: var(--rule-strong); }
|
|
229
|
+
.grid-cell .num { display: block; margin-bottom: 0.4rem; }
|
|
230
|
+
.grid-cell .of { color: var(--ink-3); }
|
|
231
|
+
.grid-cell.empty .num { color: var(--ink-3); }
|
|
232
|
+
.grid-cell.done { border-color: color-mix(in srgb, var(--accent) 35%, var(--rule)); }
|
|
233
|
+
.grid-cell .meter { display: block; height: 4px; border-radius: 2px; background: var(--track); overflow: hidden; }
|
|
234
|
+
.grid-cell .meter-fill { display: block; height: 100%; background: var(--accent); }
|
|
235
|
+
|
|
220
236
|
/* Runs table */
|
|
221
237
|
.narrowed { color: var(--ink-2); font-size: 0.88rem; margin: 0 0 0.75rem; }
|
|
222
238
|
.narrowed .clear { margin-left: 0.8rem; color: var(--ink-3); }
|
|
@@ -390,6 +406,12 @@ h3 {
|
|
|
390
406
|
}
|
|
391
407
|
.view-toggle button + button { border-left: 1px solid var(--rule-strong); }
|
|
392
408
|
.view-toggle button[aria-pressed="true"] { background: var(--accent-soft); color: var(--ink); }
|
|
409
|
+
#runs .view-toggle { display: flex; width: fit-content; float: none; margin: 0 0 0.75rem auto; }
|
|
410
|
+
.view-toggle a { display: flex; padding: 0.3rem 0.55rem; background: var(--surface); color: var(--ink-3); }
|
|
411
|
+
.view-toggle a + a { border-left: 1px solid var(--rule-strong); }
|
|
412
|
+
.view-toggle a:hover { color: var(--ink); }
|
|
413
|
+
.view-toggle a[aria-current="page"] { background: var(--accent-soft); color: var(--ink); }
|
|
414
|
+
.view-toggle svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
|
|
393
415
|
|
|
394
416
|
/* Index as cards: the same table, laid out as a grid. */
|
|
395
417
|
.ledger[data-view="cards"] { display: block; background: none; border: 0; border-radius: 0; overflow: visible; }
|
|
@@ -51,6 +51,45 @@
|
|
|
51
51
|
{% set nested = e.run_groups is not none %}
|
|
52
52
|
{% set width = e.run_columns | length + (2 if nested else 1) %}
|
|
53
53
|
{% set narrowed = view.status or view.filters or view.picked %}
|
|
54
|
+
{% set grid = e.run_grid %}
|
|
55
|
+
{% if e.mode == 'matrix' and e.runs %}
|
|
56
|
+
<nav class="view-toggle" aria-label="Runs view">
|
|
57
|
+
<a href="?#runs" title="Table" aria-label="Table"{% if not grid %} aria-current="page"{% endif %}><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2 3.5h12M2 8h12M2 12.5h12"/></svg></a>
|
|
58
|
+
<a href="?view=grid#runs" title="Grid" aria-label="Grid"{% if grid %} aria-current="page"{% endif %}><svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2" y="2" width="5" height="5" rx="1"/><rect x="9" y="2" width="5" height="5" rx="1"/><rect x="2" y="9" width="5" height="5" rx="1"/><rect x="9" y="9" width="5" height="5" rx="1"/></svg></a>
|
|
59
|
+
</nav>
|
|
60
|
+
{% endif %}
|
|
61
|
+
{% if grid %}
|
|
62
|
+
<div class="scroll">
|
|
63
|
+
<table class="runs-grid">
|
|
64
|
+
<thead>
|
|
65
|
+
{% if grid.column_key is not none %}
|
|
66
|
+
<tr class="axis-row">
|
|
67
|
+
{% if grid.row_keys %}<td colspan="{{ grid.row_keys | length }}"></td>{% endif %}
|
|
68
|
+
<th scope="colgroup" colspan="{{ grid.columns | length }}" class="axis">{{ grid.column_key }}</th>
|
|
69
|
+
</tr>
|
|
70
|
+
<tr>
|
|
71
|
+
{% for key in grid.row_keys %}<th scope="col" class="label">{{ key }}</th>{% endfor %}
|
|
72
|
+
{% for column in grid.columns %}<th scope="col">{{ column | value }}</th>{% endfor %}
|
|
73
|
+
</tr>
|
|
74
|
+
{% endif %}
|
|
75
|
+
</thead>
|
|
76
|
+
<tbody>
|
|
77
|
+
{% for row in grid.rows %}
|
|
78
|
+
<tr>
|
|
79
|
+
{% for label in row.labels %}<th scope="row">{{ label | value }}</th>{% endfor %}
|
|
80
|
+
{% for cell in row.cells %}
|
|
81
|
+
{% set goal = e.runs_per_cell or 1 %}
|
|
82
|
+
<td class="grid-cell{{ ' done' if cell.completed >= goal }}{{ ' empty' if not cell.runs }}" title="{% for key, value in cell['values'].items() %}{{ key }} = {{ value | value }}{{ ', ' if not loop.last }}{% endfor %}{{ ': ' if cell['values'] }}{{ cell.completed }} complete of {{ cell.runs }} recorded">
|
|
83
|
+
<a href="{{ cell.href }}"><span class="num">{{ cell.completed }}<span class="of">/{{ goal }}</span></span>
|
|
84
|
+
<span class="meter"><span class="meter-fill" style="width: {{ [cell.completed / goal * 100, 100] | min }}%"></span></span></a>
|
|
85
|
+
</td>
|
|
86
|
+
{% endfor %}
|
|
87
|
+
</tr>
|
|
88
|
+
{% endfor %}
|
|
89
|
+
</tbody>
|
|
90
|
+
</table>
|
|
91
|
+
</div>
|
|
92
|
+
{% else %}
|
|
54
93
|
{% if narrowed %}<p class="narrowed"><span class="num">{{ e.runs_list | length }}</span> of <span class="num">{{ e.runs }}</span> <a class="clear" href="{{ '?sort=' ~ (view.sort | urlencode) ~ ('&order=desc' if view.descending else '') if view.sort else '?' }}#runs">Clear filters</a></p>{% endif %}
|
|
55
94
|
{% if e.runs %}
|
|
56
95
|
<form id="run-filters" method="get" action="#runs">
|
|
@@ -117,6 +156,7 @@
|
|
|
117
156
|
{% else %}
|
|
118
157
|
<p class="empty">No runs recorded yet.</p>
|
|
119
158
|
{% endif %}
|
|
159
|
+
{% endif %}
|
|
120
160
|
</section>
|
|
121
161
|
{% endif %}
|
|
122
162
|
<script src="{{ asset('experiment.js') }}" defer></script>
|
|
@@ -13,7 +13,7 @@ reason = "last_stream is always the same str object taken from STREAMS, so is eq
|
|
|
13
13
|
[[python.exempt]]
|
|
14
14
|
path = "src/labnotes/load_experiment.py"
|
|
15
15
|
rules = ["mutation"]
|
|
16
|
-
lines = [61]
|
|
16
|
+
lines = [61, 69]
|
|
17
17
|
reason = "summarize_config returns mode matrix or adhoc; \"matrix\" <= \"adhoc\" is false like ==, and both are interned literals so is equals =="
|
|
18
18
|
|
|
19
19
|
[[python.exempt]]
|
|
@@ -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 = [
|
|
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 = [
|
|
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 = [
|
|
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 = [
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|