labnotes 0.2.10__tar.gz → 0.2.11__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.2.10 → labnotes-0.2.11}/PKG-INFO +1 -1
- labnotes-0.2.11/src/labnotes/tui/run_output.py +106 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/testing-conventions.toml +6 -0
- labnotes-0.2.10/src/labnotes/tui/run_output.py +0 -80
- {labnotes-0.2.10 → labnotes-0.2.11}/.gitignore +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/CHANGELOG.md +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/MIGRATIONS.md +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/README.md +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/pyproject.toml +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/__init__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/__main__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/check_counts.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/cli.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/command_line_group.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/compose_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/config_migration.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/context.md +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/copy_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/count_groups.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/create_app.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/create_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/create_note.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/data_html.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/default_counts.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/experiment_definition.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/experiment_notes.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/experiment_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/experiments.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/file_changes.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/format_duration.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/format_started.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/format_value.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/get_state.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/grid_cell.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/group_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/init.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/invocation_started.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/is_non_negative_int.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/is_non_negative_number.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/is_positive_int.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/latest_log.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/load_config.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/load_run.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/log.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/log_path.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/memory_interval.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/models.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/nests_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/note_path.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/output_html.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/param_names.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/parse_param_value.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/parse_params.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/parse_subset.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/pivot_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/read_config.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/read_path.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/retries.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/run_columns.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/run_output.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/cgroup_memory.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/check_args.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/check_hook_placeholders.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/check_subset.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/claim_run.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/command_flags.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/container_cgroup.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/container_memory.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/continue_run.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/docker_output.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/exit_signal.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/fill_dirs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/fill_experiment_env.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/finalize_lost_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/first_invocation.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/flag_name.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/group_args.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/hold_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/in_subset.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/invocation_hook.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/invocation_meta.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/new_stamped_run_id.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/override_flags.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/placeholders.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/prepare_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/project_snapshot.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/read_experiment_config.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/record_memory.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/run_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/run_git.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/run_locked.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/runs_parent.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/signal_tree.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/start_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/untracked_diff.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/wait_for_tree.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/runs_view_command.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/save_conflict_copy.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/save_note.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/server.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/set_state.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/shared_params.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/state_path.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/elapsed.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/experiment.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/local-time.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/new-note.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/note-edit.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/note-editor.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/run-output.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/summarize_config.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/experiment_run_ids.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/experiment_toml.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/experiments_ddl.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/file_text.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/list_resumable_runs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/note_text.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/open_tables.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_blocks.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_log.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_memory.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/read_run_file.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/runs_columns.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tables/summarize_experiments.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/templates/editor_imports.html +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/templates/note.html +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/templates/run.html +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/browse_app.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/browse_tui.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/check_view_response.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/config.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/dim.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/experiment_screen.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/experiments_screen.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/fill_table.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/format_cell.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/guard_view.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/leave_prompt.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/load_view.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/log_block.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/log_blocks.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/native_rows.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/reload_on_change.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/run_cells.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/run_panel.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/runs_browser.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/runs_table.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/runs_view.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/stopped_title.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/table_columns.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/table_rows.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/view_column.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/view_pane.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/view_process.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/tui/view_switcher.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/utils/__init__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/utils/format_bytes.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/utils/process_alive.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/utils/run_usage.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/utils/tree_rss.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/utils/tree_usage.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/__init__.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/answer.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/build.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/changed.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/experiment.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/respond.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view/serve.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/view_specs.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/wait_for_note.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/src/labnotes/watch_rows.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/tests/conftest.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/tests/e2e/conftest.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/tests/integration/conftest.py +0 -0
- {labnotes-0.2.10 → labnotes-0.2.11}/uv.lock +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import codecs
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Self
|
|
5
|
+
|
|
6
|
+
from rich.style import Style
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
from rich.cells import cell_len
|
|
9
|
+
from textual.geometry import Size
|
|
10
|
+
from textual.strip import Strip
|
|
11
|
+
from textual.widgets import Log
|
|
12
|
+
|
|
13
|
+
from labnotes.latest_log import latest_log
|
|
14
|
+
|
|
15
|
+
STREAMS = ("stdout", "stderr")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RunOutput(Log):
|
|
19
|
+
def __init__(self, id: str | None = None) -> None:
|
|
20
|
+
super().__init__(id=id)
|
|
21
|
+
self.reset()
|
|
22
|
+
|
|
23
|
+
def reset(self) -> None:
|
|
24
|
+
self.offsets = dict.fromkeys(STREAMS, 0)
|
|
25
|
+
self.paths: dict[str, Path] = {}
|
|
26
|
+
self.decoders = {
|
|
27
|
+
stream: codecs.getincrementaldecoder("utf-8")(errors="replace")
|
|
28
|
+
for stream in STREAMS
|
|
29
|
+
}
|
|
30
|
+
self.last_stream: str | None = None
|
|
31
|
+
self.unfinished = ""
|
|
32
|
+
self.clear()
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def mid_line(self) -> bool:
|
|
36
|
+
return bool(self.unfinished)
|
|
37
|
+
|
|
38
|
+
def follow(self, folder: Path) -> None:
|
|
39
|
+
for stream in STREAMS:
|
|
40
|
+
path = latest_log(folder, stream)
|
|
41
|
+
if not path.exists():
|
|
42
|
+
continue
|
|
43
|
+
if self.paths.setdefault(stream, path) != path:
|
|
44
|
+
self.paths[stream] = path
|
|
45
|
+
self.offsets[stream] = 0
|
|
46
|
+
with path.open("rb") as log:
|
|
47
|
+
log.seek(self.offsets[stream])
|
|
48
|
+
data = log.read()
|
|
49
|
+
self.offsets[stream] += len(data)
|
|
50
|
+
text = self.decoders[stream].decode(data)
|
|
51
|
+
if not text:
|
|
52
|
+
continue
|
|
53
|
+
# A stream's unfinished line is redrawn as it grows, but the
|
|
54
|
+
# other stream's output starts below it.
|
|
55
|
+
if self.mid_line and stream == self.last_stream:
|
|
56
|
+
self.drop_unfinished()
|
|
57
|
+
text = self.unfinished + text
|
|
58
|
+
*complete, self.unfinished = text.split("\n")
|
|
59
|
+
if complete:
|
|
60
|
+
self.write_lines(complete)
|
|
61
|
+
if self.unfinished:
|
|
62
|
+
self.write_lines([self.unfinished])
|
|
63
|
+
self.last_stream = stream
|
|
64
|
+
|
|
65
|
+
def write_lines(self, lines: Iterable[str], scroll_end: bool | None = None) -> Self:
|
|
66
|
+
new_lines = list(lines)
|
|
67
|
+
if not new_lines:
|
|
68
|
+
return self
|
|
69
|
+
at_end = self.is_vertical_scroll_end
|
|
70
|
+
self._lines.extend(new_lines)
|
|
71
|
+
self._width = max(self._width, max(map(len, new_lines)))
|
|
72
|
+
self.virtual_size = Size(self._width, len(self._lines))
|
|
73
|
+
self.refresh()
|
|
74
|
+
if (
|
|
75
|
+
self.is_mounted
|
|
76
|
+
and (self.auto_scroll if scroll_end is None else scroll_end)
|
|
77
|
+
and at_end
|
|
78
|
+
):
|
|
79
|
+
self.scroll_end(animate=False, immediate=True, x_axis=False)
|
|
80
|
+
return self
|
|
81
|
+
|
|
82
|
+
def drop_unfinished(self) -> None:
|
|
83
|
+
self._lines.pop()
|
|
84
|
+
self._render_line_cache.discard(len(self._lines))
|
|
85
|
+
self.virtual_size = Size(self._width, len(self._lines))
|
|
86
|
+
self.refresh()
|
|
87
|
+
|
|
88
|
+
def _render_line_strip(self, y: int, rich_style: Style) -> Strip:
|
|
89
|
+
selection = self.text_selection
|
|
90
|
+
if selection is None and y in self._render_line_cache:
|
|
91
|
+
return self._render_line_cache[y]
|
|
92
|
+
line_text = Text.from_ansi(self._lines[y], style=rich_style)
|
|
93
|
+
if selection is not None:
|
|
94
|
+
if (span := selection.get_span(y)) is not None:
|
|
95
|
+
start, end = span
|
|
96
|
+
if end == -1:
|
|
97
|
+
end = len(line_text)
|
|
98
|
+
line_text.stylize(
|
|
99
|
+
self.screen.get_component_rich_style("screen--selection"),
|
|
100
|
+
start,
|
|
101
|
+
end,
|
|
102
|
+
)
|
|
103
|
+
line = Strip(line_text.render(self.app.console), cell_len(line_text.plain))
|
|
104
|
+
if selection is None:
|
|
105
|
+
self._render_line_cache[y] = line
|
|
106
|
+
return line
|
|
@@ -51,3 +51,9 @@ path = "src/labnotes/runner/hold_experiment.py"
|
|
|
51
51
|
rules = ["mutation"]
|
|
52
52
|
lines = [18]
|
|
53
53
|
reason = "LOCK_EX and LOCK_NB are disjoint bits, so | equals + and ^"
|
|
54
|
+
|
|
55
|
+
[[python.exempt]]
|
|
56
|
+
path = "src/labnotes/tui/run_output.py"
|
|
57
|
+
rules = ["mutation"]
|
|
58
|
+
lines = [96]
|
|
59
|
+
reason = "a selection span ends at -1 or a non-negative offset, so <= equals ==; -1 is a CPython cached small int, so is equals =="
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import codecs
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Any, Self
|
|
4
|
-
|
|
5
|
-
from rich.text import Text
|
|
6
|
-
from textual.geometry import Size
|
|
7
|
-
from textual.widgets import RichLog
|
|
8
|
-
|
|
9
|
-
from labnotes.latest_log import latest_log
|
|
10
|
-
|
|
11
|
-
STREAMS = ("stdout", "stderr")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class RunOutput(RichLog):
|
|
15
|
-
def __init__(self, id: str | None = None) -> None:
|
|
16
|
-
super().__init__(id=id, wrap=True, min_width=1)
|
|
17
|
-
self.reset()
|
|
18
|
-
|
|
19
|
-
def reset(self) -> None:
|
|
20
|
-
self.offsets = dict.fromkeys(STREAMS, 0)
|
|
21
|
-
self.paths: dict[str, Path] = {}
|
|
22
|
-
self.decoders = {
|
|
23
|
-
stream: codecs.getincrementaldecoder("utf-8")(errors="replace")
|
|
24
|
-
for stream in STREAMS
|
|
25
|
-
}
|
|
26
|
-
self.last_stream: str | None = None
|
|
27
|
-
self.unfinished = ""
|
|
28
|
-
self.written_rows = 0
|
|
29
|
-
self.clear()
|
|
30
|
-
# A hidden log has no width; writing now would wrap every line to one
|
|
31
|
-
# cell. Hold writes until it's shown and resized.
|
|
32
|
-
self._size_known = bool(self.scrollable_content_region.width)
|
|
33
|
-
|
|
34
|
-
@property
|
|
35
|
-
def mid_line(self) -> bool:
|
|
36
|
-
return bool(self.unfinished)
|
|
37
|
-
|
|
38
|
-
def follow(self, folder: Path) -> None:
|
|
39
|
-
for stream in STREAMS:
|
|
40
|
-
path = latest_log(folder, stream)
|
|
41
|
-
if not path.exists():
|
|
42
|
-
continue
|
|
43
|
-
if self.paths.setdefault(stream, path) != path:
|
|
44
|
-
self.paths[stream] = path
|
|
45
|
-
self.offsets[stream] = 0
|
|
46
|
-
with path.open("rb") as log:
|
|
47
|
-
log.seek(self.offsets[stream])
|
|
48
|
-
data = log.read()
|
|
49
|
-
self.offsets[stream] += len(data)
|
|
50
|
-
text = self.decoders[stream].decode(data)
|
|
51
|
-
if not text:
|
|
52
|
-
continue
|
|
53
|
-
# A stream's unfinished line is redrawn as it grows, but the
|
|
54
|
-
# other stream's output starts below it.
|
|
55
|
-
if self.mid_line and stream == self.last_stream:
|
|
56
|
-
self.drop_unfinished()
|
|
57
|
-
text = self.unfinished + text
|
|
58
|
-
*complete, self.unfinished = text.split("\n")
|
|
59
|
-
if complete:
|
|
60
|
-
self.write(Text.from_ansi("\n".join(complete)))
|
|
61
|
-
if self.unfinished:
|
|
62
|
-
self.write(Text.from_ansi(self.unfinished))
|
|
63
|
-
self.last_stream = stream
|
|
64
|
-
|
|
65
|
-
# Counted here, not in follow: writes made before the size is known
|
|
66
|
-
# render later, from on_resize.
|
|
67
|
-
def write(self, content: object, *args: Any, **kwargs: Any) -> Self:
|
|
68
|
-
rows = len(self.lines)
|
|
69
|
-
super().write(content, *args, **kwargs)
|
|
70
|
-
self.written_rows = len(self.lines) - rows
|
|
71
|
-
return self
|
|
72
|
-
|
|
73
|
-
def drop_unfinished(self) -> None:
|
|
74
|
-
if not self._size_known:
|
|
75
|
-
self._deferred_renders.pop()
|
|
76
|
-
return
|
|
77
|
-
del self.lines[-self.written_rows :]
|
|
78
|
-
self._line_cache.clear()
|
|
79
|
-
self.virtual_size = Size(self.virtual_size.width, len(self.lines))
|
|
80
|
-
self.refresh()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|