cmd2 4.3.0__tar.gz → 4.3.1__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.
- {cmd2-4.3.0 → cmd2-4.3.1}/.pre-commit-config.yaml +1 -1
- {cmd2-4.3.0 → cmd2-4.3.1}/CHANGELOG.md +14 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/MANIFEST.in +1 -1
- {cmd2-4.3.0 → cmd2-4.3.1}/PKG-INFO +7 -1
- {cmd2-4.3.0 → cmd2-4.3.1}/README.md +6 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/annotated.py +11 -10
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/argparse_utils.py +3 -3
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2.egg-info/PKG-INFO +7 -1
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2.egg-info/SOURCES.txt +2 -1
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2.egg-info/scm_file_list.json +2 -0
- cmd2-4.3.1/cmd2.egg-info/scm_version.json +8 -0
- cmd2-4.3.1/docs/examples/embedding_in_textual.md +120 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/examples/index.md +1 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/prompt.md +7 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/overview/alternatives.md +6 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/README.md +5 -0
- cmd2-4.3.1/examples/textual_tty_embed.py +332 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/mkdocs.yml +1 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/pyproject.toml +1 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_annotated.py +35 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_pipeline_job_control.py +17 -2
- cmd2-4.3.0/cmd2.egg-info/scm_version.json +0 -8
- cmd2-4.3.0/docs/.DS_Store +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/.prettierignore +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/.prettierrc +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/.typos.toml +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/AGENTS.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/CLAUDE.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/GEMINI.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/LICENSE +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/Makefile +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/__init__.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/argparse_completer.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/clipboard.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/cmd2.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/colors.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/command_set.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/completion.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/constants.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/decorators.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/exceptions.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/history.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/parsing.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/plugin.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/pt_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/py.typed +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/py_bridge.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/rich_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/string_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/styles.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/theme.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/types.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2/utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2.egg-info/dependency_links.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2.egg-info/requires.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/cmd2.egg-info/top_level.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/codecov.yml +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/annotated.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/argparse_completer.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/argparse_utils.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/clipboard.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/cmd.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/colors.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/command_set.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/completion.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/constants.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/decorators.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/exceptions.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/history.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/index.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/parsing.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/plugin.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/pt_utils.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/py_bridge.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/rich_utils.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/string_utils.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/styles.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/theme.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/api/utils.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/assets/cmd2-logo.png +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/assets/cmd2-readme-demo.gif +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/assets/getting-started-demo.gif +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/doc_conventions.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/examples/alternate_event_loops.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/examples/examples.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/examples/getting_started.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/annotated.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/argument_processing.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/async_commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/builtin_commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/clipboard.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/completion.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/disable_commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/embedded_python_shells.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/generating_output.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/help.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/history.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/hooks.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/index.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/initialization.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/misc.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/modular_commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/multiline_commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/os.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/packaging.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/plugins.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/redirection.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/scripting.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/settings.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/shortcuts_aliases_macros.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/startup_commands.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/table_creation.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/features/theme.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/index.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/javascripts/readthedocs.js +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/migrating/incompatibilities.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/migrating/index.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/migrating/minimum.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/migrating/next_steps.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/migrating/why.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/mixins/index.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/mixins/mixin_template.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/overrides/main.html +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/overview/index.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/overview/installation.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/overview/integrating.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/overview/resources.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/stylesheets/cmd2.css +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/testing.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/docs/upgrades.md +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/.cmd2rc +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/annotated_example.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/argparse_completion.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/argparse_example.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/async_call.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/async_commands.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/async_printing.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/basic_completion.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/cmd2_history.dat +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/cmd_as_argument.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/color.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/command_sets.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/completion_item_choices.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/custom_parser.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/custom_types.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/default_categories.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/dynamic_commands.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/environment.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/event_loops.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/exit_code.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/getting_started.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/hello_cmd2.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/help_categories.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/hooks.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/migrating.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/mixin.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/modular_commands/__init__.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/modular_commands/commandset_basic.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/modular_commands/commandset_complex.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/modular_commands/commandset_custominit.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/modular_commandsets.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/paged_output.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/persistent_history.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/pretty_print.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/python_scripting.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/read_input.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/remove_builtin_commands.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/remove_settable.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/rich_tables.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/rich_theme.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/arg_printer.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/conditional.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/nested.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/quit.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/save_help_text.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/script.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/scripts/script.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/tmux_launch.sh +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/tmux_split.sh +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/examples/unicode_commands.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/package.json +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/ruff.toml +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/scripts/validate_tag.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/setup.cfg +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/.cmd2rc +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/__init__.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/conftest.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/echo.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/environment.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/help.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/py_locals.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/pyscript_dir.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/raises_exception.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/recursive.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/self_in_py.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/stop.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/pyscript/test_print.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/relative_multiple.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/script.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/script.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/binary.bin +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/empty.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/help.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/nested.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/one_down.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/postcmds.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/precmds.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/scripts/utf8.txt +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_argparse.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_argparse_completer.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_argparse_subcommands.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_argparse_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_categories.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_cmd2.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_commandset.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_completion.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_dynamic_complete_style.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_future_annotations.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_history.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_parsing.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_plugin.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_pt_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_py_completion.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_rich_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_run_pyscript.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_string_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_suite_environment.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_theme.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_utils.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/tests/test_utils_defining_class.py +0 -0
- {cmd2-4.3.0 → cmd2-4.3.1}/ty.toml +0 -0
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 4.3.1 (October 24, 2026)
|
|
2
|
+
|
|
3
|
+
- Bug Fixes
|
|
4
|
+
- Fixed `@with_annotated` command `--help` output bypassing the application's output stream,
|
|
5
|
+
leaving redirected help files empty and preventing help from being captured by embedded apps.
|
|
6
|
+
- Enhancements
|
|
7
|
+
- Added the
|
|
8
|
+
[textual_tty_embed.py](https://github.com/python-cmd2/cmd2/blob/main/examples/textual_tty_embed.py)
|
|
9
|
+
example, which embeds a `cmd2` application in a [Textual](https://textual.textualize.io/)
|
|
10
|
+
application using [textual-tty](https://github.com/ttygroup/textual-tty). The Textual
|
|
11
|
+
application shows a realtime status panel beside the `cmd2` application, which can display
|
|
12
|
+
much richer information than a bottom toolbar. See the
|
|
13
|
+
[Embedding in Textual](docs/examples/embedding_in_textual.md) documentation for details.
|
|
14
|
+
|
|
1
15
|
## 4.3.0 (October 13, 2026)
|
|
2
16
|
|
|
3
17
|
- Stabilized features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmd2
|
|
3
|
-
Version: 4.3.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
|
|
5
5
|
Author: cmd2 Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -55,6 +55,12 @@ completion, command history, scripting, output styling, and much more.
|
|
|
55
55
|
You can use `cmd2` for a small internal tool and grow the same application into an extensible,
|
|
56
56
|
scriptable interface without replacing the framework or writing the usual CLI boilerplate.
|
|
57
57
|
|
|
58
|
+
Want a richer visual display than a prompt and toolbar can offer? Your `cmd2` application can run
|
|
59
|
+
inside a terminal pane of a [Textual](https://textual.textualize.io/) application, right next to
|
|
60
|
+
dashboards and panels that show realtime status and other information. See
|
|
61
|
+
[Embedding in Textual](https://cmd2.readthedocs.io/en/latest/examples/embedding_in_textual/) for an
|
|
62
|
+
example.
|
|
63
|
+
|
|
58
64
|
## Quick start
|
|
59
65
|
|
|
60
66
|
Install `cmd2`:
|
|
@@ -26,6 +26,12 @@ completion, command history, scripting, output styling, and much more.
|
|
|
26
26
|
You can use `cmd2` for a small internal tool and grow the same application into an extensible,
|
|
27
27
|
scriptable interface without replacing the framework or writing the usual CLI boilerplate.
|
|
28
28
|
|
|
29
|
+
Want a richer visual display than a prompt and toolbar can offer? Your `cmd2` application can run
|
|
30
|
+
inside a terminal pane of a [Textual](https://textual.textualize.io/) application, right next to
|
|
31
|
+
dashboards and panels that show realtime status and other information. See
|
|
32
|
+
[Embedding in Textual](https://cmd2.readthedocs.io/en/latest/examples/embedding_in_textual/) for an
|
|
33
|
+
example.
|
|
34
|
+
|
|
29
35
|
## Quick start
|
|
30
36
|
|
|
31
37
|
Install `cmd2`:
|
|
@@ -3154,28 +3154,29 @@ def with_annotated(
|
|
|
3154
3154
|
|
|
3155
3155
|
@functools.wraps(command_func)
|
|
3156
3156
|
def cmd_wrapper(*args: Any, **kwargs: Any) -> _CommandReturn:
|
|
3157
|
-
|
|
3157
|
+
cmd_app, statement_arg = _parse_positionals(args)
|
|
3158
3158
|
owner = args[0] # Cmd or CommandSet instance
|
|
3159
|
-
statement, parsed_arglist =
|
|
3159
|
+
statement, parsed_arglist = cmd_app.statement_parser.get_command_arg_list(
|
|
3160
3160
|
command_name, statement_arg, preserve_quotes
|
|
3161
3161
|
)
|
|
3162
3162
|
|
|
3163
|
-
arg_parser =
|
|
3163
|
+
arg_parser = cmd_app.command_parsers.get(cast(BoundCommandFunc[...], cmd_wrapper))
|
|
3164
3164
|
if arg_parser is None:
|
|
3165
3165
|
raise ValueError(f"No argument parser found for {command_name}")
|
|
3166
3166
|
|
|
3167
3167
|
if ns_provider is None:
|
|
3168
3168
|
namespace = None
|
|
3169
3169
|
else:
|
|
3170
|
-
provider_self =
|
|
3171
|
-
namespace = ns_provider(provider_self if provider_self is not None else
|
|
3170
|
+
provider_self = cmd_app._resolve_func_self(ns_provider, args[0])
|
|
3171
|
+
namespace = ns_provider(provider_self if provider_self is not None else cmd_app)
|
|
3172
3172
|
|
|
3173
3173
|
try:
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3174
|
+
with arg_parser.output_to(cmd_app.stdout):
|
|
3175
|
+
if with_unknown_args:
|
|
3176
|
+
ns, unknown = arg_parser.parse_known_args(parsed_arglist, namespace)
|
|
3177
|
+
else:
|
|
3178
|
+
ns = arg_parser.parse_args(parsed_arglist, namespace)
|
|
3179
|
+
unknown = None
|
|
3179
3180
|
except SystemExit as exc:
|
|
3180
3181
|
raise Cmd2ArgparseError from exc
|
|
3181
3182
|
|
|
@@ -768,9 +768,9 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
768
768
|
self.completer_class = completer_class
|
|
769
769
|
|
|
770
770
|
# To assist type checkers, recast these to reflect our usage of rich-argparse.
|
|
771
|
-
self.formatter_class: type[Cmd2HelpFormatter]
|
|
772
|
-
self.description: HelpContent | None # type: ignore[assignment]
|
|
773
|
-
self.epilog: HelpContent | None # type: ignore[assignment]
|
|
771
|
+
self.formatter_class: type[Cmd2HelpFormatter] # ty: ignore[invalid-mutable-override]
|
|
772
|
+
self.description: HelpContent | None # type: ignore[assignment] # ty: ignore[invalid-attribute-override]
|
|
773
|
+
self.epilog: HelpContent | None # type: ignore[assignment] # ty: ignore[invalid-attribute-override]
|
|
774
774
|
|
|
775
775
|
def print_usage(self, file: IO[str] | None = None) -> None: # type: ignore[override] # ty: ignore[invalid-method-override]
|
|
776
776
|
"""Override to ensure the formatter is aware of the target file."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmd2
|
|
3
|
-
Version: 4.3.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
|
|
5
5
|
Author: cmd2 Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -55,6 +55,12 @@ completion, command history, scripting, output styling, and much more.
|
|
|
55
55
|
You can use `cmd2` for a small internal tool and grow the same application into an extensible,
|
|
56
56
|
scriptable interface without replacing the framework or writing the usual CLI boilerplate.
|
|
57
57
|
|
|
58
|
+
Want a richer visual display than a prompt and toolbar can offer? Your `cmd2` application can run
|
|
59
|
+
inside a terminal pane of a [Textual](https://textual.textualize.io/) application, right next to
|
|
60
|
+
dashboards and panels that show realtime status and other information. See
|
|
61
|
+
[Embedding in Textual](https://cmd2.readthedocs.io/en/latest/examples/embedding_in_textual/) for an
|
|
62
|
+
example.
|
|
63
|
+
|
|
58
64
|
## Quick start
|
|
59
65
|
|
|
60
66
|
Install `cmd2`:
|
|
@@ -47,7 +47,6 @@ cmd2.egg-info/requires.txt
|
|
|
47
47
|
cmd2.egg-info/scm_file_list.json
|
|
48
48
|
cmd2.egg-info/scm_version.json
|
|
49
49
|
cmd2.egg-info/top_level.txt
|
|
50
|
-
docs/.DS_Store
|
|
51
50
|
docs/doc_conventions.md
|
|
52
51
|
docs/index.md
|
|
53
52
|
docs/testing.md
|
|
@@ -78,6 +77,7 @@ docs/assets/cmd2-logo.png
|
|
|
78
77
|
docs/assets/cmd2-readme-demo.gif
|
|
79
78
|
docs/assets/getting-started-demo.gif
|
|
80
79
|
docs/examples/alternate_event_loops.md
|
|
80
|
+
docs/examples/embedding_in_textual.md
|
|
81
81
|
docs/examples/examples.md
|
|
82
82
|
docs/examples/getting_started.md
|
|
83
83
|
docs/examples/index.md
|
|
@@ -162,6 +162,7 @@ examples/remove_builtin_commands.py
|
|
|
162
162
|
examples/remove_settable.py
|
|
163
163
|
examples/rich_tables.py
|
|
164
164
|
examples/rich_theme.py
|
|
165
|
+
examples/textual_tty_embed.py
|
|
165
166
|
examples/tmux_launch.sh
|
|
166
167
|
examples/tmux_split.sh
|
|
167
168
|
examples/unicode_commands.py
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"docs/assets/getting-started-demo.gif",
|
|
76
76
|
"docs/doc_conventions.md",
|
|
77
77
|
"docs/examples/alternate_event_loops.md",
|
|
78
|
+
"docs/examples/embedding_in_textual.md",
|
|
78
79
|
"docs/examples/examples.md",
|
|
79
80
|
"docs/examples/getting_started.md",
|
|
80
81
|
"docs/examples/index.md",
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
"examples/scripts/save_help_text.py",
|
|
173
174
|
"examples/scripts/script.py",
|
|
174
175
|
"examples/scripts/script.txt",
|
|
176
|
+
"examples/textual_tty_embed.py",
|
|
175
177
|
"examples/tmux_launch.sh",
|
|
176
178
|
"examples/tmux_split.sh",
|
|
177
179
|
"examples/unicode_commands.py",
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Embedding in Textual
|
|
2
|
+
|
|
3
|
+
[Textual](https://textual.textualize.io/) builds full-screen terminal user interfaces with widgets,
|
|
4
|
+
layouts, and mouse support, while `cmd2` builds interactive command interpreters. You don't have to
|
|
5
|
+
choose between them. [textual-tty](https://github.com/ttygroup/textual-tty) provides a `Terminal`
|
|
6
|
+
widget for Textual applications, which is a terminal emulator that runs a program attached to a
|
|
7
|
+
pseudo-terminal. That program can be a `cmd2` application, so a Textual application can show a
|
|
8
|
+
`cmd2` application in one pane and, beside it, other widgets which display realtime status and
|
|
9
|
+
situational awareness information. This can be much richer than what fits in a
|
|
10
|
+
[bottom toolbar](../features/prompt.md#bottom-toolbar).
|
|
11
|
+
|
|
12
|
+
The
|
|
13
|
+
[textual_tty_embed.py](https://github.com/python-cmd2/cmd2/blob/main/examples/textual_tty_embed.py)
|
|
14
|
+
example shows how to do this. It has a `cmd2` application in a terminal pane on the left. On the
|
|
15
|
+
right, a status panel shows whether the `cmd2` application is idle or running a command, how many
|
|
16
|
+
commands it has run, and how long the last one took, and a clock is updated by Textual on its own.
|
|
17
|
+
|
|
18
|
+
!!! warning
|
|
19
|
+
|
|
20
|
+
textual-tty is still pre-alpha software, so its API may change. The example was written for
|
|
21
|
+
textual-tty 0.4. Also, on Windows textual-tty can only start a program by name and can't pass
|
|
22
|
+
it arguments, so the example's Textual application requires a POSIX system such as Linux or
|
|
23
|
+
macOS.
|
|
24
|
+
|
|
25
|
+
## Running the Example
|
|
26
|
+
|
|
27
|
+
Neither Textual nor textual-tty are dependencies of `cmd2`. In a `cmd2` checkout, textual-tty is
|
|
28
|
+
part of the development environment on POSIX systems, so you can run:
|
|
29
|
+
|
|
30
|
+
```shell
|
|
31
|
+
uv run examples/textual_tty_embed.py
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Otherwise, install textual-tty, which also installs Textual, into your own environment:
|
|
35
|
+
|
|
36
|
+
```shell
|
|
37
|
+
pip install textual-tty
|
|
38
|
+
python examples/textual_tty_embed.py
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Use the `quit` command or press ++ctrl+q++ to exit. Pass `--cmd2-only` to run just the `cmd2`
|
|
42
|
+
application in your current terminal, without Textual.
|
|
43
|
+
|
|
44
|
+
## How It Works
|
|
45
|
+
|
|
46
|
+
The Textual application runs the `cmd2` application as a child process in a `Terminal` widget. The
|
|
47
|
+
child process is the example script itself, run with `--cmd2-only --report-status`:
|
|
48
|
+
|
|
49
|
+
```py
|
|
50
|
+
def compose(self) -> ComposeResult:
|
|
51
|
+
cmd2_command = [sys.executable, __file__, "--cmd2-only", "--report-status"]
|
|
52
|
+
yield Header()
|
|
53
|
+
with Horizontal():
|
|
54
|
+
with Vertical(id="cmd2-pane"):
|
|
55
|
+
yield Terminal(command=cmd2_command, id="cmd2")
|
|
56
|
+
with Vertical(id="sidebar"):
|
|
57
|
+
yield StatusPanel(id="status")
|
|
58
|
+
yield ClockPanel(id="clock")
|
|
59
|
+
yield Footer()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Because it is attached to a pseudo-terminal, the `cmd2` application is a completely normal `cmd2`
|
|
63
|
+
application which uses `prompt-toolkit` and doesn't know that it is embedded. Everything typed into
|
|
64
|
+
the focused `Terminal` goes to the `cmd2` application.
|
|
65
|
+
|
|
66
|
+
To report its state, the `cmd2` application registers a
|
|
67
|
+
[postparsing hook](../features/hooks.md#postparsing-hooks), which runs before each command, and a
|
|
68
|
+
[command finalization hook](../features/hooks.md#command-finalization-hooks), which runs after it.
|
|
69
|
+
Both of them call [cmd2.Cmd.set_window_title][] with a JSON document. The document is prefixed with
|
|
70
|
+
`cmd2-status:` so that the Textual application can tell it apart from other window titles. The
|
|
71
|
+
`Terminal` widget turns each title change into a `Terminal.TitleChanged` message, which the Textual
|
|
72
|
+
application handles to update the status panel:
|
|
73
|
+
|
|
74
|
+
```py
|
|
75
|
+
def on_terminal_title_changed(self, event: Terminal.TitleChanged) -> None:
|
|
76
|
+
if not event.title.startswith(STATUS_PREFIX):
|
|
77
|
+
return
|
|
78
|
+
with contextlib.suppress(TypeError, ValueError, OverflowError, RecursionError):
|
|
79
|
+
status = json.loads(event.title.removeprefix(STATUS_PREFIX))
|
|
80
|
+
if isinstance(status, dict):
|
|
81
|
+
self.query_one(StatusPanel).apply(status)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Since the status travels through the pseudo-terminal, there are no sockets, files, or threads to
|
|
85
|
+
manage.
|
|
86
|
+
|
|
87
|
+
## Things to Watch Out For
|
|
88
|
+
|
|
89
|
+
The example handles several details which are easy to miss when building something similar:
|
|
90
|
+
|
|
91
|
+
- Command finalization hooks run for every line of input, including blank lines, comments,
|
|
92
|
+
++ctrl+c++ at the prompt, and lines with syntax errors. The other hooks only run for lines which
|
|
93
|
+
were parsed into a statement, so check whether `data.statement` is `None` in a finalization hook.
|
|
94
|
+
- Commands run by other commands, like `run_script`, `history -r`, and `run_pyscript`, go through
|
|
95
|
+
the hooks too. The example counts the running commands so that only the outermost one is reported.
|
|
96
|
+
- The postparsing hooks stop running as soon as one of them sets `stop` or raises an exception, but
|
|
97
|
+
the finalization hooks still run. If your application has other postparsing hooks, register the
|
|
98
|
+
one which counts commands first so that it is never skipped.
|
|
99
|
+
- `prompt-toolkit` buffers its output, so flush it after setting the window title when a command
|
|
100
|
+
starts. Otherwise the "running" state only reaches the Textual application after the command is
|
|
101
|
+
done.
|
|
102
|
+
- Any program run in the terminal, for example by the `shell` command, can set the window title.
|
|
103
|
+
Validate a status document before using it. Besides `json.JSONDecodeError`, `json.loads` raises
|
|
104
|
+
`ValueError` for integers with too many digits and `RecursionError` for documents which are nested
|
|
105
|
+
too deeply. Also escape the document's strings with `textual.markup.escape` before putting them in
|
|
106
|
+
Textual markup.
|
|
107
|
+
- Only report status through the window title when running inside the Textual application. In a
|
|
108
|
+
normal terminal, it would overwrite the title of the user's window.
|
|
109
|
+
- If the Textual application exits while a command is running, the pseudo-terminal is closed before
|
|
110
|
+
the finalization hook reports the end of that command, so setting the window title raises
|
|
111
|
+
`OSError`. The example ignores that error.
|
|
112
|
+
- When the child process exits, `Terminal.ProcessExited.exit_code` holds its exit code, which is the
|
|
113
|
+
negated signal number if a signal killed it. The example passes the exit code back to the shell,
|
|
114
|
+
using 128 plus the signal number like a shell does, and when it isn't 0 the example keeps the
|
|
115
|
+
terminal on the screen so that any traceback can still be read.
|
|
116
|
+
- A `Terminal` sizes its pseudo-terminal from its outer size, so put a border on a container around
|
|
117
|
+
the `Terminal` rather than on the `Terminal` itself. Otherwise the `cmd2` application draws more
|
|
118
|
+
rows than are visible and its prompt can end up hidden.
|
|
119
|
+
- The focused `Terminal` sends almost every key press to the `cmd2` application. Textual's built-in
|
|
120
|
+
++ctrl+q++ binding to quit is a priority binding, so it still works.
|
|
@@ -106,3 +106,10 @@ class App(cmd2.Cmd):
|
|
|
106
106
|
See the
|
|
107
107
|
[getting_started.py](https://github.com/python-cmd2/cmd2/blob/main/examples/getting_started.py)
|
|
108
108
|
example for a demonstration of this technique.
|
|
109
|
+
|
|
110
|
+
!!! tip
|
|
111
|
+
|
|
112
|
+
If you want to show more realtime status information than fits in a toolbar, you can run your
|
|
113
|
+
`cmd2` application inside a [Textual](https://textual.textualize.io/) application, next to
|
|
114
|
+
widgets which display that information. See
|
|
115
|
+
[Embedding in Textual](../examples/embedding_in_textual.md).
|
|
@@ -38,3 +38,9 @@ If you are seeking a visually richer end-user experience and don't mind investin
|
|
|
38
38
|
time, we would recommend checking out [Textual](https://github.com/Textualize/textual) as this can
|
|
39
39
|
be used to build very sophisticated user interfaces in a terminal that are more akin to feature-rich
|
|
40
40
|
web GUIs.
|
|
41
|
+
|
|
42
|
+
You don't have to choose between `cmd2` and Textual, though. The
|
|
43
|
+
[textual-tty](https://github.com/ttygroup/textual-tty) package provides a terminal emulator widget
|
|
44
|
+
for Textual, so a `cmd2` application can run inside a Textual application, next to widgets which
|
|
45
|
+
display realtime information about it. See
|
|
46
|
+
[Embedding in Textual](../examples/embedding_in_textual.md) for an example of how to do this.
|
|
@@ -92,6 +92,11 @@ each:
|
|
|
92
92
|
- Example of using Rich Tables within a cmd2 application for displaying tabular data
|
|
93
93
|
- [rich_theme.py](https://github.com/python-cmd2/cmd2/blob/main/examples/rich_theme.py)
|
|
94
94
|
- Demonstrates how to create a custom theme for a cmd2 application
|
|
95
|
+
- [textual_tty_embed.py](https://github.com/python-cmd2/cmd2/blob/main/examples/textual_tty_embed.py)
|
|
96
|
+
- Shows how to embed a `cmd2` application in a [Textual](https://textual.textualize.io/)
|
|
97
|
+
application using [textual-tty](https://github.com/ttygroup/textual-tty), with a realtime
|
|
98
|
+
status panel next to the terminal. Requires a POSIX system such as Linux or macOS and
|
|
99
|
+
`textual-tty`, which is part of the `cmd2` development environment but not a `cmd2` dependency
|
|
95
100
|
- [tmux_launch.sh](https://github.com/python-cmd2/cmd2/blob/main/examples/tmux_launch.sh)
|
|
96
101
|
- Shell script that launches two applications using tmux in different windows/tabs
|
|
97
102
|
- [tmux_split.sh](https://github.com/python-cmd2/cmd2/blob/main/examples/tmux_split.sh)
|