cmd2 4.0.0b1__tar.gz → 4.0.0b2__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.0.0b1 → cmd2-4.0.0b2}/.pre-commit-config.yaml +16 -1
- cmd2-4.0.0b2/.typos.toml +5 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/CHANGELOG.md +14 -4
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/Makefile +4 -4
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/PKG-INFO +2 -2
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/README.md +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/__init__.py +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/argparse_completer.py +57 -36
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/argparse_custom.py +67 -52
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/cmd2.py +206 -79
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/completion.py +14 -12
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/decorators.py +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/pt_utils.py +9 -6
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/rich_utils.py +103 -101
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/string_utils.py +23 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2.egg-info/PKG-INFO +2 -2
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2.egg-info/SOURCES.txt +2 -2
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/doc_conventions.md +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/generating_output.md +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/misc.md +4 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/README.md +4 -4
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/argparse_completion.py +4 -4
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/command_sets.py +3 -3
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/custom_types.py +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/read_input.py +28 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/pyproject.toml +2 -2
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/ruff.toml +1 -1
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_argparse_completer.py +219 -85
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_argparse_custom.py +59 -12
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_cmd2.py +282 -12
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_commandset.py +3 -3
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_completion.py +4 -4
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_pt_utils.py +17 -10
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_rich_utils.py +37 -38
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_string_utils.py +26 -0
- cmd2-4.0.0b1/examples/cmd2_history.dat +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/.prettierignore +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/.prettierrc +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/GEMINI.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/LICENSE +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/MANIFEST.in +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/clipboard.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/colors.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/command_definition.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/constants.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/exceptions.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/history.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/parsing.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/plugin.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/py.typed +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/py_bridge.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/styles.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/types.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2/utils.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2.egg-info/dependency_links.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2.egg-info/requires.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2.egg-info/top_level.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/cmd2.png +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/codecov.yml +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/argparse_completer.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/argparse_custom.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/clipboard.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/cmd.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/colors.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/command_definition.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/completion.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/constants.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/decorators.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/exceptions.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/history.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/parsing.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/plugin.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/pt_utils.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/py_bridge.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/rich_utils.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/string_utils.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/styles.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/api/utils.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/examples/alternate_event_loops.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/examples/examples.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/examples/getting_started.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/examples/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/argument_processing.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/async_commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/builtin_commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/clipboard.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/completion.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/disable_commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/embedded_python_shells.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/help.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/history.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/hooks.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/initialization.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/modular_commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/multiline_commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/os.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/packaging.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/plugins.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/prompt.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/redirection.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/scripting.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/settings.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/shortcuts_aliases_macros.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/startup_commands.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/table_creation.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/features/theme.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/javascripts/readthedocs.js +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/migrating/incompatibilities.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/migrating/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/migrating/minimum.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/migrating/next_steps.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/migrating/why.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/mixins/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/mixins/mixin_template.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/overrides/main.html +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/overview/alternatives.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/overview/index.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/overview/installation.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/overview/integrating.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/overview/resources.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/stylesheets/cmd2.css +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/testing.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/docs/upgrades.md +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/.cmd2rc +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/argparse_example.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/async_call.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/async_commands.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/async_printing.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/basic_completion.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/cmd_as_argument.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/color.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/custom_parser.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/default_categories.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/dynamic_commands.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/environment.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/event_loops.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/exit_code.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/getting_started.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/hello_cmd2.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/help_categories.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/hooks.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/migrating.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/mixin.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/modular_commands/__init__.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/modular_commands/commandset_basic.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/modular_commands/commandset_complex.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/modular_commands/commandset_custominit.py +0 -0
- /cmd2-4.0.0b1/examples/modular_commands.py → /cmd2-4.0.0b2/examples/modular_commandsets.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/paged_output.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/persistent_history.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/pretty_print.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/python_scripting.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/remove_builtin_commands.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/remove_settable.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/rich_tables.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/rich_theme.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/arg_printer.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/conditional.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/nested.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/quit.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/save_help_text.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/script.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/scripts/script.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/tmux_launch.sh +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/tmux_split.sh +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/examples/unicode_commands.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/mkdocs.yml +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/package.json +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/scripts/validate_tag.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/setup.cfg +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/.cmd2rc +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/__init__.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/conftest.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/echo.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/environment.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/help.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/py_locals.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/pyscript_dir.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/raises_exception.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/recursive.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/self_in_py.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/stdout_capture.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/pyscript/stop.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/relative_multiple.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/script.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/script.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/binary.bin +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/empty.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/help.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/nested.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/one_down.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/postcmds.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/precmds.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/scripts/utf8.txt +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_argparse.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_argparse_subcommands.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_categories.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_dynamic_complete_style.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_future_annotations.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_history.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_parsing.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_plugin.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_py_completion.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_run_pyscript.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_utils.py +0 -0
- {cmd2-4.0.0b1 → cmd2-4.0.0b2}/tests/test_utils_defining_class.py +0 -0
|
@@ -3,13 +3,18 @@ repos:
|
|
|
3
3
|
rev: "v6.0.0"
|
|
4
4
|
hooks:
|
|
5
5
|
- id: check-case-conflict
|
|
6
|
+
- id: check-executables-have-shebangs
|
|
6
7
|
- id: check-merge-conflict
|
|
7
8
|
- id: check-toml
|
|
9
|
+
- id: check-yaml
|
|
10
|
+
- id: detect-private-key
|
|
8
11
|
- id: end-of-file-fixer
|
|
12
|
+
- id: fix-byte-order-marker
|
|
13
|
+
- id: mixed-line-ending
|
|
9
14
|
- id: trailing-whitespace
|
|
10
15
|
|
|
11
16
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
12
|
-
rev: "v0.15.
|
|
17
|
+
rev: "v0.15.6"
|
|
13
18
|
hooks:
|
|
14
19
|
- id: ruff-format
|
|
15
20
|
args: [--config=ruff.toml]
|
|
@@ -23,3 +28,13 @@ repos:
|
|
|
23
28
|
additional_dependencies:
|
|
24
29
|
- prettier@3.8.1
|
|
25
30
|
- prettier-plugin-toml@2.0.6
|
|
31
|
+
|
|
32
|
+
- repo: https://github.com/crate-ci/typos
|
|
33
|
+
rev: v1.44.0
|
|
34
|
+
hooks:
|
|
35
|
+
- id: typos
|
|
36
|
+
exclude: |
|
|
37
|
+
(?x)^(
|
|
38
|
+
ruff.toml|
|
|
39
|
+
tests/.*
|
|
40
|
+
)$
|
cmd2-4.0.0b2/.typos.toml
ADDED
|
@@ -37,13 +37,15 @@ prompt is displayed.
|
|
|
37
37
|
longer needed
|
|
38
38
|
- `completer` functions must now return a `cmd2.Completions` object instead of `list[str]`.
|
|
39
39
|
- `choices_provider` functions must now return a `cmd2.Choices` object instead of `list[str]`.
|
|
40
|
-
- An argparse argument's `descriptive_headers` field is now called `
|
|
41
|
-
- `CompletionItem.descriptive_data` is now called `CompletionItem.
|
|
40
|
+
- An argparse argument's `descriptive_headers` field is now called `table_columns`.
|
|
41
|
+
- `CompletionItem.descriptive_data` is now called `CompletionItem.table_data`.
|
|
42
|
+
- Removed `DEFAULT_DESCRIPTIVE_HEADERS`. This means you must define `table_columns` when using
|
|
43
|
+
`CompletionItem.table_data` data.
|
|
42
44
|
- `Cmd.default_sort_key` moved to `utils.DEFAULT_STR_SORT_KEY`.
|
|
43
45
|
- Moved completion state data, which previously resided in `Cmd`, into other classes.
|
|
44
46
|
- `Cmd.matches_sorted` -> `Completions.is_sorted` and `Choices.is_sorted`
|
|
45
|
-
- `Cmd.completion_hint` -> `Completions.
|
|
46
|
-
- `Cmd.formatted_completions` -> `Completions.
|
|
47
|
+
- `Cmd.completion_hint` -> `Completions.hint`
|
|
48
|
+
- `Cmd.formatted_completions` -> `Completions.table` (Now a Rich Table)
|
|
47
49
|
- `Cmd.allow_appended_space/allow_closing_quote` -> `Completions.allow_finalization`
|
|
48
50
|
- Removed `Cmd.matches_delimited` since it's no longer used.
|
|
49
51
|
- Removed `flag_based_complete` and `index_based_complete` functions since their functionality
|
|
@@ -61,6 +63,7 @@ prompt is displayed.
|
|
|
61
63
|
`add_alert()`. This new function is thread-safe and does not require you to acquire a mutex
|
|
62
64
|
before calling it like the previous functions did.
|
|
63
65
|
- Removed `Cmd.default_to_shell`.
|
|
66
|
+
- Removed `Cmd.ruler` since `cmd2` no longer uses it.
|
|
64
67
|
- Enhancements
|
|
65
68
|
- New `cmd2.Cmd` parameters
|
|
66
69
|
- **auto_suggest**: (boolean) if `True`, provide fish shell style auto-suggestions. These
|
|
@@ -75,9 +78,16 @@ prompt is displayed.
|
|
|
75
78
|
- **get_rprompt**: override to populate right prompt
|
|
76
79
|
- **pre_prompt**: hook method that is called before the prompt is displayed, but after
|
|
77
80
|
`prompt-toolkit` event loop has started
|
|
81
|
+
- **read_secret**: read secrets like passwords without displaying them to the terminal
|
|
78
82
|
- New settables:
|
|
79
83
|
- **max_column_completion_results**: (int) the maximum number of completion results to
|
|
80
84
|
display in a single column
|
|
85
|
+
- `cmd2.Cmd.select` has been revamped to use the
|
|
86
|
+
[choice](https://python-prompt-toolkit.readthedocs.io/en/3.0.52/pages/asking_for_a_choice.html)
|
|
87
|
+
function from `prompt-toolkit` when both **stdin** and **stdout** are TTYs
|
|
88
|
+
- Add support for Python 3.15 by fixing various bugs related to internal `argparse` changes
|
|
89
|
+
- Added `common_prefix` method to `cmd2.string_utils` module as a replacement for
|
|
90
|
+
`os.path.commonprefix` since that is now deprecated in Python 3.15
|
|
81
91
|
|
|
82
92
|
## 3.4.0 (March 3, 2026)
|
|
83
93
|
|
|
@@ -7,8 +7,8 @@ install: ## Install the virtual environment with dependencies
|
|
|
7
7
|
@echo "🚀 Creating uv Python virtual environment"
|
|
8
8
|
@uv python install 3.14
|
|
9
9
|
@uv sync --python=3.14
|
|
10
|
-
@echo "🚀 Installing Git
|
|
11
|
-
@uv run
|
|
10
|
+
@echo "🚀 Installing Git prek hooks locally"
|
|
11
|
+
@uv run prek install -f
|
|
12
12
|
@echo "🚀 Installing Prettier using npm"
|
|
13
13
|
@npm install -q --no-fund --include=dev
|
|
14
14
|
|
|
@@ -16,8 +16,8 @@ install: ## Install the virtual environment with dependencies
|
|
|
16
16
|
check: ## Run code quality tools.
|
|
17
17
|
@echo "🚀 Checking lock file consistency with 'pyproject.toml'"
|
|
18
18
|
@uv lock --locked
|
|
19
|
-
@echo "🚀 Linting code and documentation: Running
|
|
20
|
-
@uv run
|
|
19
|
+
@echo "🚀 Auto-formatting/Linting code and documentation: Running prek"
|
|
20
|
+
@uv run prek run -a
|
|
21
21
|
@echo "🚀 Static type checking: Running mypy"
|
|
22
22
|
@uv run mypy
|
|
23
23
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmd2
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.0b2
|
|
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
|
|
@@ -139,7 +139,7 @@ examples.
|
|
|
139
139
|
- [cmd2 example applications](https://github.com/python-cmd2/cmd2/tree/main/examples)
|
|
140
140
|
- Basic cmd2 examples to demonstrate how to use various features
|
|
141
141
|
- [Advanced Examples](https://github.com/jayrod/cmd2-example-apps)
|
|
142
|
-
- More complex examples that demonstrate more
|
|
142
|
+
- More complex examples that demonstrate more features about how to put together a complete
|
|
143
143
|
application
|
|
144
144
|
- [Cookiecutter](https://github.com/cookiecutter/cookiecutter) Templates from community
|
|
145
145
|
- Basic cookiecutter template for cmd2 application :
|
|
@@ -107,7 +107,7 @@ examples.
|
|
|
107
107
|
- [cmd2 example applications](https://github.com/python-cmd2/cmd2/tree/main/examples)
|
|
108
108
|
- Basic cmd2 examples to demonstrate how to use various features
|
|
109
109
|
- [Advanced Examples](https://github.com/jayrod/cmd2-example-apps)
|
|
110
|
-
- More complex examples that demonstrate more
|
|
110
|
+
- More complex examples that demonstrate more features about how to put together a complete
|
|
111
111
|
application
|
|
112
112
|
- [Cookiecutter](https://github.com/cookiecutter/cookiecutter) Templates from community
|
|
113
113
|
- Basic cookiecutter template for cmd2 application :
|
|
@@ -25,16 +25,12 @@ from typing import (
|
|
|
25
25
|
from rich.text import Text
|
|
26
26
|
|
|
27
27
|
from .constants import INFINITY
|
|
28
|
-
from .rich_utils import
|
|
28
|
+
from .rich_utils import Cmd2SimpleTable
|
|
29
29
|
|
|
30
30
|
if TYPE_CHECKING: # pragma: no cover
|
|
31
31
|
from .cmd2 import Cmd
|
|
32
32
|
|
|
33
|
-
from rich.
|
|
34
|
-
from rich.table import (
|
|
35
|
-
Column,
|
|
36
|
-
Table,
|
|
37
|
-
)
|
|
33
|
+
from rich.table import Column
|
|
38
34
|
|
|
39
35
|
from .argparse_custom import (
|
|
40
36
|
ChoicesCallable,
|
|
@@ -47,10 +43,6 @@ from .completion import (
|
|
|
47
43
|
all_display_numeric,
|
|
48
44
|
)
|
|
49
45
|
from .exceptions import CompletionError
|
|
50
|
-
from .styles import Cmd2Style
|
|
51
|
-
|
|
52
|
-
# If no table header is supplied, then this will be used instead
|
|
53
|
-
DEFAULT_TABLE_HEADER: Sequence[str | Column] = ['Description']
|
|
54
46
|
|
|
55
47
|
# Name of the choice/completer function argument that, if present, will be passed a dictionary of
|
|
56
48
|
# command line tokens up through the token being completed mapped to their argparse destination name.
|
|
@@ -500,11 +492,11 @@ class ArgparseCompleter:
|
|
|
500
492
|
|
|
501
493
|
# If we have results, then return them
|
|
502
494
|
if completions:
|
|
503
|
-
if not completions.
|
|
495
|
+
if not completions.hint:
|
|
504
496
|
# Add a hint even though there are results in case Cmd.always_show_hint is True.
|
|
505
497
|
completions = dataclasses.replace(
|
|
506
498
|
completions,
|
|
507
|
-
|
|
499
|
+
hint=_build_hint(self._parser, flag_arg_state.action),
|
|
508
500
|
)
|
|
509
501
|
|
|
510
502
|
return completions
|
|
@@ -528,11 +520,11 @@ class ArgparseCompleter:
|
|
|
528
520
|
|
|
529
521
|
# If we have results, then return them
|
|
530
522
|
if completions:
|
|
531
|
-
if not completions.
|
|
523
|
+
if not completions.hint:
|
|
532
524
|
# Add a hint even though there are results in case Cmd.always_show_hint is True.
|
|
533
525
|
completions = dataclasses.replace(
|
|
534
526
|
completions,
|
|
535
|
-
|
|
527
|
+
hint=_build_hint(self._parser, pos_arg_state.action),
|
|
536
528
|
)
|
|
537
529
|
return completions
|
|
538
530
|
|
|
@@ -592,15 +584,52 @@ class ArgparseCompleter:
|
|
|
592
584
|
|
|
593
585
|
return Completions(items)
|
|
594
586
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
if
|
|
600
|
-
|
|
587
|
+
@staticmethod
|
|
588
|
+
def _validate_table_data(arg_state: _ArgumentState, completions: Completions) -> None:
|
|
589
|
+
"""Verify the integrity of completion table data.
|
|
590
|
+
|
|
591
|
+
:raises ValueError: if there is an error with the data.
|
|
592
|
+
"""
|
|
593
|
+
table_columns = arg_state.action.get_table_columns() # type: ignore[attr-defined]
|
|
594
|
+
has_table_data = any(item.table_data for item in completions)
|
|
595
|
+
|
|
596
|
+
if table_columns is None:
|
|
597
|
+
if has_table_data:
|
|
598
|
+
raise ValueError(
|
|
599
|
+
f"Argument '{arg_state.action.dest}' has CompletionItems with table_data, "
|
|
600
|
+
f"but no table_columns were defined in add_argument()."
|
|
601
|
+
)
|
|
602
|
+
return
|
|
603
|
+
|
|
604
|
+
# If columns are defined, then every item must have data, and lengths must match
|
|
605
|
+
for item in completions:
|
|
606
|
+
if not item.table_data:
|
|
607
|
+
raise ValueError(
|
|
608
|
+
f"Argument '{arg_state.action.dest}' has table_columns defined, "
|
|
609
|
+
f"but the CompletionItem for '{item.text}' is missing table_data."
|
|
610
|
+
)
|
|
611
|
+
if len(item.table_data) != len(table_columns):
|
|
612
|
+
raise ValueError(
|
|
613
|
+
f"Argument '{arg_state.action.dest}': table_data length ({len(item.table_data)}) "
|
|
614
|
+
f"does not match table_columns length ({len(table_columns)}) for item '{item.text}'."
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
def _build_completion_table(self, arg_state: _ArgumentState, completions: Completions) -> Completions:
|
|
618
|
+
"""Build a rich.Table for completion results if applicable."""
|
|
619
|
+
# Verify integrity of completion data
|
|
620
|
+
self._validate_table_data(arg_state, completions)
|
|
601
621
|
|
|
602
|
-
|
|
603
|
-
|
|
622
|
+
table_columns = cast(
|
|
623
|
+
Sequence[str | Column] | None,
|
|
624
|
+
arg_state.action.get_table_columns(), # type: ignore[attr-defined]
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
# Skip table generation if results are outside thresholds or no columns are defined
|
|
628
|
+
if (
|
|
629
|
+
len(completions) < 2
|
|
630
|
+
or len(completions) > self._cmd2_app.max_completion_table_items
|
|
631
|
+
or table_columns is None
|
|
632
|
+
): # fmt: skip
|
|
604
633
|
return completions
|
|
605
634
|
|
|
606
635
|
# If a metavar was defined, use that instead of the dest field
|
|
@@ -620,26 +649,18 @@ class ArgparseCompleter:
|
|
|
620
649
|
# Build header row
|
|
621
650
|
rich_columns: list[Column] = []
|
|
622
651
|
rich_columns.append(Column(destination.upper(), justify="right" if all_nums else "left", no_wrap=True))
|
|
623
|
-
table_header = cast(Sequence[str | Column] | None, arg_state.action.get_table_header()) # type: ignore[attr-defined]
|
|
624
|
-
if table_header is None:
|
|
625
|
-
table_header = DEFAULT_TABLE_HEADER
|
|
626
652
|
rich_columns.extend(
|
|
627
|
-
column if isinstance(column, Column) else Column(column, overflow="fold") for column in
|
|
653
|
+
column if isinstance(column, Column) else Column(column, overflow="fold") for column in table_columns
|
|
628
654
|
)
|
|
629
655
|
|
|
630
|
-
#
|
|
631
|
-
|
|
656
|
+
# Build the table
|
|
657
|
+
table = Cmd2SimpleTable(*rich_columns)
|
|
632
658
|
for item in completions:
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
# Generate the table string
|
|
636
|
-
console = Cmd2GeneralConsole(file=self._cmd2_app.stdout)
|
|
637
|
-
with console.capture() as capture:
|
|
638
|
-
console.print(hint_table, end="", soft_wrap=False)
|
|
659
|
+
table.add_row(Text.from_ansi(item.display), *item.table_data)
|
|
639
660
|
|
|
640
661
|
return dataclasses.replace(
|
|
641
662
|
completions,
|
|
642
|
-
|
|
663
|
+
table=table,
|
|
643
664
|
)
|
|
644
665
|
|
|
645
666
|
def complete_subcommand_help(self, text: str, line: str, begidx: int, endidx: int, tokens: Sequence[str]) -> Completions:
|
|
@@ -780,7 +801,7 @@ class ArgparseCompleter:
|
|
|
780
801
|
filtered = [choice for choice in all_choices if choice.text not in used_values]
|
|
781
802
|
completions = self._cmd2_app.basic_complete(text, line, begidx, endidx, filtered)
|
|
782
803
|
|
|
783
|
-
return self.
|
|
804
|
+
return self._build_completion_table(arg_state, completions)
|
|
784
805
|
|
|
785
806
|
|
|
786
807
|
# The default ArgparseCompleter class for a cmd2 app
|
|
@@ -127,7 +127,7 @@ completion results displayed to the screen.
|
|
|
127
127
|
|
|
128
128
|
1. display - string for displaying the completion differently in the completion menu
|
|
129
129
|
2. display_meta - meta information about completion which displays in the completion menu
|
|
130
|
-
3.
|
|
130
|
+
3. table_data - supplemental data for completion tables
|
|
131
131
|
|
|
132
132
|
They can also be used as argparse choices. When a ``CompletionItem`` is created, it
|
|
133
133
|
stores the original value (e.g. ID number) and makes it accessible through a property
|
|
@@ -139,8 +139,8 @@ is compared to ``CompletionItem.value`` instead of the ``CompletionItem`` instan
|
|
|
139
139
|
These were added to help in cases where uninformative data is being completed.
|
|
140
140
|
For instance, completing ID numbers isn't very helpful to a user without context.
|
|
141
141
|
|
|
142
|
-
Providing ``
|
|
143
|
-
to output the completion results in a table with
|
|
142
|
+
Providing ``table_data`` in your ``CompletionItem`` signals ArgparseCompleter
|
|
143
|
+
to output the completion results in a table with supplemental data instead of just a table
|
|
144
144
|
of tokens::
|
|
145
145
|
|
|
146
146
|
Instead of this:
|
|
@@ -155,22 +155,21 @@ of tokens::
|
|
|
155
155
|
|
|
156
156
|
|
|
157
157
|
The left-most column is the actual value being completed and its header is
|
|
158
|
-
that value's name.
|
|
159
|
-
``
|
|
160
|
-
names
|
|
161
|
-
``
|
|
162
|
-
same number of items as ``
|
|
158
|
+
that value's name. Any additional column headers are defined using the
|
|
159
|
+
``table_columns`` parameter of add_argument(), which is a list of header
|
|
160
|
+
names. The supplemental column values come from the
|
|
161
|
+
``table_data`` argument to ``CompletionItem``. It's a ``Sequence`` with the
|
|
162
|
+
same number of items as ``table_columns``.
|
|
163
163
|
|
|
164
164
|
Example::
|
|
165
165
|
|
|
166
|
-
Add an argument and define its
|
|
166
|
+
Add an argument and define its table_columns.
|
|
167
167
|
|
|
168
168
|
parser.add_argument(
|
|
169
|
-
add_argument(
|
|
170
169
|
"item_id",
|
|
171
170
|
type=int,
|
|
172
171
|
choices_provider=get_choices,
|
|
173
|
-
|
|
172
|
+
table_columns=["Item Name", "Checked Out", "Due Date"],
|
|
174
173
|
)
|
|
175
174
|
|
|
176
175
|
Implement the choices_provider to return Choices.
|
|
@@ -178,12 +177,12 @@ Example::
|
|
|
178
177
|
def get_choices(self) -> Choices:
|
|
179
178
|
\"\"\"choices_provider which returns CompletionItems\"\"\"
|
|
180
179
|
|
|
181
|
-
# Populate CompletionItem's
|
|
182
|
-
# Its item count should match that of
|
|
180
|
+
# Populate CompletionItem's table_data argument.
|
|
181
|
+
# Its item count should match that of table_columns.
|
|
183
182
|
items = [
|
|
184
|
-
CompletionItem(1,
|
|
185
|
-
CompletionItem(2,
|
|
186
|
-
CompletionItem(3,
|
|
183
|
+
CompletionItem(1, table_data=["My item", True, "02/02/2022"]),
|
|
184
|
+
CompletionItem(2, table_data=["Another item", False, ""]),
|
|
185
|
+
CompletionItem(3, table_data=["Yet another item", False, ""]),
|
|
187
186
|
]
|
|
188
187
|
return Choices(items)
|
|
189
188
|
|
|
@@ -195,7 +194,7 @@ Example::
|
|
|
195
194
|
2 Another item False
|
|
196
195
|
3 Yet another item False
|
|
197
196
|
|
|
198
|
-
``
|
|
197
|
+
``table_columns`` can be strings or ``Rich.table.Columns`` for more
|
|
199
198
|
control over things like alignment.
|
|
200
199
|
|
|
201
200
|
- If a header is a string, it will render as a left-aligned column with its
|
|
@@ -207,9 +206,9 @@ This means a long string which exceeds the width of its column will be
|
|
|
207
206
|
truncated with an ellipsis at the end. You can override this and other settings
|
|
208
207
|
when you create the ``Column``.
|
|
209
208
|
|
|
210
|
-
``
|
|
209
|
+
``table_data`` items can include Rich objects, including styled Text and Tables.
|
|
211
210
|
|
|
212
|
-
To avoid printing
|
|
211
|
+
To avoid printing excessive information to the screen at once when a user
|
|
213
212
|
presses tab, there is a maximum threshold for the number of ``CompletionItems``
|
|
214
213
|
that will be shown. Its value is defined in ``cmd2.Cmd.max_completion_table_items``.
|
|
215
214
|
It defaults to 50, but can be changed. If the number of completion suggestions
|
|
@@ -240,8 +239,8 @@ for cases in which you need to manually access the cmd2-specific attributes.
|
|
|
240
239
|
- ``argparse.Action.get_choices_callable()`` - See `action_get_choices_callable` for more details.
|
|
241
240
|
- ``argparse.Action.set_choices_provider()`` - See `_action_set_choices_provider` for more details.
|
|
242
241
|
- ``argparse.Action.set_completer()`` - See `_action_set_completer` for more details.
|
|
243
|
-
- ``argparse.Action.
|
|
244
|
-
- ``argparse.Action.
|
|
242
|
+
- ``argparse.Action.get_table_columns()`` - See `_action_get_table_columns` for more details.
|
|
243
|
+
- ``argparse.Action.set_table_columns()`` - See `_action_set_table_columns` for more details.
|
|
245
244
|
- ``argparse.Action.get_nargs_range()`` - See `_action_get_nargs_range` for more details.
|
|
246
245
|
- ``argparse.Action.set_nargs_range()`` - See `_action_set_nargs_range` for more details.
|
|
247
246
|
- ``argparse.Action.get_suppress_tab_hint()`` - See `_action_get_suppress_tab_hint` for more details.
|
|
@@ -309,21 +308,21 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
309
308
|
|
|
310
309
|
def generate_range_error(range_min: int, range_max: float) -> str:
|
|
311
310
|
"""Generate an error message when the the number of arguments provided is not within the expected range."""
|
|
312
|
-
|
|
311
|
+
err_msg = "expected "
|
|
313
312
|
|
|
314
313
|
if range_max == constants.INFINITY:
|
|
315
314
|
plural = '' if range_min == 1 else 's'
|
|
316
|
-
|
|
315
|
+
err_msg += f"at least {range_min}"
|
|
317
316
|
else:
|
|
318
317
|
plural = '' if range_max == 1 else 's'
|
|
319
318
|
if range_min == range_max:
|
|
320
|
-
|
|
319
|
+
err_msg += f"{range_min}"
|
|
321
320
|
else:
|
|
322
|
-
|
|
321
|
+
err_msg += f"{range_min} to {range_max}"
|
|
323
322
|
|
|
324
|
-
|
|
323
|
+
err_msg += f" argument{plural}"
|
|
325
324
|
|
|
326
|
-
return
|
|
325
|
+
return err_msg
|
|
327
326
|
|
|
328
327
|
|
|
329
328
|
def set_parser_prog(parser: argparse.ArgumentParser, prog: str) -> None:
|
|
@@ -398,14 +397,14 @@ class ChoicesCallable:
|
|
|
398
397
|
|
|
399
398
|
@property
|
|
400
399
|
def choices_provider(self) -> ChoicesProviderUnbound[CmdOrSet]:
|
|
401
|
-
"""
|
|
400
|
+
"""Retrieve the internal choices_provider function."""
|
|
402
401
|
if self.is_completer:
|
|
403
402
|
raise AttributeError("This instance is configured as a completer, not a choices_provider")
|
|
404
403
|
return cast(ChoicesProviderUnbound[CmdOrSet], self.to_call)
|
|
405
404
|
|
|
406
405
|
@property
|
|
407
406
|
def completer(self) -> CompleterUnbound[CmdOrSet]:
|
|
408
|
-
"""
|
|
407
|
+
"""Retrieve the internal completer function."""
|
|
409
408
|
if not self.is_completer:
|
|
410
409
|
raise AttributeError("This instance is configured as a choices_provider, not a completer")
|
|
411
410
|
return cast(CompleterUnbound[CmdOrSet], self.to_call)
|
|
@@ -418,8 +417,8 @@ class ChoicesCallable:
|
|
|
418
417
|
# ChoicesCallable object that specifies the function to be called which provides choices to the argument
|
|
419
418
|
ATTR_CHOICES_CALLABLE = 'choices_callable'
|
|
420
419
|
|
|
421
|
-
#
|
|
422
|
-
|
|
420
|
+
# Completion table columns
|
|
421
|
+
ATTR_TABLE_COLUMNS = 'table_columns'
|
|
423
422
|
|
|
424
423
|
# A tuple specifying nargs as a range (min, max)
|
|
425
424
|
ATTR_NARGS_RANGE = 'nargs_range'
|
|
@@ -516,38 +515,38 @@ setattr(argparse.Action, 'set_completer', _action_set_completer)
|
|
|
516
515
|
|
|
517
516
|
|
|
518
517
|
############################################################################################################
|
|
519
|
-
# Patch argparse.Action with accessors for
|
|
518
|
+
# Patch argparse.Action with accessors for table_columns attribute
|
|
520
519
|
############################################################################################################
|
|
521
|
-
def
|
|
522
|
-
"""Get the
|
|
520
|
+
def _action_get_table_columns(self: argparse.Action) -> Sequence[str | Column] | None:
|
|
521
|
+
"""Get the table_columns attribute of an argparse Action.
|
|
523
522
|
|
|
524
|
-
This function is added by cmd2 as a method called ``
|
|
523
|
+
This function is added by cmd2 as a method called ``get_table_columns()`` to ``argparse.Action`` class.
|
|
525
524
|
|
|
526
|
-
To call: ``action.
|
|
525
|
+
To call: ``action.get_table_columns()``
|
|
527
526
|
|
|
528
527
|
:param self: argparse Action being queried
|
|
529
|
-
:return: The value of
|
|
528
|
+
:return: The value of table_columns or None if attribute does not exist
|
|
530
529
|
"""
|
|
531
|
-
return cast(Sequence[str | Column] | None, getattr(self,
|
|
530
|
+
return cast(Sequence[str | Column] | None, getattr(self, ATTR_TABLE_COLUMNS, None))
|
|
532
531
|
|
|
533
532
|
|
|
534
|
-
setattr(argparse.Action, '
|
|
533
|
+
setattr(argparse.Action, 'get_table_columns', _action_get_table_columns)
|
|
535
534
|
|
|
536
535
|
|
|
537
|
-
def
|
|
538
|
-
"""Set the
|
|
536
|
+
def _action_set_table_columns(self: argparse.Action, table_columns: Sequence[str | Column] | None) -> None:
|
|
537
|
+
"""Set the table_columns attribute of an argparse Action.
|
|
539
538
|
|
|
540
|
-
This function is added by cmd2 as a method called ``
|
|
539
|
+
This function is added by cmd2 as a method called ``set_table_columns()`` to ``argparse.Action`` class.
|
|
541
540
|
|
|
542
|
-
To call: ``action.
|
|
541
|
+
To call: ``action.set_table_columns(table_columns)``
|
|
543
542
|
|
|
544
543
|
:param self: argparse Action being updated
|
|
545
|
-
:param
|
|
544
|
+
:param table_columns: value being assigned
|
|
546
545
|
"""
|
|
547
|
-
setattr(self,
|
|
546
|
+
setattr(self, ATTR_TABLE_COLUMNS, table_columns)
|
|
548
547
|
|
|
549
548
|
|
|
550
|
-
setattr(argparse.Action, '
|
|
549
|
+
setattr(argparse.Action, 'set_table_columns', _action_set_table_columns)
|
|
551
550
|
|
|
552
551
|
|
|
553
552
|
############################################################################################################
|
|
@@ -698,7 +697,7 @@ def _add_argument_wrapper(
|
|
|
698
697
|
choices_provider: ChoicesProviderUnbound[CmdOrSet] | None = None,
|
|
699
698
|
completer: CompleterUnbound[CmdOrSet] | None = None,
|
|
700
699
|
suppress_tab_hint: bool = False,
|
|
701
|
-
|
|
700
|
+
table_columns: Sequence[str | Column] | None = None,
|
|
702
701
|
**kwargs: Any,
|
|
703
702
|
) -> argparse.Action:
|
|
704
703
|
"""Wrap ActionsContainer.add_argument() which supports more settings used by cmd2.
|
|
@@ -718,7 +717,7 @@ def _add_argument_wrapper(
|
|
|
718
717
|
current argument's help text as a hint. Set this to True to suppress the hint. If this
|
|
719
718
|
argument's help text is set to argparse.SUPPRESS, then tab hints will not display
|
|
720
719
|
regardless of the value passed for suppress_tab_hint. Defaults to False.
|
|
721
|
-
:param
|
|
720
|
+
:param table_columns: optional headers for when displaying a completion table. Defaults to None.
|
|
722
721
|
|
|
723
722
|
# Args from original function
|
|
724
723
|
:param kwargs: keyword-arguments recognized by argparse._ActionsContainer.add_argument
|
|
@@ -809,7 +808,7 @@ def _add_argument_wrapper(
|
|
|
809
808
|
new_arg.set_completer(completer) # type: ignore[attr-defined]
|
|
810
809
|
|
|
811
810
|
new_arg.set_suppress_tab_hint(suppress_tab_hint) # type: ignore[attr-defined]
|
|
812
|
-
new_arg.
|
|
811
|
+
new_arg.set_table_columns(table_columns) # type: ignore[attr-defined]
|
|
813
812
|
|
|
814
813
|
for keyword, value in custom_attribs.items():
|
|
815
814
|
attr_setter = getattr(new_arg, f'set_{keyword}', None)
|
|
@@ -1030,6 +1029,22 @@ class Cmd2HelpFormatter(RichHelpFormatter):
|
|
|
1030
1029
|
"""Set our console instance."""
|
|
1031
1030
|
self._console = console
|
|
1032
1031
|
|
|
1032
|
+
def _set_color(self, color: bool, **kwargs: Any) -> None:
|
|
1033
|
+
"""Set the color for the help output.
|
|
1034
|
+
|
|
1035
|
+
This override is needed because Python 3.15 added a 'file' keyword argument
|
|
1036
|
+
to _set_color() which some versions of RichHelpFormatter don't support.
|
|
1037
|
+
"""
|
|
1038
|
+
# Argparse didn't add color support until 3.14
|
|
1039
|
+
if sys.version_info < (3, 14):
|
|
1040
|
+
return
|
|
1041
|
+
|
|
1042
|
+
try: # type: ignore[unreachable]
|
|
1043
|
+
super()._set_color(color, **kwargs)
|
|
1044
|
+
except TypeError:
|
|
1045
|
+
# Fallback for older versions of RichHelpFormatter that don't support keyword arguments
|
|
1046
|
+
super()._set_color(color)
|
|
1047
|
+
|
|
1033
1048
|
def _build_nargs_range_str(self, nargs_range: tuple[int, int | float]) -> str:
|
|
1034
1049
|
"""Generate nargs range string for help text."""
|
|
1035
1050
|
if nargs_range[1] == constants.INFINITY:
|
|
@@ -1134,7 +1149,7 @@ class TextGroup:
|
|
|
1134
1149
|
self,
|
|
1135
1150
|
title: str,
|
|
1136
1151
|
text: RenderableType,
|
|
1137
|
-
formatter_creator: Callable[
|
|
1152
|
+
formatter_creator: Callable[..., Cmd2HelpFormatter],
|
|
1138
1153
|
) -> None:
|
|
1139
1154
|
"""TextGroup initializer.
|
|
1140
1155
|
|
|
@@ -1258,9 +1273,9 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
1258
1273
|
|
|
1259
1274
|
self.exit(2, f'{formatted_message}\n')
|
|
1260
1275
|
|
|
1261
|
-
def _get_formatter(self) -> Cmd2HelpFormatter:
|
|
1276
|
+
def _get_formatter(self, **kwargs: Any) -> Cmd2HelpFormatter:
|
|
1262
1277
|
"""Override with customizations for Cmd2HelpFormatter."""
|
|
1263
|
-
return cast(Cmd2HelpFormatter, super()._get_formatter())
|
|
1278
|
+
return cast(Cmd2HelpFormatter, super()._get_formatter(**kwargs))
|
|
1264
1279
|
|
|
1265
1280
|
def format_help(self) -> str:
|
|
1266
1281
|
"""Override to add a newline."""
|