labnotes 0.0.121__tar.gz → 0.0.123__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.121 → labnotes-0.0.123}/PKG-INFO +1 -1
- {labnotes-0.0.121 → labnotes-0.0.123}/pyproject.toml +1 -1
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/context.md +5 -10
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/models.py +0 -4
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/run_control.py +1 -3
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/describe_event.py +0 -10
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/run_experiment.py +1 -51
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/run_app.py +9 -140
- {labnotes-0.0.121 → labnotes-0.0.123}/testing-conventions.toml +6 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/uv.lock +4 -4
- {labnotes-0.0.121 → labnotes-0.0.123}/.gitignore +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/CHANGELOG.md +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/MIGRATIONS.md +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/README.md +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/__main__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/compose_experiment.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/count_groups.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/create_note.py +0 -0
- {labnotes-0.0.121/src/labnotes/utils → labnotes-0.0.123/src/labnotes/daemon}/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/control_run.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/daemon_app.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/daemon_client.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/daemon_running.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/daemon_server.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/describe_status.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/ensure_daemon.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/exit_when_idle.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/finalize_lost_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/last_stderr.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/remote_start.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/run_daemon.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/run_logs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/serve_daemon.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/socket_path.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/stop_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/watch_daemon.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon/watch_status.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/daemon_command.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/experiments.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/file_changes.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/format_duration.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/format_started.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/grid_cell.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/group_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/init.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/invocation_started.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/is_non_negative_int.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/is_non_negative_number.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/is_positive_int.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/load_run.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/log.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/log_path.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/memory_interval.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/modes.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/nests_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/note_path.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/parse_subset.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/pivot_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/retries.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/run_command.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/run_output.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/run_status.py +0 -0
- {labnotes-0.0.121/src/labnotes/tui → labnotes-0.0.123/src/labnotes/runner}/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/check_subset.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/exit_signal.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/hold_folder.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/in_subset.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/invocation_meta.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/new_param_run_id.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/param_run_name.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/prepare_experiment.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/record_memory.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/signal_tree.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/wait_for_tree.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/runs_view_command.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/save_conflict_copy.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/save_note.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/server.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/shared_params.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/elapsed.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/experiment.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/local-time.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/new-note.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/note-edit.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/note-editor.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/run-output.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/experiment_run_ids.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/experiment_toml.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/experiments_ddl.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/file_text.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/note_text.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_blocks.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_log.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_memory.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/read_run_file.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/runs_columns.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/templates/editor_imports.html +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/templates/note.html +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/templates/run.html +0 -0
- {labnotes-0.0.121/src/labnotes/runner → labnotes-0.0.123/src/labnotes/tui}/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/browse_app.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/browse_tui.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/check_view_response.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/config.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/experiment_screen.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/experiments_screen.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/fill_table.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/format_cell.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/group_cells.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/invocation_columns.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/invocation_rows.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/leave_prompt.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/log_block.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/log_blocks.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/native_rows.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/reload_on_change.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/run_cells.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/run_output.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/run_screen.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/runs_view.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/stopped_title.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/view_column.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/tui/view_process.py +0 -0
- {labnotes-0.0.121/src/labnotes/daemon → labnotes-0.0.123/src/labnotes/utils}/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/utils/format_bytes.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/utils/process_alive.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/utils/run_usage.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/utils/tree_rss.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/utils/tree_usage.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/view/__init__.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/view/answer.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/view/build.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/view/respond.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/view/serve.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/wait_for_note.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/src/labnotes/watch_rows.py +0 -0
- {labnotes-0.0.121 → labnotes-0.0.123}/tests/integration/conftest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: labnotes
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.123
|
|
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>
|
|
@@ -132,14 +132,10 @@ sets the seconds between samples; 0 turns it off.
|
|
|
132
132
|
|
|
133
133
|
In a terminal, `run` shows a live table of runs (status, time, memory and
|
|
134
134
|
folder size) and stays
|
|
135
|
-
open when they finish. Failed runs show their status in red
|
|
136
|
-
runs it again under a new id, with `retry_of` set. `j` and `k` move the cursor, `g` and `G` jump to the
|
|
135
|
+
open when they finish. Failed runs show their status in red. `j` and `k` move the cursor, `g` and `G` jump to the
|
|
137
136
|
first and last row. Runs not started yet show grayed as `pending`, and as
|
|
138
|
-
`skipped` once stopped.
|
|
139
|
-
|
|
140
|
-
drops it, Escape puts it back. Space deselects a pending run so it won't run; Space again puts it back at
|
|
141
|
-
the end of the queue. `/` filters rows by params text; Enter keeps the filter,
|
|
142
|
-
Escape clears it. `D` deselects every pending run the filter shows. `x` stops the
|
|
137
|
+
`skipped` once stopped. `/` filters rows by params text; Enter keeps the filter,
|
|
138
|
+
Escape clears it. `x` stops the
|
|
143
139
|
running run under the cursor; `x` again kills it. `+` and
|
|
144
140
|
`-` change how many run at once; lowering it lets running runs
|
|
145
141
|
finish. Enter on a run follows its `stdout.log` and `stderr.log` together, as
|
|
@@ -180,9 +176,8 @@ going. Elsewhere, it prints a line per event instead.
|
|
|
180
176
|
waits for a daemon when none is up. `--json` prints one JSON object per line.
|
|
181
177
|
Following doesn't keep the daemon up.
|
|
182
178
|
- `labnotes run control NAME ACTION [ARG]` sends one live-view control to a
|
|
183
|
-
running experiment: `kill
|
|
184
|
-
|
|
185
|
-
`set_concurrency` to a number, `interrupt` or `finish`.
|
|
179
|
+
running experiment: `kill` a run, `set_concurrency` to a number,
|
|
180
|
+
`interrupt` or `finish`.
|
|
186
181
|
- A second `run` of the same experiment fails while the first is going.
|
|
187
182
|
- It exits 0 even if runs fail; the summary line counts failures. A run that
|
|
188
183
|
was retried counts as retried, not failed. If it can't
|
|
@@ -14,13 +14,9 @@ Report = Callable[[dict[str, object]], None]
|
|
|
14
14
|
@dataclass(frozen=True)
|
|
15
15
|
class Controls:
|
|
16
16
|
interrupt: Callable[[], None]
|
|
17
|
-
run_next: Callable[[str], None]
|
|
18
17
|
set_concurrency: Callable[[int], None]
|
|
19
|
-
toggle: Callable[[str], None]
|
|
20
18
|
kill: Callable[[str], None]
|
|
21
|
-
retry: Callable[[str], None]
|
|
22
19
|
finish: Callable[[], None]
|
|
23
|
-
move: Callable[[str, int], None]
|
|
24
20
|
|
|
25
21
|
|
|
26
22
|
Listen = Callable[[Controls], None]
|
|
@@ -18,9 +18,7 @@ PARAMS = {
|
|
|
18
18
|
name="control",
|
|
19
19
|
help=(
|
|
20
20
|
"Send one control to an experiment's runs, as the live view's keys do. "
|
|
21
|
-
"kill
|
|
22
|
-
"in the queue, from 0; set_concurrency a number; "
|
|
23
|
-
"interrupt and finish nothing."
|
|
21
|
+
"kill takes a run; set_concurrency a number; interrupt and finish nothing."
|
|
24
22
|
),
|
|
25
23
|
)
|
|
26
24
|
@click.argument("name")
|
|
@@ -14,16 +14,6 @@ def describe_event(event: dict[str, object]) -> str:
|
|
|
14
14
|
case "ended":
|
|
15
15
|
outcome = event["error"] or f"exited {event['exit_code']}"
|
|
16
16
|
return f"{event['run']} {outcome}"
|
|
17
|
-
case "queued":
|
|
18
|
-
return f"{event['run']} runs next."
|
|
19
|
-
case "moved":
|
|
20
|
-
pending: list[str] = event["pending"] # type: ignore[assignment]
|
|
21
|
-
place = pending.index(str(event["run"])) + 1
|
|
22
|
-
return f"{event['run']} moved to {place} of {len(pending)} in the queue."
|
|
23
|
-
case "deselected":
|
|
24
|
-
return f"{event['run']} deselected."
|
|
25
|
-
case "reselected":
|
|
26
|
-
return f"{event['run']} back in the queue."
|
|
27
17
|
case "stopping run":
|
|
28
18
|
return f"Stopping {event['run']}."
|
|
29
19
|
case "killing run":
|
|
@@ -128,43 +128,6 @@ async def run_experiment(
|
|
|
128
128
|
report({"event": "stopping run", "run": run})
|
|
129
129
|
signal_run(run, signal.SIGTERM)
|
|
130
130
|
|
|
131
|
-
held: list[Entry] = []
|
|
132
|
-
|
|
133
|
-
def find(entries: list[Entry], run: str) -> Entry | None:
|
|
134
|
-
return next((entry for entry in entries if entry[0] == run), None)
|
|
135
|
-
|
|
136
|
-
def arrange(event: str, run: str) -> None:
|
|
137
|
-
pending = [id_ for id_, _ in plan]
|
|
138
|
-
deselected = [id_ for id_, _ in held]
|
|
139
|
-
report({"event": event, "run": run, "pending": pending, "held": deselected})
|
|
140
|
-
|
|
141
|
-
def run_next(run: str) -> None:
|
|
142
|
-
entry = find(plan, run)
|
|
143
|
-
if entry is not None:
|
|
144
|
-
plan.remove(entry)
|
|
145
|
-
plan.insert(0, entry)
|
|
146
|
-
arrange("queued", run)
|
|
147
|
-
|
|
148
|
-
def move(run: str, place: int) -> None:
|
|
149
|
-
entry = find(plan, run)
|
|
150
|
-
if entry is not None:
|
|
151
|
-
plan.remove(entry)
|
|
152
|
-
plan.insert(max(0, place), entry)
|
|
153
|
-
arrange("moved", run)
|
|
154
|
-
|
|
155
|
-
def toggle(run: str) -> None:
|
|
156
|
-
if stopping.is_set():
|
|
157
|
-
return
|
|
158
|
-
if (entry := find(plan, run)) is not None:
|
|
159
|
-
plan.remove(entry)
|
|
160
|
-
held.append(entry)
|
|
161
|
-
arrange("deselected", run)
|
|
162
|
-
elif (entry := find(held, run)) is not None:
|
|
163
|
-
held.remove(entry)
|
|
164
|
-
plan.append(entry)
|
|
165
|
-
arrange("reselected", run)
|
|
166
|
-
fill()
|
|
167
|
-
|
|
168
131
|
ended: dict[str, dict[str, object]] = {}
|
|
169
132
|
parents: dict[str, str] = {}
|
|
170
133
|
attempts: dict[str, int] = {}
|
|
@@ -179,15 +142,6 @@ async def run_experiment(
|
|
|
179
142
|
report({"event": "retried", "run": run, "retry": again, "params": ended[run]})
|
|
180
143
|
fill()
|
|
181
144
|
|
|
182
|
-
def retry(run: str) -> None:
|
|
183
|
-
if stopping.is_set() or run not in ended:
|
|
184
|
-
return
|
|
185
|
-
if run in waiting:
|
|
186
|
-
waiting.pop(run).cancel()
|
|
187
|
-
requeue(run, attempts.get(run, 0) + 1)
|
|
188
|
-
else:
|
|
189
|
-
requeue(run, 0)
|
|
190
|
-
|
|
191
145
|
def retry_later(run: str) -> None:
|
|
192
146
|
tried = attempts.get(run, 0)
|
|
193
147
|
if tried >= experiment.retries:
|
|
@@ -277,11 +231,7 @@ async def run_experiment(
|
|
|
277
231
|
):
|
|
278
232
|
retry_later(run)
|
|
279
233
|
|
|
280
|
-
listen(
|
|
281
|
-
Controls(
|
|
282
|
-
interrupt, run_next, set_concurrency, toggle, kill, retry, finish, move
|
|
283
|
-
)
|
|
284
|
-
)
|
|
234
|
+
listen(Controls(interrupt, set_concurrency, kill, finish))
|
|
285
235
|
fill()
|
|
286
236
|
await done.wait()
|
|
287
237
|
await asyncio.gather(*started)
|
|
@@ -26,27 +26,15 @@ from labnotes.tui.runs_table import RunsTable
|
|
|
26
26
|
|
|
27
27
|
PENDING, PASSED, FAILED = "○", "✓", "✗"
|
|
28
28
|
SPINNER = "|/-\\"
|
|
29
|
-
SKIPPED
|
|
29
|
+
SKIPPED = "–"
|
|
30
30
|
VIEWING_ACTIONS = {"leave", "quit", "interrupt", "command_palette"}
|
|
31
|
-
GRABBED_ACTIONS = {"shift", "drop", "put_back"}
|
|
32
|
-
GRABBING_ACTIONS = {*GRABBED_ACTIONS, "grab", "quit", "interrupt", "command_palette"}
|
|
33
31
|
|
|
34
32
|
|
|
35
33
|
class RunApp(App[None]):
|
|
36
34
|
CSS = "#concurrency { dock: right; width: auto; padding: 0 1; }"
|
|
37
35
|
BINDINGS = [
|
|
38
36
|
Binding("ctrl+c", "interrupt", "Quit"),
|
|
39
|
-
Binding("n", "run_next", "Run next"),
|
|
40
|
-
Binding("m", "grab", "Move"),
|
|
41
|
-
Binding("j,down", "shift(1)", priority=True),
|
|
42
|
-
Binding("k,up", "shift(-1)", priority=True),
|
|
43
|
-
Binding("enter", "drop", "Drop", priority=True),
|
|
44
|
-
Binding("escape", "put_back", "Put back"),
|
|
45
|
-
Binding("space", "toggle_run", "Deselect"),
|
|
46
|
-
Binding("D", "deselect_shown", "Deselect shown"),
|
|
47
37
|
Binding("x", "kill_run", "Stop run"),
|
|
48
|
-
Binding("f", "hide_failed", "Hide failed"),
|
|
49
|
-
Binding("r", "retry", "Retry"),
|
|
50
38
|
Binding("slash", "filter", "Filter", key_display="/"),
|
|
51
39
|
Binding("escape", "leave", "Back"),
|
|
52
40
|
Binding("plus,equals_sign", "concurrency(1)", "More at once", key_display="+"),
|
|
@@ -61,18 +49,10 @@ class RunApp(App[None]):
|
|
|
61
49
|
self.results: list[dict[str, object]] = []
|
|
62
50
|
self.error: Exception | None = None
|
|
63
51
|
self.controls = Controls(
|
|
64
|
-
lambda: None,
|
|
65
|
-
lambda run: None,
|
|
66
|
-
lambda count: None,
|
|
67
|
-
lambda run: None,
|
|
68
|
-
lambda run: None,
|
|
69
|
-
lambda run: None,
|
|
70
|
-
lambda: None,
|
|
71
|
-
lambda run, place: None,
|
|
52
|
+
lambda: None, lambda count: None, lambda run: None, lambda: None
|
|
72
53
|
)
|
|
73
54
|
self.concurrency = 1
|
|
74
55
|
self.idle = False
|
|
75
|
-
self.next_run: str | None = None
|
|
76
56
|
self.ended: set[str] = set()
|
|
77
57
|
self.frame = 0
|
|
78
58
|
self.started: dict[str, float] = {}
|
|
@@ -82,11 +62,8 @@ class RunApp(App[None]):
|
|
|
82
62
|
self.failed: set[str] = set()
|
|
83
63
|
self.retried: set[str] = set()
|
|
84
64
|
self.waiting: dict[str, float] = {}
|
|
85
|
-
self.hiding = False
|
|
86
65
|
self.folders: dict[str, Path] = {}
|
|
87
66
|
self.viewing: str | None = None
|
|
88
|
-
self.grabbed: str | None = None
|
|
89
|
-
self.grabbed_from: list[str] = []
|
|
90
67
|
self.sampling = False
|
|
91
68
|
self.unmeasured: dict[str, None] = {}
|
|
92
69
|
|
|
@@ -143,14 +120,10 @@ class RunApp(App[None]):
|
|
|
143
120
|
case "adhoc", [only]:
|
|
144
121
|
self.view(only["run"]) # type: ignore[index]
|
|
145
122
|
case "started":
|
|
146
|
-
if run == self.grabbed:
|
|
147
|
-
self.action_put_back()
|
|
148
123
|
self.idle = False
|
|
149
124
|
self.pending.discard(run)
|
|
150
125
|
self.started[run] = time.monotonic()
|
|
151
126
|
self.folders[run] = Path(str(event["folder"]))
|
|
152
|
-
if run == self.next_run:
|
|
153
|
-
self.show("")
|
|
154
127
|
args = " ".join(param_args(event["params"])) # type: ignore[arg-type]
|
|
155
128
|
shown = {
|
|
156
129
|
"run": run.rpartition("/")[2],
|
|
@@ -175,21 +148,6 @@ class RunApp(App[None]):
|
|
|
175
148
|
self.redraw(table.cursor_row)
|
|
176
149
|
self.unmeasured[run] = None
|
|
177
150
|
self.measure()
|
|
178
|
-
case "queued":
|
|
179
|
-
self.reposition(event, run)
|
|
180
|
-
self.next_run = run
|
|
181
|
-
case "moved":
|
|
182
|
-
self.reposition(event, run)
|
|
183
|
-
case "deselected":
|
|
184
|
-
self.pending.discard(run)
|
|
185
|
-
self.set_cell(run, "status", dim(DESELECTED))
|
|
186
|
-
self.reorder(event, table.cursor_row)
|
|
187
|
-
self.show(describe_event(event))
|
|
188
|
-
case "reselected":
|
|
189
|
-
self.pending.add(run)
|
|
190
|
-
self.set_cell(run, "status", dim(PENDING))
|
|
191
|
-
self.reorder(event, table.cursor_row)
|
|
192
|
-
self.show(describe_event(event))
|
|
193
151
|
case "retrying":
|
|
194
152
|
self.waiting[run] = time.monotonic() + float(event["seconds"]) # type: ignore[arg-type]
|
|
195
153
|
self.tick()
|
|
@@ -233,25 +191,11 @@ class RunApp(App[None]):
|
|
|
233
191
|
again = f" {retried} retried." if retried else ""
|
|
234
192
|
self.show(f"{passed} passed, {failed} failed.{again} Ctrl-C to quit.")
|
|
235
193
|
|
|
236
|
-
def reposition(self, event: dict[str, object], run: str) -> None:
|
|
237
|
-
table = self.query_one(DataTable)
|
|
238
|
-
self.reorder(event, table.cursor_row)
|
|
239
|
-
table.move_cursor(row=table.get_row_index(run))
|
|
240
|
-
self.show(describe_event(event))
|
|
241
|
-
|
|
242
|
-
def reorder(self, event: dict[str, object], row: int) -> None:
|
|
243
|
-
self.release()
|
|
244
|
-
waiting: list[str] = [*event["pending"], *event["held"]] # type: ignore[misc]
|
|
245
|
-
for run in waiting:
|
|
246
|
-
self.cells[run] = self.cells.pop(run)
|
|
247
|
-
self.redraw(row)
|
|
248
|
-
|
|
249
194
|
def redraw(self, row: int) -> None:
|
|
250
195
|
table = self.query_one(DataTable)
|
|
251
196
|
table.clear()
|
|
252
197
|
for run, cells in self.cells.items():
|
|
253
|
-
|
|
254
|
-
if self.filter in str(cells.get("params", "")) and not hidden:
|
|
198
|
+
if self.filter in str(cells.get("params", "")):
|
|
255
199
|
table.add_row(
|
|
256
200
|
*(cells.get(c, "") for c in self.columns),
|
|
257
201
|
key=run,
|
|
@@ -274,10 +218,8 @@ class RunApp(App[None]):
|
|
|
274
218
|
def check_action(self, action: str, parameters: tuple[object, ...]) -> bool:
|
|
275
219
|
if isinstance(self.screen, LeavePrompt):
|
|
276
220
|
return False
|
|
277
|
-
if self.
|
|
278
|
-
return
|
|
279
|
-
if action in GRABBED_ACTIONS:
|
|
280
|
-
return False
|
|
221
|
+
if action == "leave" and self.viewing is None:
|
|
222
|
+
return self.query_one(Input).display
|
|
281
223
|
return self.viewing is None or action in VIEWING_ACTIONS
|
|
282
224
|
|
|
283
225
|
def show_concurrency(self, event: dict[str, object]) -> None:
|
|
@@ -324,7 +266,6 @@ class RunApp(App[None]):
|
|
|
324
266
|
self.set_cell(run, "status", SPINNER[self.frame])
|
|
325
267
|
|
|
326
268
|
def show(self, text: str) -> None:
|
|
327
|
-
self.next_run = None
|
|
328
269
|
self.query_one("#status", Static).update(text)
|
|
329
270
|
|
|
330
271
|
def stop_runs(self) -> None:
|
|
@@ -358,84 +299,10 @@ class RunApp(App[None]):
|
|
|
358
299
|
cell = table.coordinate_to_cell_key(table.cursor_coordinate)
|
|
359
300
|
return str(cell.row_key.value)
|
|
360
301
|
|
|
361
|
-
def action_run_next(self) -> None:
|
|
362
|
-
if (run := self.cursor_run()) is not None:
|
|
363
|
-
self.controls.run_next(run)
|
|
364
|
-
|
|
365
|
-
def queue(self) -> list[str]:
|
|
366
|
-
return [run for run in self.cells if run in self.pending]
|
|
367
|
-
|
|
368
|
-
def action_grab(self) -> None:
|
|
369
|
-
if self.grabbed is not None:
|
|
370
|
-
self.action_drop()
|
|
371
|
-
return
|
|
372
|
-
run = self.cursor_run()
|
|
373
|
-
if run not in self.pending:
|
|
374
|
-
return
|
|
375
|
-
self.grabbed = run
|
|
376
|
-
self.grabbed_from = list(self.cells)
|
|
377
|
-
self.refresh_bindings()
|
|
378
|
-
self.show(f"Moving {run}. j/k moves it, Enter drops it, Escape puts it back.")
|
|
379
|
-
|
|
380
|
-
def action_shift(self, step: int) -> None:
|
|
381
|
-
run = str(self.grabbed)
|
|
382
|
-
queue = self.queue()
|
|
383
|
-
place = queue.index(run) + step
|
|
384
|
-
if place not in range(len(queue)):
|
|
385
|
-
return
|
|
386
|
-
order = list(self.cells)
|
|
387
|
-
here, there = order.index(run), order.index(queue[place])
|
|
388
|
-
order[here], order[there] = order[there], order[here]
|
|
389
|
-
self.cells = {key: self.cells[key] for key in order}
|
|
390
|
-
self.redraw_on(run)
|
|
391
|
-
|
|
392
|
-
def action_drop(self) -> None:
|
|
393
|
-
run = str(self.grabbed)
|
|
394
|
-
self.release()
|
|
395
|
-
self.show("")
|
|
396
|
-
self.controls.move(run, self.queue().index(run))
|
|
397
|
-
|
|
398
|
-
def action_put_back(self) -> None:
|
|
399
|
-
run = str(self.grabbed)
|
|
400
|
-
self.release()
|
|
401
|
-
places = {key: place for place, key in enumerate(self.grabbed_from)}
|
|
402
|
-
ordered = sorted(self.cells, key=lambda key: places.get(key, len(places)))
|
|
403
|
-
self.cells = {key: self.cells[key] for key in ordered}
|
|
404
|
-
self.redraw_on(run)
|
|
405
|
-
self.show("")
|
|
406
|
-
|
|
407
|
-
def release(self) -> None:
|
|
408
|
-
self.grabbed = None
|
|
409
|
-
self.refresh_bindings()
|
|
410
|
-
|
|
411
|
-
def redraw_on(self, run: str) -> None:
|
|
412
|
-
table = self.query_one(DataTable)
|
|
413
|
-
self.redraw(table.cursor_row)
|
|
414
|
-
table.move_cursor(row=table.get_row_index(run))
|
|
415
|
-
|
|
416
|
-
def action_toggle_run(self) -> None:
|
|
417
|
-
if (run := self.cursor_run()) is not None:
|
|
418
|
-
self.controls.toggle(run)
|
|
419
|
-
|
|
420
|
-
def action_hide_failed(self) -> None:
|
|
421
|
-
self.hiding = not self.hiding
|
|
422
|
-
self.redraw(self.query_one(DataTable).cursor_row)
|
|
423
|
-
self.show("Failed runs hidden." if self.hiding else "Failed runs shown.")
|
|
424
|
-
|
|
425
|
-
def action_retry(self) -> None:
|
|
426
|
-
if (run := self.cursor_run()) is not None and run in self.failed:
|
|
427
|
-
self.controls.retry(run)
|
|
428
|
-
|
|
429
302
|
def action_kill_run(self) -> None:
|
|
430
303
|
if (run := self.cursor_run()) is not None:
|
|
431
304
|
self.controls.kill(run)
|
|
432
305
|
|
|
433
|
-
def action_deselect_shown(self) -> None:
|
|
434
|
-
shown = [str(key.value) for key in self.query_one(DataTable).rows]
|
|
435
|
-
for run in shown:
|
|
436
|
-
if run in self.pending:
|
|
437
|
-
self.controls.toggle(run)
|
|
438
|
-
|
|
439
306
|
def action_concurrency(self, change: int) -> None:
|
|
440
307
|
self.controls.set_concurrency(self.concurrency + change)
|
|
441
308
|
|
|
@@ -443,10 +310,10 @@ class RunApp(App[None]):
|
|
|
443
310
|
field = self.query_one(Input)
|
|
444
311
|
field.display = True
|
|
445
312
|
field.focus()
|
|
313
|
+
self.refresh_bindings()
|
|
446
314
|
|
|
447
315
|
def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
|
|
448
|
-
|
|
449
|
-
self.view(str(event.row_key.value))
|
|
316
|
+
self.view(str(event.row_key.value))
|
|
450
317
|
|
|
451
318
|
def view(self, run: str) -> None:
|
|
452
319
|
self.viewing = run
|
|
@@ -481,6 +348,7 @@ class RunApp(App[None]):
|
|
|
481
348
|
field.value = ""
|
|
482
349
|
field.display = False
|
|
483
350
|
self.query_one(DataTable).focus()
|
|
351
|
+
self.refresh_bindings()
|
|
484
352
|
|
|
485
353
|
def on_input_changed(self, event: Input.Changed) -> None:
|
|
486
354
|
self.filter = event.value
|
|
@@ -489,3 +357,4 @@ class RunApp(App[None]):
|
|
|
489
357
|
def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
490
358
|
event.input.display = bool(event.value)
|
|
491
359
|
self.query_one(DataTable).focus()
|
|
360
|
+
self.refresh_bindings()
|
|
@@ -81,3 +81,9 @@ path = "src/labnotes/experiments.py"
|
|
|
81
81
|
rules = ["mutation"]
|
|
82
82
|
lines = [120]
|
|
83
83
|
reason = "click hands back the \"json\" choice literal itself, so is not equals !="
|
|
84
|
+
|
|
85
|
+
[[python.exempt]]
|
|
86
|
+
path = "src/labnotes/tui/run_app.py"
|
|
87
|
+
rules = ["mutation"]
|
|
88
|
+
lines = [221]
|
|
89
|
+
reason = "the leave action name is the string literal from the Binding, which CPython interns, so is equals =="
|
|
@@ -237,15 +237,15 @@ wheels = [
|
|
|
237
237
|
|
|
238
238
|
[[package]]
|
|
239
239
|
name = "curtaincall"
|
|
240
|
-
version = "0.
|
|
240
|
+
version = "0.4.0"
|
|
241
241
|
source = { registry = "https://pypi.org/simple" }
|
|
242
242
|
dependencies = [
|
|
243
243
|
{ name = "pexpect" },
|
|
244
244
|
{ name = "pyte" },
|
|
245
245
|
]
|
|
246
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
246
|
+
sdist = { url = "https://files.pythonhosted.org/packages/4c/c3/14a2abeb4d38d1c381c33fb3fbd4d55675a0f98be8c39b15d688c546b3f3/curtaincall-0.4.0.tar.gz", hash = "sha256:b68c9652cb33eb0955e5b9307573302e8b6f260930a67ab69152c48db79b75cc", size = 33924, upload-time = "2026-10-26T14:16:25.535Z" }
|
|
247
247
|
wheels = [
|
|
248
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
248
|
+
{ url = "https://files.pythonhosted.org/packages/bc/43/6c5749737b1fbb9a2757adf6df70ded2a38e832b63d4b4f9e75b6adf1080/curtaincall-0.4.0-py3-none-any.whl", hash = "sha256:2294a8b8e2d8cd10f47f5004ae7bc9b68ce9f7f1182c364dba294b3d190aa726", size = 29057, upload-time = "2026-10-26T14:16:24.342Z" },
|
|
249
249
|
]
|
|
250
250
|
|
|
251
251
|
[[package]]
|
|
@@ -602,7 +602,7 @@ requires-dist = [
|
|
|
602
602
|
|
|
603
603
|
[package.metadata.requires-dev]
|
|
604
604
|
dev = [
|
|
605
|
-
{ name = "curtaincall", specifier = ">=0.
|
|
605
|
+
{ name = "curtaincall", specifier = ">=0.4.0" },
|
|
606
606
|
{ name = "mypy", specifier = ">=2.4.0" },
|
|
607
607
|
{ name = "playwright", specifier = ">=1.64.0" },
|
|
608
608
|
{ name = "pytest", specifier = ">=8.0" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|