cmd2 3.3.0__tar.gz → 3.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmd2-3.3.0 → cmd2-3.5.0}/CHANGELOG.md +18 -1
- {cmd2-3.3.0 → cmd2-3.5.0}/PKG-INFO +3 -3
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/argparse_completer.py +1 -1
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/argparse_custom.py +2 -2
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/cmd2.py +43 -102
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/rich_utils.py +151 -66
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/utils.py +1 -1
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2.egg-info/PKG-INFO +3 -3
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2.egg-info/SOURCES.txt +0 -1
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2.egg-info/requires.txt +2 -2
- {cmd2-3.3.0 → cmd2-3.5.0}/pyproject.toml +2 -2
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_cmd2.py +21 -46
- cmd2-3.5.0/tests/test_rich_utils.py +254 -0
- cmd2-3.3.0/examples/cmd2_history.dat +0 -0
- cmd2-3.3.0/tests/test_rich_utils.py +0 -144
- {cmd2-3.3.0 → cmd2-3.5.0}/.pre-commit-config.yaml +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/.prettierignore +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/.prettierrc +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/GEMINI.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/LICENSE +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/MANIFEST.in +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/Makefile +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/README.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/__init__.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/clipboard.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/colors.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/command_definition.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/constants.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/decorators.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/exceptions.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/history.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/parsing.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/plugin.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/py.typed +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/py_bridge.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/rl_utils.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/string_utils.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/styles.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/terminal_utils.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2/transcript.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2.egg-info/dependency_links.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2.egg-info/top_level.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/cmd2.png +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/codecov.yml +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/argparse_completer.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/argparse_custom.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/clipboard.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/cmd.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/colors.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/command_definition.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/constants.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/decorators.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/exceptions.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/history.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/parsing.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/plugin.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/py_bridge.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/rich_utils.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/rl_utils.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/string_utils.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/styles.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/terminal_utils.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/transcript.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/api/utils.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/doc_conventions.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/examples/alternate_event_loops.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/examples/examples.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/examples/getting_started.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/examples/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/argument_processing.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/builtin_commands.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/clipboard.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/commands.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/completion.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/disable_commands.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/embedded_python_shells.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/generating_output.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/help.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/history.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/hooks.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/initialization.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/misc.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/modular_commands.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/multiline_commands.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/os.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/packaging.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/plugins.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/prompt.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/redirection.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/scripting.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/settings.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/shortcuts_aliases_macros.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/startup_commands.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/table_creation.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/theme.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/features/transcripts.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/javascripts/readthedocs.js +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/migrating/incompatibilities.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/migrating/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/migrating/minimum.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/migrating/next_steps.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/migrating/why.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/mixins/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/mixins/mixin_template.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/overrides/main.html +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/overview/alternatives.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/overview/index.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/overview/installation.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/overview/integrating.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/overview/resources.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/stylesheets/cmd2.css +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/testing.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/docs/upgrades.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/.cmd2rc +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/README.md +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/argparse_completion.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/argparse_example.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/async_call.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/async_printing.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/basic_completion.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/cmd_as_argument.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/color.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/command_sets.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/custom_parser.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/custom_types.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/default_categories.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/dynamic_commands.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/environment.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/event_loops.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/exit_code.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/getting_started.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/hello_cmd2.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/help_categories.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/hooks.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/migrating.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/mixin.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/modular_commands/__init__.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/modular_commands/commandset_basic.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/modular_commands/commandset_complex.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/modular_commands/commandset_custominit.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/modular_commands.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/paged_output.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/persistent_history.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/pretty_print.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/python_scripting.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/read_input.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/remove_builtin_commands.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/remove_settable.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/rich_tables.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/rich_theme.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/arg_printer.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/conditional.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/nested.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/quit.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/save_help_text.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/script.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/scripts/script.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/tmux_launch.sh +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/tmux_split.sh +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/transcript_example.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/transcripts/exampleSession.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/transcripts/pirate.transcript +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/transcripts/quit.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/transcripts/transcript_regex.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/examples/unicode_commands.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/mkdocs.yml +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/package.json +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/ruff.toml +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/scripts/validate_tag.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/setup.cfg +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/.cmd2rc +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/__init__.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/conftest.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/echo.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/environment.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/help.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/py_locals.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/pyscript_dir.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/raises_exception.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/recursive.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/self_in_py.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/stdout_capture.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/pyscript/stop.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/relative_multiple.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/script.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/script.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/binary.bin +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/empty.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/help.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/nested.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/one_down.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/postcmds.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/precmds.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/scripts/utf8.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_argparse.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_argparse_completer.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_argparse_custom.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_argparse_subcommands.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_async_alert.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_categories.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_commandset.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_completion.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_future_annotations.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_history.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_parsing.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_plugin.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_run_pyscript.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_string_utils.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_terminal_utils.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_transcript.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_utils.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/test_utils_defining_class.py +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/bol_eol.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/characterclass.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/dotstar.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/extension_notation.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/failure.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/from_cmdloop.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/multiline_no_regex.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/multiline_regex.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/no_output.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/no_output_last.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/singleslash.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/slashes_escaped.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/slashslash.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/spaces.txt +0 -0
- {cmd2-3.3.0 → cmd2-3.5.0}/tests/transcripts/word_boundaries.txt +0 -0
|
@@ -1,4 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
## 3.5.0 (April 13, 2026)
|
|
2
|
+
|
|
3
|
+
- Bug Fixes
|
|
4
|
+
- Fixed issue where Rich stripped colors from text in test environments where TERM=dumb.
|
|
5
|
+
|
|
6
|
+
## 3.4.0 (March 3, 2026)
|
|
7
|
+
|
|
8
|
+
- Enhancements
|
|
9
|
+
- Moved cmd2-specific printing logic from `Cmd.print_to()` into `Cmd2BaseConsole.print()` and
|
|
10
|
+
`Cmd2BaseConsole.log()`. This removes need to pass a console object to `Cmd.print_to()`.
|
|
11
|
+
- Addressed a bug in `rich.console.Console` where complex renderables (like `Table` and `Rule`)
|
|
12
|
+
may not receive formatting settings passed to `console.print()` and `console.log()`.
|
|
13
|
+
|
|
14
|
+
- Breaking Changes
|
|
15
|
+
- Renamed the `destination` parameter of `Cmd.print_to()` back to `file` since you can no longer
|
|
16
|
+
pass in a console.
|
|
17
|
+
|
|
18
|
+
## 3.3.0 (March 1, 2026)
|
|
2
19
|
|
|
3
20
|
- Enhancements
|
|
4
21
|
- Added ability to pass a console object to `Cmd.print_to()`. This provides support for things
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmd2
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
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
|
|
@@ -26,8 +26,8 @@ Requires-Dist: backports.strenum; python_version == "3.10"
|
|
|
26
26
|
Requires-Dist: gnureadline>=8; platform_system == "Darwin"
|
|
27
27
|
Requires-Dist: pyperclip>=1.8.2
|
|
28
28
|
Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
|
|
29
|
-
Requires-Dist: rich>=
|
|
30
|
-
Requires-Dist: rich-argparse>=1.7.
|
|
29
|
+
Requires-Dist: rich>=15.0.0
|
|
30
|
+
Requires-Dist: rich-argparse>=1.7.2
|
|
31
31
|
Requires-Dist: typing-extensions; python_version == "3.10"
|
|
32
32
|
Dynamic: license-file
|
|
33
33
|
|
|
@@ -368,7 +368,7 @@ class ArgparseCompleter:
|
|
|
368
368
|
action = remaining_positionals.popleft()
|
|
369
369
|
|
|
370
370
|
# Are we at a subcommand? If so, forward to the matching completer
|
|
371
|
-
if action == self._subcommand_action:
|
|
371
|
+
if self._subcommand_action is not None and action == self._subcommand_action:
|
|
372
372
|
if token in self._subcommand_action.choices:
|
|
373
373
|
# Merge self._parent_tokens and consumed_arg_values
|
|
374
374
|
parent_tokens = {**self._parent_tokens, **consumed_arg_values}
|
|
@@ -1361,10 +1361,10 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
1361
1361
|
|
|
1362
1362
|
self.print_usage(sys.stderr)
|
|
1363
1363
|
|
|
1364
|
-
#
|
|
1364
|
+
# Use console to add style since it will respect ALLOW_STYLE's value
|
|
1365
1365
|
console = self._get_formatter().console
|
|
1366
1366
|
with console.capture() as capture:
|
|
1367
|
-
console.print(formatted_message, style=Cmd2Style.ERROR
|
|
1367
|
+
console.print(formatted_message, style=Cmd2Style.ERROR)
|
|
1368
1368
|
formatted_message = f"{capture.get()}"
|
|
1369
1369
|
|
|
1370
1370
|
self.exit(2, f'{formatted_message}\n')
|
|
@@ -66,7 +66,6 @@ from typing import (
|
|
|
66
66
|
|
|
67
67
|
import rich.box
|
|
68
68
|
from rich.console import (
|
|
69
|
-
Console,
|
|
70
69
|
Group,
|
|
71
70
|
RenderableType,
|
|
72
71
|
)
|
|
@@ -1252,66 +1251,30 @@ class Cmd:
|
|
|
1252
1251
|
|
|
1253
1252
|
def print_to(
|
|
1254
1253
|
self,
|
|
1255
|
-
|
|
1254
|
+
file: IO[str],
|
|
1256
1255
|
*objects: Any,
|
|
1257
1256
|
sep: str = " ",
|
|
1258
1257
|
end: str = "\n",
|
|
1259
1258
|
style: StyleType | None = None,
|
|
1260
|
-
soft_wrap: bool
|
|
1261
|
-
emoji: bool
|
|
1262
|
-
markup: bool
|
|
1263
|
-
highlight: bool
|
|
1259
|
+
soft_wrap: bool = True,
|
|
1260
|
+
emoji: bool = False,
|
|
1261
|
+
markup: bool = False,
|
|
1262
|
+
highlight: bool = False,
|
|
1264
1263
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1265
1264
|
**kwargs: Any, # noqa: ARG002
|
|
1266
1265
|
) -> None:
|
|
1267
|
-
"""Print objects to a given
|
|
1268
|
-
|
|
1269
|
-
If ``destination`` is a file-like object, it is wrapped in a ``Cmd2GeneralConsole``
|
|
1270
|
-
which is configured for general-purpose printing. By default, it enables soft wrap and
|
|
1271
|
-
disables Rich's automatic detection for markup, emoji, and highlighting. These defaults
|
|
1272
|
-
can be overridden by passing explicit keyword arguments.
|
|
1273
|
-
|
|
1274
|
-
If ``destination`` is a ``Cmd2BaseConsole``, the console's default settings for
|
|
1275
|
-
soft wrap, markup, emoji, and highlighting are used unless overridden by passing
|
|
1276
|
-
explicit keyword arguments.
|
|
1277
|
-
|
|
1278
|
-
See the Rich documentation for more details on emoji codes, markup tags, and highlighting.
|
|
1279
|
-
|
|
1280
|
-
**Why use this method instead of console.print()?**
|
|
1281
|
-
|
|
1282
|
-
This method calls ``cmd2.rich_utils.prepare_objects_for_rendering()`` on the objects
|
|
1283
|
-
being printed. This ensures that strings containing ANSI style sequences are converted
|
|
1284
|
-
to Rich Text objects, so that Rich can correctly calculate their display width when
|
|
1285
|
-
printing.
|
|
1286
|
-
|
|
1287
|
-
Example:
|
|
1288
|
-
```py
|
|
1289
|
-
with console.capture() as capture:
|
|
1290
|
-
self.print_to(console, some_ansi_styled_string)
|
|
1291
|
-
```
|
|
1292
|
-
|
|
1293
|
-
!!! note
|
|
1294
|
-
|
|
1295
|
-
To ensure consistent behavior, this method requires a file-like object or
|
|
1296
|
-
an instance of ``Cmd2BaseConsole``.
|
|
1297
|
-
Consoles not derived from ``Cmd2BaseConsole`` are disallowed because:
|
|
1266
|
+
"""Print objects to a given file stream.
|
|
1298
1267
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
``Cmd2BaseConsole`` instead raises a catchable ``BrokenPipeError``,
|
|
1303
|
-
ensuring the CLI application remains alive if a pipe is closed.
|
|
1268
|
+
This method is configured for general-purpose printing. By default, it enables
|
|
1269
|
+
soft wrap and disables Rich's automatic detection for markup, emoji, and highlighting.
|
|
1270
|
+
These defaults can be overridden by passing explicit keyword arguments.
|
|
1304
1271
|
|
|
1305
|
-
:param
|
|
1306
|
-
wrapped in a ``Cmd2GeneralConsole`` to ensure they respect
|
|
1307
|
-
cmd2 global settings; otherwise, this must be an
|
|
1308
|
-
instance of ``Cmd2BaseConsole``.
|
|
1272
|
+
:param file: file stream being written to
|
|
1309
1273
|
:param objects: objects to print
|
|
1310
1274
|
:param sep: string to write between printed text. Defaults to " ".
|
|
1311
1275
|
:param end: string to write at end of printed text. Defaults to a newline.
|
|
1312
1276
|
:param style: optional style to apply to output
|
|
1313
|
-
:param soft_wrap: Enable soft wrap mode. Defaults to
|
|
1314
|
-
If None, the destination console's default behavior is used.
|
|
1277
|
+
:param soft_wrap: Enable soft wrap mode. Defaults to True.
|
|
1315
1278
|
If True, text that doesn't fit will run on to the following line,
|
|
1316
1279
|
just like with print(). This is useful for raw text and logs.
|
|
1317
1280
|
If False, Rich wraps text to fit the terminal width.
|
|
@@ -1320,44 +1283,23 @@ class Cmd:
|
|
|
1320
1283
|
For example, when soft_wrap is True Panels truncate text
|
|
1321
1284
|
which is wider than the terminal.
|
|
1322
1285
|
:param emoji: If True, Rich will replace emoji codes (e.g., :smiley:) with their
|
|
1323
|
-
corresponding Unicode characters. Defaults to
|
|
1324
|
-
If None, the destination console's default behavior is used.
|
|
1286
|
+
corresponding Unicode characters. Defaults to False.
|
|
1325
1287
|
:param markup: If True, Rich will interpret strings with tags (e.g., [bold]hello[/bold])
|
|
1326
|
-
as styled output. Defaults to
|
|
1327
|
-
If None, the destination console's default behavior is used.
|
|
1288
|
+
as styled output. Defaults to False.
|
|
1328
1289
|
:param highlight: If True, Rich will automatically apply highlighting to elements within
|
|
1329
1290
|
strings, such as common Python data types like numbers, booleans, or None.
|
|
1330
1291
|
This is particularly useful when pretty printing objects like lists and
|
|
1331
|
-
dictionaries to display them in color. Defaults to
|
|
1332
|
-
If None, the destination console's default behavior is used.
|
|
1292
|
+
dictionaries to display them in color. Defaults to False.
|
|
1333
1293
|
:param rich_print_kwargs: optional additional keyword arguments to pass to Rich's Console.print().
|
|
1334
1294
|
:param kwargs: Arbitrary keyword arguments. This allows subclasses to extend the signature of this
|
|
1335
1295
|
method and still call `super()` without encountering unexpected keyword argument errors.
|
|
1336
1296
|
These arguments are not passed to Rich's Console.print().
|
|
1337
|
-
:raises TypeError: If ``destination`` is a non-cmd2 ``Console`` instance that
|
|
1338
|
-
does not derive from ``Cmd2BaseConsole``.
|
|
1339
1297
|
|
|
1298
|
+
See the Rich documentation for more details on emoji codes, markup tags, and highlighting.
|
|
1340
1299
|
"""
|
|
1341
|
-
if isinstance(destination, Console):
|
|
1342
|
-
if not isinstance(destination, Cmd2BaseConsole):
|
|
1343
|
-
# Explicitly reject non-cmd2 consoles to ensure safe behavior
|
|
1344
|
-
raise TypeError(
|
|
1345
|
-
f"destination must be a 'Cmd2BaseConsole' or a file-like object, "
|
|
1346
|
-
f"not a non-cmd2 '{type(destination).__name__}'. "
|
|
1347
|
-
"Consoles not derived from 'Cmd2BaseConsole' bypass cmd2's "
|
|
1348
|
-
"'ALLOW_STYLE' logic, 'APP_THEME' settings, and trigger 'SystemExit' "
|
|
1349
|
-
"on broken pipes."
|
|
1350
|
-
)
|
|
1351
|
-
console = destination
|
|
1352
|
-
else:
|
|
1353
|
-
# It's a file-like object (e.g., sys.stdout, StringIO)
|
|
1354
|
-
console = Cmd2GeneralConsole(file=destination)
|
|
1355
|
-
|
|
1356
|
-
prepared_objects = ru.prepare_objects_for_rendering(*objects)
|
|
1357
|
-
|
|
1358
1300
|
try:
|
|
1359
|
-
|
|
1360
|
-
*
|
|
1301
|
+
Cmd2BaseConsole(file=file).print(
|
|
1302
|
+
*objects,
|
|
1361
1303
|
sep=sep,
|
|
1362
1304
|
end=end,
|
|
1363
1305
|
style=style,
|
|
@@ -1373,7 +1315,7 @@ class Cmd:
|
|
|
1373
1315
|
# writing. If you would like your application to print a
|
|
1374
1316
|
# warning message, then set the broken_pipe_warning attribute
|
|
1375
1317
|
# to the message you want printed.
|
|
1376
|
-
if self.broken_pipe_warning and
|
|
1318
|
+
if self.broken_pipe_warning and file != sys.stderr:
|
|
1377
1319
|
Cmd2GeneralConsole(file=sys.stderr).print(self.broken_pipe_warning)
|
|
1378
1320
|
|
|
1379
1321
|
def poutput(
|
|
@@ -1382,10 +1324,10 @@ class Cmd:
|
|
|
1382
1324
|
sep: str = " ",
|
|
1383
1325
|
end: str = "\n",
|
|
1384
1326
|
style: StyleType | None = None,
|
|
1385
|
-
soft_wrap: bool
|
|
1386
|
-
emoji: bool
|
|
1387
|
-
markup: bool
|
|
1388
|
-
highlight: bool
|
|
1327
|
+
soft_wrap: bool = True,
|
|
1328
|
+
emoji: bool = False,
|
|
1329
|
+
markup: bool = False,
|
|
1330
|
+
highlight: bool = False,
|
|
1389
1331
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1390
1332
|
**kwargs: Any, # noqa: ARG002
|
|
1391
1333
|
) -> None:
|
|
@@ -1412,10 +1354,10 @@ class Cmd:
|
|
|
1412
1354
|
sep: str = " ",
|
|
1413
1355
|
end: str = "\n",
|
|
1414
1356
|
style: StyleType | None = Cmd2Style.ERROR,
|
|
1415
|
-
soft_wrap: bool
|
|
1416
|
-
emoji: bool
|
|
1417
|
-
markup: bool
|
|
1418
|
-
highlight: bool
|
|
1357
|
+
soft_wrap: bool = True,
|
|
1358
|
+
emoji: bool = False,
|
|
1359
|
+
markup: bool = False,
|
|
1360
|
+
highlight: bool = False,
|
|
1419
1361
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1420
1362
|
**kwargs: Any, # noqa: ARG002
|
|
1421
1363
|
) -> None:
|
|
@@ -1443,10 +1385,10 @@ class Cmd:
|
|
|
1443
1385
|
*objects: Any,
|
|
1444
1386
|
sep: str = " ",
|
|
1445
1387
|
end: str = "\n",
|
|
1446
|
-
soft_wrap: bool
|
|
1447
|
-
emoji: bool
|
|
1448
|
-
markup: bool
|
|
1449
|
-
highlight: bool
|
|
1388
|
+
soft_wrap: bool = True,
|
|
1389
|
+
emoji: bool = False,
|
|
1390
|
+
markup: bool = False,
|
|
1391
|
+
highlight: bool = False,
|
|
1450
1392
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1451
1393
|
**kwargs: Any, # noqa: ARG002
|
|
1452
1394
|
) -> None:
|
|
@@ -1471,10 +1413,10 @@ class Cmd:
|
|
|
1471
1413
|
*objects: Any,
|
|
1472
1414
|
sep: str = " ",
|
|
1473
1415
|
end: str = "\n",
|
|
1474
|
-
soft_wrap: bool
|
|
1475
|
-
emoji: bool
|
|
1476
|
-
markup: bool
|
|
1477
|
-
highlight: bool
|
|
1416
|
+
soft_wrap: bool = True,
|
|
1417
|
+
emoji: bool = False,
|
|
1418
|
+
markup: bool = False,
|
|
1419
|
+
highlight: bool = False,
|
|
1478
1420
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1479
1421
|
**kwargs: Any, # noqa: ARG002
|
|
1480
1422
|
) -> None:
|
|
@@ -1554,10 +1496,10 @@ class Cmd:
|
|
|
1554
1496
|
sep: str = " ",
|
|
1555
1497
|
end: str = "\n",
|
|
1556
1498
|
style: StyleType | None = None,
|
|
1557
|
-
soft_wrap: bool
|
|
1558
|
-
emoji: bool
|
|
1559
|
-
markup: bool
|
|
1560
|
-
highlight: bool
|
|
1499
|
+
soft_wrap: bool = True,
|
|
1500
|
+
emoji: bool = False,
|
|
1501
|
+
markup: bool = False,
|
|
1502
|
+
highlight: bool = False,
|
|
1561
1503
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1562
1504
|
**kwargs: Any, # noqa: ARG002
|
|
1563
1505
|
) -> None:
|
|
@@ -1602,9 +1544,9 @@ class Cmd:
|
|
|
1602
1544
|
style: StyleType | None = None,
|
|
1603
1545
|
chop: bool = False,
|
|
1604
1546
|
soft_wrap: bool = True,
|
|
1605
|
-
emoji: bool
|
|
1606
|
-
markup: bool
|
|
1607
|
-
highlight: bool
|
|
1547
|
+
emoji: bool = False,
|
|
1548
|
+
markup: bool = False,
|
|
1549
|
+
highlight: bool = False,
|
|
1608
1550
|
rich_print_kwargs: RichPrintKwargs | None = None,
|
|
1609
1551
|
**kwargs: Any, # noqa: ARG002
|
|
1610
1552
|
) -> None:
|
|
@@ -1646,10 +1588,9 @@ class Cmd:
|
|
|
1646
1588
|
soft_wrap = True
|
|
1647
1589
|
|
|
1648
1590
|
# Generate the bytes to send to the pager
|
|
1649
|
-
console =
|
|
1591
|
+
console = Cmd2BaseConsole(file=self.stdout)
|
|
1650
1592
|
with console.capture() as capture:
|
|
1651
|
-
|
|
1652
|
-
console,
|
|
1593
|
+
console.print(
|
|
1653
1594
|
*objects,
|
|
1654
1595
|
sep=sep,
|
|
1655
1596
|
end=end,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Provides common utilities to support Rich in cmd2-based applications."""
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
+
import threading
|
|
4
5
|
from collections.abc import Mapping
|
|
5
6
|
from enum import Enum
|
|
6
7
|
from typing import (
|
|
@@ -135,8 +136,9 @@ class Cmd2BaseConsole(Console):
|
|
|
135
136
|
:param kwargs: keyword arguments passed to the parent Console class.
|
|
136
137
|
:raises TypeError: if disallowed keyword argument is passed in.
|
|
137
138
|
"""
|
|
138
|
-
#
|
|
139
|
-
|
|
139
|
+
# These settings are controlled by the ALLOW_STYLE setting and cannot be overridden.
|
|
140
|
+
if "color_system" in kwargs:
|
|
141
|
+
raise TypeError("Passing 'color_system' is not allowed. Its behavior is controlled by the 'ALLOW_STYLE' setting.")
|
|
140
142
|
if "force_terminal" in kwargs:
|
|
141
143
|
raise TypeError(
|
|
142
144
|
"Passing 'force_terminal' is not allowed. Its behavior is controlled by the 'ALLOW_STYLE' setting."
|
|
@@ -156,29 +158,175 @@ class Cmd2BaseConsole(Console):
|
|
|
156
158
|
|
|
157
159
|
force_terminal: bool | None = None
|
|
158
160
|
force_interactive: bool | None = None
|
|
161
|
+
allow_style = False
|
|
159
162
|
|
|
160
163
|
if ALLOW_STYLE == AllowStyle.ALWAYS:
|
|
161
164
|
force_terminal = True
|
|
165
|
+
allow_style = True
|
|
162
166
|
|
|
163
167
|
# Turn off interactive mode if dest is not actually a terminal which supports it
|
|
164
168
|
tmp_console = Console(file=file)
|
|
165
169
|
force_interactive = tmp_console.is_interactive
|
|
170
|
+
elif ALLOW_STYLE == AllowStyle.TERMINAL:
|
|
171
|
+
tmp_console = Console(file=file)
|
|
172
|
+
allow_style = tmp_console.is_terminal
|
|
166
173
|
elif ALLOW_STYLE == AllowStyle.NEVER:
|
|
167
174
|
force_terminal = False
|
|
168
175
|
|
|
169
176
|
super().__init__(
|
|
170
177
|
file=file,
|
|
178
|
+
color_system="truecolor" if allow_style else None,
|
|
171
179
|
force_terminal=force_terminal,
|
|
172
180
|
force_interactive=force_interactive,
|
|
173
181
|
theme=APP_THEME,
|
|
174
182
|
**kwargs,
|
|
175
183
|
)
|
|
184
|
+
self._thread_local = threading.local()
|
|
176
185
|
|
|
177
186
|
def on_broken_pipe(self) -> None:
|
|
178
187
|
"""Override which raises BrokenPipeError instead of SystemExit."""
|
|
179
188
|
self.quiet = True
|
|
180
189
|
raise BrokenPipeError
|
|
181
190
|
|
|
191
|
+
def render_str(
|
|
192
|
+
self,
|
|
193
|
+
text: str,
|
|
194
|
+
highlight: bool | None = None,
|
|
195
|
+
markup: bool | None = None,
|
|
196
|
+
emoji: bool | None = None,
|
|
197
|
+
**kwargs: Any,
|
|
198
|
+
) -> Text:
|
|
199
|
+
"""Override to ensure formatting overrides passed to print() and log() are respected."""
|
|
200
|
+
if emoji is None:
|
|
201
|
+
emoji = getattr(self._thread_local, "emoji", None)
|
|
202
|
+
if markup is None:
|
|
203
|
+
markup = getattr(self._thread_local, "markup", None)
|
|
204
|
+
if highlight is None:
|
|
205
|
+
highlight = getattr(self._thread_local, "highlight", None)
|
|
206
|
+
|
|
207
|
+
return super().render_str(text, highlight=highlight, markup=markup, emoji=emoji, **kwargs)
|
|
208
|
+
|
|
209
|
+
def print(
|
|
210
|
+
self,
|
|
211
|
+
*objects: Any,
|
|
212
|
+
sep: str = " ",
|
|
213
|
+
end: str = "\n",
|
|
214
|
+
style: StyleType | None = None,
|
|
215
|
+
justify: JustifyMethod | None = None,
|
|
216
|
+
overflow: OverflowMethod | None = None,
|
|
217
|
+
no_wrap: bool | None = None,
|
|
218
|
+
emoji: bool | None = None,
|
|
219
|
+
markup: bool | None = None,
|
|
220
|
+
highlight: bool | None = None,
|
|
221
|
+
width: int | None = None,
|
|
222
|
+
height: int | None = None,
|
|
223
|
+
crop: bool = True,
|
|
224
|
+
soft_wrap: bool | None = None,
|
|
225
|
+
new_line_start: bool = False,
|
|
226
|
+
) -> None:
|
|
227
|
+
"""Override to support ANSI sequences and address a bug in Rich.
|
|
228
|
+
|
|
229
|
+
This method calls [cmd2.rich_utils.prepare_objects_for_rendering][] on the
|
|
230
|
+
objects being printed. This ensures that strings containing ANSI style
|
|
231
|
+
sequences are converted to Rich Text objects, so that Rich can correctly
|
|
232
|
+
calculate their display width.
|
|
233
|
+
|
|
234
|
+
Additionally, it works around a bug in Rich where complex renderables
|
|
235
|
+
(like Table and Rule) may not receive formatting settings passed to print().
|
|
236
|
+
By temporarily injecting these settings into thread-local storage, we ensure
|
|
237
|
+
that all internal rendering calls within the print() operation respect the
|
|
238
|
+
requested overrides.
|
|
239
|
+
|
|
240
|
+
There is an issue on Rich to fix the latter:
|
|
241
|
+
https://github.com/Textualize/rich/issues/4028
|
|
242
|
+
"""
|
|
243
|
+
prepared_objects = prepare_objects_for_rendering(*objects)
|
|
244
|
+
|
|
245
|
+
# Inject overrides into thread-local storage
|
|
246
|
+
self._thread_local.emoji = emoji
|
|
247
|
+
self._thread_local.markup = markup
|
|
248
|
+
self._thread_local.highlight = highlight
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
super().print(
|
|
252
|
+
*prepared_objects,
|
|
253
|
+
sep=sep,
|
|
254
|
+
end=end,
|
|
255
|
+
style=style,
|
|
256
|
+
justify=justify,
|
|
257
|
+
overflow=overflow,
|
|
258
|
+
no_wrap=no_wrap,
|
|
259
|
+
emoji=emoji,
|
|
260
|
+
markup=markup,
|
|
261
|
+
highlight=highlight,
|
|
262
|
+
width=width,
|
|
263
|
+
height=height,
|
|
264
|
+
crop=crop,
|
|
265
|
+
soft_wrap=soft_wrap,
|
|
266
|
+
new_line_start=new_line_start,
|
|
267
|
+
)
|
|
268
|
+
finally:
|
|
269
|
+
# Clear overrides from thread-local storage
|
|
270
|
+
self._thread_local.emoji = None
|
|
271
|
+
self._thread_local.markup = None
|
|
272
|
+
self._thread_local.highlight = None
|
|
273
|
+
|
|
274
|
+
def log(
|
|
275
|
+
self,
|
|
276
|
+
*objects: Any,
|
|
277
|
+
sep: str = " ",
|
|
278
|
+
end: str = "\n",
|
|
279
|
+
style: StyleType | None = None,
|
|
280
|
+
justify: JustifyMethod | None = None,
|
|
281
|
+
emoji: bool | None = None,
|
|
282
|
+
markup: bool | None = None,
|
|
283
|
+
highlight: bool | None = None,
|
|
284
|
+
log_locals: bool = False,
|
|
285
|
+
_stack_offset: int = 1,
|
|
286
|
+
) -> None:
|
|
287
|
+
"""Override to support ANSI sequences and address a bug in Rich.
|
|
288
|
+
|
|
289
|
+
This method calls [cmd2.rich_utils.prepare_objects_for_rendering][] on the
|
|
290
|
+
objects being logged. This ensures that strings containing ANSI style
|
|
291
|
+
sequences are converted to Rich Text objects, so that Rich can correctly
|
|
292
|
+
calculate their display width.
|
|
293
|
+
|
|
294
|
+
Additionally, it works around a bug in Rich where complex renderables
|
|
295
|
+
(like Table and Rule) may not receive formatting settings passed to log().
|
|
296
|
+
By temporarily injecting these settings into thread-local storage, we ensure
|
|
297
|
+
that all internal rendering calls within the log() operation respect the
|
|
298
|
+
requested overrides.
|
|
299
|
+
|
|
300
|
+
There is an issue on Rich to fix the latter:
|
|
301
|
+
https://github.com/Textualize/rich/issues/4028
|
|
302
|
+
"""
|
|
303
|
+
prepared_objects = prepare_objects_for_rendering(*objects)
|
|
304
|
+
|
|
305
|
+
# Inject overrides into thread-local storage
|
|
306
|
+
self._thread_local.emoji = emoji
|
|
307
|
+
self._thread_local.markup = markup
|
|
308
|
+
self._thread_local.highlight = highlight
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
# Increment _stack_offset because we added this wrapper frame
|
|
312
|
+
super().log(
|
|
313
|
+
*prepared_objects,
|
|
314
|
+
sep=sep,
|
|
315
|
+
end=end,
|
|
316
|
+
style=style,
|
|
317
|
+
justify=justify,
|
|
318
|
+
emoji=emoji,
|
|
319
|
+
markup=markup,
|
|
320
|
+
highlight=highlight,
|
|
321
|
+
log_locals=log_locals,
|
|
322
|
+
_stack_offset=_stack_offset + 1,
|
|
323
|
+
)
|
|
324
|
+
finally:
|
|
325
|
+
# Clear overrides from thread-local storage
|
|
326
|
+
self._thread_local.emoji = None
|
|
327
|
+
self._thread_local.markup = None
|
|
328
|
+
self._thread_local.highlight = None
|
|
329
|
+
|
|
182
330
|
|
|
183
331
|
class Cmd2GeneralConsole(Cmd2BaseConsole):
|
|
184
332
|
"""Rich console for general-purpose printing.
|
|
@@ -271,11 +419,9 @@ def rich_text_to_string(text: Text) -> str:
|
|
|
271
419
|
"""
|
|
272
420
|
console = Console(
|
|
273
421
|
force_terminal=True,
|
|
422
|
+
color_system="truecolor",
|
|
274
423
|
soft_wrap=True,
|
|
275
424
|
no_color=False,
|
|
276
|
-
markup=False,
|
|
277
|
-
emoji=False,
|
|
278
|
-
highlight=False,
|
|
279
425
|
theme=APP_THEME,
|
|
280
426
|
)
|
|
281
427
|
with console.capture() as capture:
|
|
@@ -339,64 +485,3 @@ def prepare_objects_for_rendering(*objects: Any) -> tuple[Any, ...]:
|
|
|
339
485
|
object_list[i] = Text.from_ansi(renderable_as_str)
|
|
340
486
|
|
|
341
487
|
return tuple(object_list)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
###################################################################################
|
|
345
|
-
# Rich Library Monkey Patches
|
|
346
|
-
#
|
|
347
|
-
# These patches fix specific bugs in the Rich library. They are conditional and
|
|
348
|
-
# will only be applied if the bug is detected. When the bugs are fixed in a
|
|
349
|
-
# future Rich release, these patches and their corresponding tests should be
|
|
350
|
-
# removed.
|
|
351
|
-
###################################################################################
|
|
352
|
-
|
|
353
|
-
###################################################################################
|
|
354
|
-
# Text.from_ansi() monkey patch
|
|
355
|
-
###################################################################################
|
|
356
|
-
|
|
357
|
-
# Save original Text.from_ansi() so we can call it in our wrapper
|
|
358
|
-
_orig_text_from_ansi = Text.from_ansi
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
@classmethod # type: ignore[misc]
|
|
362
|
-
def _from_ansi_wrapper(cls: type[Text], text: str, *args: Any, **kwargs: Any) -> Text: # noqa: ARG001
|
|
363
|
-
r"""Wrap Text.from_ansi() to fix its trailing newline bug.
|
|
364
|
-
|
|
365
|
-
This wrapper handles an issue where Text.from_ansi() removes the
|
|
366
|
-
trailing line break from a string (e.g. "Hello\n" becomes "Hello").
|
|
367
|
-
|
|
368
|
-
There is currently a pull request on Rich to fix this.
|
|
369
|
-
https://github.com/Textualize/rich/pull/3793
|
|
370
|
-
"""
|
|
371
|
-
result = _orig_text_from_ansi(text, *args, **kwargs)
|
|
372
|
-
|
|
373
|
-
# If the original string ends with a recognized line break character,
|
|
374
|
-
# then restore the missing newline. We use "\n" because Text.from_ansi()
|
|
375
|
-
# converts all line breaks into newlines.
|
|
376
|
-
# Source: https://docs.python.org/3/library/stdtypes.html#str.splitlines
|
|
377
|
-
line_break_chars = {
|
|
378
|
-
"\n", # Line Feed
|
|
379
|
-
"\r", # Carriage Return
|
|
380
|
-
"\v", # Vertical Tab
|
|
381
|
-
"\f", # Form Feed
|
|
382
|
-
"\x1c", # File Separator
|
|
383
|
-
"\x1d", # Group Separator
|
|
384
|
-
"\x1e", # Record Separator
|
|
385
|
-
"\x85", # Next Line (NEL)
|
|
386
|
-
"\u2028", # Line Separator
|
|
387
|
-
"\u2029", # Paragraph Separator
|
|
388
|
-
}
|
|
389
|
-
if text and text[-1] in line_break_chars:
|
|
390
|
-
result.append("\n")
|
|
391
|
-
|
|
392
|
-
return result
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
def _from_ansi_has_newline_bug() -> bool:
|
|
396
|
-
"""Check if Test.from_ansi() strips the trailing line break from a string."""
|
|
397
|
-
return Text.from_ansi("\n") == Text.from_ansi("")
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
# Only apply the monkey patch if the bug is present
|
|
401
|
-
if _from_ansi_has_newline_bug():
|
|
402
|
-
Text.from_ansi = _from_ansi_wrapper # type: ignore[assignment]
|
|
@@ -75,7 +75,7 @@ class Settable:
|
|
|
75
75
|
settable_object: object,
|
|
76
76
|
*,
|
|
77
77
|
settable_attrib_name: str | None = None,
|
|
78
|
-
onchange_cb: Callable[[str,
|
|
78
|
+
onchange_cb: Callable[[str, Any, Any], Any] | None = None,
|
|
79
79
|
choices: Iterable[Any] | None = None,
|
|
80
80
|
choices_provider: ChoicesProviderFunc | None = None,
|
|
81
81
|
completer: CompleterFunc | None = None,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmd2
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
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
|
|
@@ -26,8 +26,8 @@ Requires-Dist: backports.strenum; python_version == "3.10"
|
|
|
26
26
|
Requires-Dist: gnureadline>=8; platform_system == "Darwin"
|
|
27
27
|
Requires-Dist: pyperclip>=1.8.2
|
|
28
28
|
Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
|
|
29
|
-
Requires-Dist: rich>=
|
|
30
|
-
Requires-Dist: rich-argparse>=1.7.
|
|
29
|
+
Requires-Dist: rich>=15.0.0
|
|
30
|
+
Requires-Dist: rich-argparse>=1.7.2
|
|
31
31
|
Requires-Dist: typing-extensions; python_version == "3.10"
|
|
32
32
|
Dynamic: license-file
|
|
33
33
|
|
|
@@ -33,8 +33,8 @@ dependencies = [
|
|
|
33
33
|
"gnureadline>=8; platform_system == 'Darwin'",
|
|
34
34
|
"pyperclip>=1.8.2",
|
|
35
35
|
"pyreadline3>=3.4; platform_system == 'Windows'",
|
|
36
|
-
"rich>=
|
|
37
|
-
"rich-argparse>=1.7.
|
|
36
|
+
"rich>=15.0.0",
|
|
37
|
+
"rich-argparse>=1.7.2",
|
|
38
38
|
"typing-extensions; python_version == '3.10'",
|
|
39
39
|
]
|
|
40
40
|
|