cmd2 4.0.0b2__tar.gz → 4.0.0b4__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.0b2 → cmd2-4.0.0b4}/.pre-commit-config.yaml +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/CHANGELOG.md +47 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/PKG-INFO +3 -3
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/__init__.py +53 -41
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/argparse_completer.py +102 -94
- cmd2-4.0.0b4/cmd2/argparse_utils.py +847 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/cmd2.py +572 -514
- cmd2-4.0.0b4/cmd2/command_set.py +137 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/completion.py +79 -37
- cmd2-4.0.0b4/cmd2/constants.py +100 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/decorators.py +148 -129
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/history.py +19 -19
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/parsing.py +43 -43
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/pt_utils.py +13 -13
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/py_bridge.py +4 -4
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/rich_utils.py +329 -115
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/string_utils.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/styles.py +7 -1
- cmd2-4.0.0b4/cmd2/types.py +113 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/utils.py +41 -40
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2.egg-info/PKG-INFO +3 -3
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2.egg-info/SOURCES.txt +5 -5
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2.egg-info/requires.txt +2 -2
- cmd2-4.0.0b4/docs/api/argparse_utils.md +3 -0
- cmd2-4.0.0b4/docs/api/command_set.md +3 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/index.md +3 -3
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/argument_processing.md +20 -24
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/completion.md +3 -3
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/help.md +56 -30
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/initialization.md +9 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/modular_commands.md +98 -52
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/migrating/next_steps.md +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/README.md +1 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/argparse_completion.py +13 -13
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/argparse_example.py +38 -39
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/async_call.py +5 -5
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/async_commands.py +6 -6
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/async_printing.py +15 -15
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/basic_completion.py +7 -7
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/cmd_as_argument.py +22 -22
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/color.py +4 -4
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/command_sets.py +38 -36
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/custom_parser.py +7 -7
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/custom_types.py +9 -9
- cmd2-4.0.0b4/examples/default_categories.py +68 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/dynamic_commands.py +3 -3
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/environment.py +5 -5
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/event_loops.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/exit_code.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/getting_started.py +14 -19
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/hello_cmd2.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/help_categories.py +34 -34
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/hooks.py +6 -6
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/migrating.py +6 -6
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/mixin.py +3 -3
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/modular_commands/commandset_basic.py +15 -13
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/modular_commands/commandset_complex.py +17 -15
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/modular_commands/commandset_custominit.py +8 -5
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/modular_commandsets.py +6 -6
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/paged_output.py +4 -4
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/persistent_history.py +3 -3
- cmd2-4.0.0b4/examples/pretty_print.py +28 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/python_scripting.py +14 -14
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/read_input.py +10 -10
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/remove_builtin_commands.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/remove_settable.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/rich_tables.py +13 -18
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/scripts/conditional.py +10 -10
- cmd2-4.0.0b4/examples/scripts/save_help_text.py +107 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/unicode_commands.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/mkdocs.yml +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/pyproject.toml +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/ruff.toml +1 -4
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/scripts/validate_tag.py +5 -5
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/conftest.py +6 -20
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/echo.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/environment.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/help.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/raises_exception.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/recursive.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/self_in_py.py +1 -1
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/stop.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_argparse.py +182 -152
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_argparse_completer.py +385 -384
- cmd2-4.0.0b4/tests/test_argparse_subcommands.py +131 -0
- cmd2-4.0.0b4/tests/test_argparse_utils.py +567 -0
- cmd2-4.0.0b4/tests/test_categories.py +130 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_cmd2.py +865 -710
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_commandset.py +288 -273
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_completion.py +411 -255
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_dynamic_complete_style.py +6 -6
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_future_annotations.py +2 -2
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_history.py +263 -263
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_parsing.py +425 -425
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_plugin.py +86 -86
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_pt_utils.py +46 -46
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_py_completion.py +5 -5
- cmd2-4.0.0b4/tests/test_rich_utils.py +363 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_run_pyscript.py +44 -44
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_string_utils.py +29 -29
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_utils.py +63 -63
- cmd2-4.0.0b2/cmd2/argparse_custom.py +0 -1325
- cmd2-4.0.0b2/cmd2/command_definition.py +0 -202
- cmd2-4.0.0b2/cmd2/constants.py +0 -53
- cmd2-4.0.0b2/cmd2/types.py +0 -61
- cmd2-4.0.0b2/docs/api/argparse_custom.md +0 -3
- cmd2-4.0.0b2/docs/api/command_definition.md +0 -3
- cmd2-4.0.0b2/examples/default_categories.py +0 -76
- cmd2-4.0.0b2/examples/pretty_print.py +0 -44
- cmd2-4.0.0b2/examples/scripts/save_help_text.py +0 -97
- cmd2-4.0.0b2/tests/test_argparse_custom.py +0 -402
- cmd2-4.0.0b2/tests/test_argparse_subcommands.py +0 -133
- cmd2-4.0.0b2/tests/test_categories.py +0 -109
- cmd2-4.0.0b2/tests/test_rich_utils.py +0 -193
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/.prettierignore +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/.prettierrc +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/.typos.toml +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/GEMINI.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/LICENSE +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/MANIFEST.in +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/Makefile +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/README.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/clipboard.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/colors.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/exceptions.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/plugin.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2/py.typed +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2.egg-info/dependency_links.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2.egg-info/top_level.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/cmd2.png +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/codecov.yml +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/argparse_completer.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/clipboard.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/cmd.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/colors.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/completion.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/constants.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/decorators.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/exceptions.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/history.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/parsing.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/plugin.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/pt_utils.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/py_bridge.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/rich_utils.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/string_utils.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/styles.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/api/utils.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/doc_conventions.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/examples/alternate_event_loops.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/examples/examples.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/examples/getting_started.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/examples/index.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/async_commands.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/builtin_commands.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/clipboard.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/commands.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/disable_commands.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/embedded_python_shells.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/generating_output.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/history.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/hooks.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/index.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/misc.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/multiline_commands.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/os.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/packaging.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/plugins.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/prompt.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/redirection.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/scripting.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/settings.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/shortcuts_aliases_macros.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/startup_commands.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/table_creation.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/features/theme.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/index.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/javascripts/readthedocs.js +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/migrating/incompatibilities.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/migrating/index.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/migrating/minimum.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/migrating/why.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/mixins/index.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/mixins/mixin_template.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/overrides/main.html +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/overview/alternatives.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/overview/index.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/overview/installation.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/overview/integrating.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/overview/resources.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/stylesheets/cmd2.css +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/testing.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/docs/upgrades.md +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/.cmd2rc +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/modular_commands/__init__.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/rich_theme.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/scripts/arg_printer.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/scripts/nested.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/scripts/quit.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/scripts/script.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/scripts/script.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/tmux_launch.sh +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/examples/tmux_split.sh +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/package.json +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/setup.cfg +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/.cmd2rc +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/__init__.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/py_locals.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/pyscript_dir.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/pyscript/stdout_capture.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/relative_multiple.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/script.py +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/script.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/binary.bin +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/empty.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/help.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/nested.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/one_down.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/postcmds.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/precmds.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/scripts/utf8.txt +0 -0
- {cmd2-4.0.0b2 → cmd2-4.0.0b4}/tests/test_utils_defining_class.py +0 -0
|
@@ -64,6 +64,38 @@ prompt is displayed.
|
|
|
64
64
|
before calling it like the previous functions did.
|
|
65
65
|
- Removed `Cmd.default_to_shell`.
|
|
66
66
|
- Removed `Cmd.ruler` since `cmd2` no longer uses it.
|
|
67
|
+
- All parsers used with `cmd2` commands must be an instance of `Cmd2ArgumentParser` or a child
|
|
68
|
+
class of it.
|
|
69
|
+
- Removed `set_ap_completer_type()` and `get_ap_completer_type()` since `ap_completer_type` is
|
|
70
|
+
now a public member of `Cmd2ArgumentParser`.
|
|
71
|
+
- Moved `set_parser_prog()` to `Cmd2ArgumentParser.update_prog()`.
|
|
72
|
+
- Renamed `cmd2_handler` to `cmd2_subcmd_handler` in the `argparse.Namespace` for clarity.
|
|
73
|
+
- Removed `Cmd2AttributeWrapper` class. `argparse.Namespace` objects passed to command functions
|
|
74
|
+
now contain direct attributes for `cmd2_statement` and `cmd2_subcmd_handler`.
|
|
75
|
+
- Renamed `cmd2/command_definition.py` to `cmd2/command_set.py`.
|
|
76
|
+
- Removed `Cmd.doc_header` and the `with_default_category` decorator. Help categorization is now
|
|
77
|
+
driven by the `DEFAULT_CATEGORY` class variable (see **Simplified command categorization** in
|
|
78
|
+
the Enhancements section below for details).
|
|
79
|
+
- Removed `Cmd.undoc_header` since all commands are now considered categorized.
|
|
80
|
+
- Renamed `Cmd.cmd_func()` to `Cmd.get_command_func()`.
|
|
81
|
+
- `cmd2` no longer sets a default title for a subparsers group. If you desire a title, you will
|
|
82
|
+
need to pass one in like this `parser.add_subparsers(title="subcommands")`. This is standard
|
|
83
|
+
`argparse` behavior.
|
|
84
|
+
- `TextGroup` is now a standalone Rich renderable.
|
|
85
|
+
- Removed `formatter_creator` parameter from `TextGroup.__init__()`.
|
|
86
|
+
- Removed `Cmd2ArgumentParser.create_text_group()` method.
|
|
87
|
+
- `argparse` and `Rich` integration refactoring:
|
|
88
|
+
- Renamed `argparse_custom` module to `argparse_utils`.
|
|
89
|
+
- Moved the following classes from `argparse_utils` to `rich_utils`:
|
|
90
|
+
- `Cmd2HelpFormatter`
|
|
91
|
+
- `ArgumentDefaultsCmd2HelpFormatter`
|
|
92
|
+
- `MetavarTypeCmd2HelpFormatter`
|
|
93
|
+
- `RawDescriptionCmd2HelpFormatter`
|
|
94
|
+
- `RawTextCmd2HelpFormatter`
|
|
95
|
+
- `TextGroup`
|
|
96
|
+
- Replaced the global `APP_THEME` constant in `rich_utils.py` with `get_theme()` and
|
|
97
|
+
`set_theme()` functions to support lazy initialization and safer in-place updates of the
|
|
98
|
+
theme.
|
|
67
99
|
- Enhancements
|
|
68
100
|
- New `cmd2.Cmd` parameters
|
|
69
101
|
- **auto_suggest**: (boolean) if `True`, provide fish shell style auto-suggestions. These
|
|
@@ -79,6 +111,7 @@ prompt is displayed.
|
|
|
79
111
|
- **pre_prompt**: hook method that is called before the prompt is displayed, but after
|
|
80
112
|
`prompt-toolkit` event loop has started
|
|
81
113
|
- **read_secret**: read secrets like passwords without displaying them to the terminal
|
|
114
|
+
- **ppretty**: a cmd2-compatible replacement for `rich.pretty.pprint()`
|
|
82
115
|
- New settables:
|
|
83
116
|
- **max_column_completion_results**: (int) the maximum number of completion results to
|
|
84
117
|
display in a single column
|
|
@@ -88,6 +121,20 @@ prompt is displayed.
|
|
|
88
121
|
- Add support for Python 3.15 by fixing various bugs related to internal `argparse` changes
|
|
89
122
|
- Added `common_prefix` method to `cmd2.string_utils` module as a replacement for
|
|
90
123
|
`os.path.commonprefix` since that is now deprecated in Python 3.15
|
|
124
|
+
- Simplified command categorization:
|
|
125
|
+
- By default, all commands in a class are grouped under its `DEFAULT_CATEGORY`.
|
|
126
|
+
- Individual commands can still be manually moved using the `with_category()` decorator.
|
|
127
|
+
- For more details and examples, see the [Help](docs/features/help.md) documentation and the
|
|
128
|
+
`examples/default_categories.py` file.
|
|
129
|
+
- `CommandSet` is now a generic class, which allows developers to parameterize it with their
|
|
130
|
+
specific `cmd2.Cmd` subclass (e.g.,`class MyCommandSet(CommandSet[MyApp]):`). This provides
|
|
131
|
+
full type hints and IDE autocompletion for `self._cmd` without needing to override and cast
|
|
132
|
+
the property.
|
|
133
|
+
|
|
134
|
+
## 3.5.0 (April 13, 2026)
|
|
135
|
+
|
|
136
|
+
- Bug Fixes
|
|
137
|
+
- Fixed issue where Rich stripped colors from text in test environments where TERM=dumb.
|
|
91
138
|
|
|
92
139
|
## 3.4.0 (March 3, 2026)
|
|
93
140
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmd2
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.0b4
|
|
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
|
|
@@ -25,8 +25,8 @@ License-File: LICENSE
|
|
|
25
25
|
Requires-Dist: backports.strenum; python_version == "3.10"
|
|
26
26
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
27
27
|
Requires-Dist: pyperclip>=1.8.2
|
|
28
|
-
Requires-Dist: rich>=
|
|
29
|
-
Requires-Dist: rich-argparse>=1.7.
|
|
28
|
+
Requires-Dist: rich>=15.0.0
|
|
29
|
+
Requires-Dist: rich-argparse>=1.7.2
|
|
30
30
|
Requires-Dist: typing-extensions; python_version == "3.10"
|
|
31
31
|
Dynamic: license-file
|
|
32
32
|
|
|
@@ -12,18 +12,14 @@ from . import (
|
|
|
12
12
|
string_utils,
|
|
13
13
|
)
|
|
14
14
|
from .argparse_completer import set_default_ap_completer_type
|
|
15
|
-
from .
|
|
15
|
+
from .argparse_utils import (
|
|
16
16
|
Cmd2ArgumentParser,
|
|
17
|
-
Cmd2AttributeWrapper,
|
|
18
17
|
register_argparse_argument_parameter,
|
|
19
18
|
set_default_argument_parser_type,
|
|
20
19
|
)
|
|
21
20
|
from .cmd2 import Cmd
|
|
22
21
|
from .colors import Color
|
|
23
|
-
from .
|
|
24
|
-
CommandSet,
|
|
25
|
-
with_default_category,
|
|
26
|
-
)
|
|
22
|
+
from .command_set import CommandSet
|
|
27
23
|
from .completion import (
|
|
28
24
|
Choices,
|
|
29
25
|
CompletionItem,
|
|
@@ -48,7 +44,17 @@ from .exceptions import (
|
|
|
48
44
|
)
|
|
49
45
|
from .parsing import Statement
|
|
50
46
|
from .py_bridge import CommandResult
|
|
51
|
-
from .rich_utils import
|
|
47
|
+
from .rich_utils import (
|
|
48
|
+
ArgumentDefaultsCmd2HelpFormatter,
|
|
49
|
+
Cmd2HelpFormatter,
|
|
50
|
+
MetavarTypeCmd2HelpFormatter,
|
|
51
|
+
RawDescriptionCmd2HelpFormatter,
|
|
52
|
+
RawTextCmd2HelpFormatter,
|
|
53
|
+
RichPrintKwargs,
|
|
54
|
+
TextGroup,
|
|
55
|
+
get_theme,
|
|
56
|
+
set_theme,
|
|
57
|
+
)
|
|
52
58
|
from .string_utils import stylize
|
|
53
59
|
from .styles import Cmd2Style
|
|
54
60
|
from .utils import (
|
|
@@ -59,50 +65,56 @@ from .utils import (
|
|
|
59
65
|
)
|
|
60
66
|
|
|
61
67
|
__all__: list[str] = [ # noqa: RUF022
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
"COMMAND_NAME",
|
|
69
|
+
"DEFAULT_SHORTCUTS",
|
|
64
70
|
# Argparse Exports
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
'set_default_argument_parser_type',
|
|
71
|
+
"Cmd2ArgumentParser",
|
|
72
|
+
"register_argparse_argument_parameter",
|
|
73
|
+
"set_default_ap_completer_type",
|
|
74
|
+
"set_default_argument_parser_type",
|
|
70
75
|
# Cmd2
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
"Cmd",
|
|
77
|
+
"CommandResult",
|
|
78
|
+
"CommandSet",
|
|
79
|
+
"Statement",
|
|
75
80
|
# Colors
|
|
76
81
|
"Color",
|
|
77
82
|
# Completion
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
"Choices",
|
|
84
|
+
"CompletionItem",
|
|
85
|
+
"Completions",
|
|
81
86
|
# Decorators
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
'as_subcommand_to',
|
|
87
|
+
"with_argument_list",
|
|
88
|
+
"with_argparser",
|
|
89
|
+
"with_category",
|
|
90
|
+
"as_subcommand_to",
|
|
87
91
|
# Exceptions
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
"Cmd2ArgparseError",
|
|
93
|
+
"CommandSetRegistrationError",
|
|
94
|
+
"CompletionError",
|
|
95
|
+
"PassThroughException",
|
|
96
|
+
"SkipPostcommandHooks",
|
|
93
97
|
# modules
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
"plugin",
|
|
99
|
+
"rich_utils",
|
|
100
|
+
"string_utils",
|
|
97
101
|
# Rich Utils
|
|
98
|
-
|
|
102
|
+
"ArgumentDefaultsCmd2HelpFormatter",
|
|
103
|
+
"Cmd2HelpFormatter",
|
|
104
|
+
"get_theme",
|
|
105
|
+
"MetavarTypeCmd2HelpFormatter",
|
|
106
|
+
"RawDescriptionCmd2HelpFormatter",
|
|
107
|
+
"RawTextCmd2HelpFormatter",
|
|
108
|
+
"RichPrintKwargs",
|
|
109
|
+
"set_theme",
|
|
110
|
+
"TextGroup",
|
|
99
111
|
# String Utils
|
|
100
|
-
|
|
112
|
+
"stylize",
|
|
101
113
|
# Styles,
|
|
102
|
-
|
|
114
|
+
"Cmd2Style",
|
|
103
115
|
# Utilities
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
"categorize",
|
|
117
|
+
"CustomCompletionSettings",
|
|
118
|
+
"Settable",
|
|
119
|
+
"set_default_str_sort_key",
|
|
108
120
|
]
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"""Module defines the ArgparseCompleter class which provides argparse-based completion to cmd2 apps.
|
|
2
2
|
|
|
3
|
-
See the header of
|
|
3
|
+
See the header of argparse_utils.py for instructions on how to use these features.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import argparse
|
|
7
7
|
import dataclasses
|
|
8
8
|
import inspect
|
|
9
|
-
from collections import
|
|
10
|
-
defaultdict,
|
|
11
|
-
deque,
|
|
12
|
-
)
|
|
9
|
+
from collections import deque
|
|
13
10
|
from collections.abc import (
|
|
14
11
|
Mapping,
|
|
15
12
|
MutableSequence,
|
|
@@ -22,39 +19,42 @@ from typing import (
|
|
|
22
19
|
cast,
|
|
23
20
|
)
|
|
24
21
|
|
|
25
|
-
from rich.text import Text
|
|
26
|
-
|
|
27
|
-
from .constants import INFINITY
|
|
28
|
-
from .rich_utils import Cmd2SimpleTable
|
|
29
|
-
|
|
30
|
-
if TYPE_CHECKING: # pragma: no cover
|
|
31
|
-
from .cmd2 import Cmd
|
|
32
|
-
|
|
33
22
|
from rich.table import Column
|
|
23
|
+
from rich.text import Text
|
|
34
24
|
|
|
35
|
-
from .
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
from .argparse_utils import (
|
|
26
|
+
Cmd2ArgumentParser,
|
|
27
|
+
build_range_error,
|
|
38
28
|
)
|
|
39
|
-
from .
|
|
29
|
+
from .command_set import CommandSet
|
|
40
30
|
from .completion import (
|
|
41
31
|
CompletionItem,
|
|
42
32
|
Completions,
|
|
43
|
-
all_display_numeric,
|
|
44
33
|
)
|
|
34
|
+
from .constants import INFINITY
|
|
45
35
|
from .exceptions import CompletionError
|
|
36
|
+
from .rich_utils import Cmd2SimpleTable
|
|
37
|
+
from .types import (
|
|
38
|
+
CmdOrSetT,
|
|
39
|
+
UnboundChoicesProvider,
|
|
40
|
+
UnboundCompleter,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
44
|
+
from .cmd2 import Cmd
|
|
45
|
+
|
|
46
46
|
|
|
47
47
|
# Name of the choice/completer function argument that, if present, will be passed a dictionary of
|
|
48
48
|
# command line tokens up through the token being completed mapped to their argparse destination name.
|
|
49
|
-
ARG_TOKENS =
|
|
49
|
+
ARG_TOKENS = "arg_tokens"
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def _build_hint(parser:
|
|
52
|
+
def _build_hint(parser: Cmd2ArgumentParser, arg_action: argparse.Action) -> str:
|
|
53
53
|
"""Build completion hint for a given argument."""
|
|
54
54
|
# Check if hinting is disabled for this argument
|
|
55
55
|
suppress_hint = arg_action.get_suppress_tab_hint() # type: ignore[attr-defined]
|
|
56
56
|
if suppress_hint or arg_action.help == argparse.SUPPRESS:
|
|
57
|
-
return
|
|
57
|
+
return ""
|
|
58
58
|
|
|
59
59
|
# Use the parser's help formatter to display just this action's help text
|
|
60
60
|
formatter = parser._get_formatter()
|
|
@@ -64,12 +64,12 @@ def _build_hint(parser: argparse.ArgumentParser, arg_action: argparse.Action) ->
|
|
|
64
64
|
return formatter.format_help()
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def _single_prefix_char(token: str, parser:
|
|
67
|
+
def _single_prefix_char(token: str, parser: Cmd2ArgumentParser) -> bool:
|
|
68
68
|
"""Is a token just a single flag prefix character."""
|
|
69
69
|
return len(token) == 1 and token[0] in parser.prefix_chars
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
def _looks_like_flag(token: str, parser:
|
|
72
|
+
def _looks_like_flag(token: str, parser: Cmd2ArgumentParser) -> bool:
|
|
73
73
|
"""Determine if a token looks like a flag.
|
|
74
74
|
|
|
75
75
|
Unless an argument has nargs set to argparse.REMAINDER, then anything that looks like a flag
|
|
@@ -90,7 +90,7 @@ def _looks_like_flag(token: str, parser: argparse.ArgumentParser) -> bool:
|
|
|
90
90
|
return False
|
|
91
91
|
|
|
92
92
|
# Flags can't have a space
|
|
93
|
-
return
|
|
93
|
+
return " " not in token
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
class _ArgumentState:
|
|
@@ -133,19 +133,19 @@ class _UnfinishedFlagError(CompletionError):
|
|
|
133
133
|
|
|
134
134
|
:param flag_arg_state: information about the unfinished flag action.
|
|
135
135
|
"""
|
|
136
|
-
arg = f
|
|
137
|
-
err = f
|
|
136
|
+
arg = f"{argparse._get_action_name(flag_arg_state.action)}"
|
|
137
|
+
err = f"{build_range_error(flag_arg_state.min, flag_arg_state.max)}"
|
|
138
138
|
error = f"Error: argument {arg}: {err} ({flag_arg_state.count} entered)"
|
|
139
139
|
super().__init__(error)
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
class _NoResultsError(CompletionError):
|
|
143
|
-
def __init__(self, parser:
|
|
143
|
+
def __init__(self, parser: Cmd2ArgumentParser, arg_action: argparse.Action) -> None:
|
|
144
144
|
"""CompletionError which occurs when there are no results.
|
|
145
145
|
|
|
146
146
|
If hinting is allowed on this argument, then its hint text will display.
|
|
147
147
|
|
|
148
|
-
:param parser:
|
|
148
|
+
:param parser: Cmd2ArgumentParser instance which owns the action being completed
|
|
149
149
|
:param arg_action: action being completed.
|
|
150
150
|
"""
|
|
151
151
|
# Set apply_style to False because we don't want hints to look like errors
|
|
@@ -157,14 +157,14 @@ class ArgparseCompleter:
|
|
|
157
157
|
|
|
158
158
|
def __init__(
|
|
159
159
|
self,
|
|
160
|
-
parser:
|
|
161
|
-
cmd2_app:
|
|
160
|
+
parser: Cmd2ArgumentParser,
|
|
161
|
+
cmd2_app: "Cmd",
|
|
162
162
|
*,
|
|
163
163
|
parent_tokens: Mapping[str, MutableSequence[str]] | None = None,
|
|
164
164
|
) -> None:
|
|
165
165
|
"""Create an ArgparseCompleter.
|
|
166
166
|
|
|
167
|
-
:param parser:
|
|
167
|
+
:param parser: Cmd2ArgumentParser instance
|
|
168
168
|
:param cmd2_app: reference to the Cmd2 application that owns this ArgparseCompleter
|
|
169
169
|
:param parent_tokens: optional Mapping of parent parsers' arg names to their tokens
|
|
170
170
|
This is only used by ArgparseCompleter when recursing on subcommand parsers
|
|
@@ -187,7 +187,7 @@ class ArgparseCompleter:
|
|
|
187
187
|
self._positional_actions: list[argparse.Action] = []
|
|
188
188
|
|
|
189
189
|
# This will be set if self._parser has subcommands
|
|
190
|
-
self._subcommand_action: argparse._SubParsersAction[
|
|
190
|
+
self._subcommand_action: argparse._SubParsersAction[Cmd2ArgumentParser] | None = None
|
|
191
191
|
|
|
192
192
|
# Start digging through the argparse structures.
|
|
193
193
|
# _actions is the top level container of parameter definitions
|
|
@@ -214,7 +214,7 @@ class ArgparseCompleter:
|
|
|
214
214
|
endidx: int,
|
|
215
215
|
tokens: Sequence[str],
|
|
216
216
|
*,
|
|
217
|
-
cmd_set: CommandSet | None = None,
|
|
217
|
+
cmd_set: CommandSet[Any] | None = None,
|
|
218
218
|
) -> Completions:
|
|
219
219
|
"""Complete text using argparse metadata.
|
|
220
220
|
|
|
@@ -248,7 +248,7 @@ class ArgparseCompleter:
|
|
|
248
248
|
used_flags: set[str] = set()
|
|
249
249
|
|
|
250
250
|
# Keeps track of arguments we've seen and any tokens they consumed
|
|
251
|
-
consumed_arg_values: dict[str, list[str]] =
|
|
251
|
+
consumed_arg_values: dict[str, list[str]] = {}
|
|
252
252
|
|
|
253
253
|
# Completed mutually exclusive groups
|
|
254
254
|
completed_mutex_groups: dict[argparse._MutuallyExclusiveGroup, argparse.Action] = {}
|
|
@@ -256,7 +256,7 @@ class ArgparseCompleter:
|
|
|
256
256
|
def consume_argument(arg_state: _ArgumentState, arg_token: str) -> None:
|
|
257
257
|
"""Consume token as an argument."""
|
|
258
258
|
arg_state.count += 1
|
|
259
|
-
consumed_arg_values
|
|
259
|
+
consumed_arg_values.setdefault(arg_state.action.dest, []).append(arg_token)
|
|
260
260
|
|
|
261
261
|
#############################################################################################
|
|
262
262
|
# Parse all but the last token
|
|
@@ -269,14 +269,14 @@ class ArgparseCompleter:
|
|
|
269
269
|
|
|
270
270
|
# If we're in a flag REMAINDER arg, force all future tokens to go to that until a double dash is hit
|
|
271
271
|
if flag_arg_state is not None and flag_arg_state.is_remainder:
|
|
272
|
-
if token ==
|
|
272
|
+
if token == "--": # noqa: S105
|
|
273
273
|
flag_arg_state = None
|
|
274
274
|
else:
|
|
275
275
|
consume_argument(flag_arg_state, token)
|
|
276
276
|
continue
|
|
277
277
|
|
|
278
278
|
# Handle '--' which tells argparse all remaining arguments are non-flags
|
|
279
|
-
if token ==
|
|
279
|
+
if token == "--" and not skip_remaining_flags: # noqa: S105
|
|
280
280
|
# Check if there is an unfinished flag
|
|
281
281
|
if (
|
|
282
282
|
flag_arg_state is not None
|
|
@@ -333,7 +333,7 @@ class ArgparseCompleter:
|
|
|
333
333
|
# filter them from future completion results and clear any previously
|
|
334
334
|
# recorded values for this destination.
|
|
335
335
|
used_flags.update(action.option_strings)
|
|
336
|
-
consumed_arg_values[action.dest]
|
|
336
|
+
consumed_arg_values[action.dest] = []
|
|
337
337
|
|
|
338
338
|
new_arg_state = _ArgumentState(action)
|
|
339
339
|
|
|
@@ -357,9 +357,8 @@ class ArgparseCompleter:
|
|
|
357
357
|
action = remaining_positionals.popleft()
|
|
358
358
|
|
|
359
359
|
# Are we at a subcommand? If so, forward to the matching completer
|
|
360
|
-
if action == self._subcommand_action:
|
|
360
|
+
if self._subcommand_action is not None and action == self._subcommand_action:
|
|
361
361
|
if token in self._subcommand_action.choices:
|
|
362
|
-
# Merge self._parent_tokens and consumed_arg_values
|
|
363
362
|
parent_tokens = {**self._parent_tokens, **consumed_arg_values}
|
|
364
363
|
|
|
365
364
|
# Include the subcommand name if its destination was set
|
|
@@ -438,8 +437,8 @@ class ArgparseCompleter:
|
|
|
438
437
|
if arg_action == completer_action:
|
|
439
438
|
return
|
|
440
439
|
|
|
441
|
-
arg_str = f
|
|
442
|
-
completer_str = f
|
|
440
|
+
arg_str = f"{argparse._get_action_name(arg_action)}"
|
|
441
|
+
completer_str = f"{argparse._get_action_name(completer_action)}"
|
|
443
442
|
error = f"Error: argument {arg_str}: not allowed with argument {completer_str}"
|
|
444
443
|
raise CompletionError(error)
|
|
445
444
|
|
|
@@ -470,7 +469,7 @@ class ArgparseCompleter:
|
|
|
470
469
|
consumed_arg_values: dict[str, list[str]],
|
|
471
470
|
used_flags: set[str],
|
|
472
471
|
skip_remaining_flags: bool,
|
|
473
|
-
cmd_set: CommandSet | None,
|
|
472
|
+
cmd_set: CommandSet[Any] | None,
|
|
474
473
|
) -> Completions:
|
|
475
474
|
"""Perform final completion step handling positionals and flags."""
|
|
476
475
|
# Check if we are completing a flag name. This check ignores strings with a length of one, like '-'.
|
|
@@ -554,7 +553,7 @@ class ArgparseCompleter:
|
|
|
554
553
|
match_against.append(flag)
|
|
555
554
|
|
|
556
555
|
# Build a dictionary linking actions with their matched flag names
|
|
557
|
-
matched_actions: dict[argparse.Action, list[str]] =
|
|
556
|
+
matched_actions: dict[argparse.Action, list[str]] = {}
|
|
558
557
|
|
|
559
558
|
# Keep flags sorted in the order provided by argparse so our completion
|
|
560
559
|
# suggestions display the same as argparse help text.
|
|
@@ -562,23 +561,23 @@ class ArgparseCompleter:
|
|
|
562
561
|
|
|
563
562
|
for flag in matched_flags.to_strings():
|
|
564
563
|
action = self._flag_to_action[flag]
|
|
565
|
-
matched_actions[
|
|
564
|
+
matched_actions.setdefault(action, []).append(flag)
|
|
566
565
|
|
|
567
566
|
# For completion suggestions, group matched flags by action
|
|
568
567
|
items: list[CompletionItem] = []
|
|
569
568
|
for action, option_strings in matched_actions.items():
|
|
570
|
-
flag_text =
|
|
569
|
+
flag_text = ", ".join(option_strings)
|
|
571
570
|
|
|
572
571
|
# Mark optional flags with brackets
|
|
573
572
|
if not action.required:
|
|
574
|
-
flag_text =
|
|
573
|
+
flag_text = "[" + flag_text + "]"
|
|
575
574
|
|
|
576
575
|
# Use the first option string as the completion result for this action
|
|
577
576
|
items.append(
|
|
578
577
|
CompletionItem(
|
|
579
578
|
option_strings[0],
|
|
580
579
|
display=flag_text,
|
|
581
|
-
display_meta=action.help or
|
|
580
|
+
display_meta=action.help or "",
|
|
582
581
|
)
|
|
583
582
|
)
|
|
584
583
|
|
|
@@ -643,12 +642,15 @@ class ArgparseCompleter:
|
|
|
643
642
|
# the 3rd or more argument here.
|
|
644
643
|
destination = destination[min(len(destination) - 1, arg_state.count)]
|
|
645
644
|
|
|
646
|
-
# Determine if all display values are numeric so we can right-align them
|
|
647
|
-
all_nums = all_display_numeric(completions.items)
|
|
648
|
-
|
|
649
645
|
# Build header row
|
|
650
646
|
rich_columns: list[Column] = []
|
|
651
|
-
rich_columns.append(
|
|
647
|
+
rich_columns.append(
|
|
648
|
+
Column(
|
|
649
|
+
destination.upper(),
|
|
650
|
+
justify="right" if completions.numeric_display else "left",
|
|
651
|
+
no_wrap=True,
|
|
652
|
+
)
|
|
653
|
+
)
|
|
652
654
|
rich_columns.extend(
|
|
653
655
|
column if isinstance(column, Column) else Column(column, overflow="fold") for column in table_columns
|
|
654
656
|
)
|
|
@@ -707,51 +709,50 @@ class ArgparseCompleter:
|
|
|
707
709
|
return
|
|
708
710
|
self._parser.print_help(file=file)
|
|
709
711
|
|
|
710
|
-
def
|
|
711
|
-
"""
|
|
712
|
-
if arg_state.action.choices is
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
for name, subparser in arg_state.action.choices.items()
|
|
724
|
-
]
|
|
725
|
-
|
|
726
|
-
# Standard choices
|
|
712
|
+
def _choices_to_items(self, arg_state: _ArgumentState) -> list[CompletionItem]:
|
|
713
|
+
"""Convert choices from action to list of CompletionItems."""
|
|
714
|
+
if arg_state.action.choices is None:
|
|
715
|
+
return []
|
|
716
|
+
|
|
717
|
+
# If choices are subcommands, then get their help text to populate display_meta.
|
|
718
|
+
if isinstance(arg_state.action, argparse._SubParsersAction):
|
|
719
|
+
parser_help = {}
|
|
720
|
+
for action in arg_state.action._choices_actions:
|
|
721
|
+
if action.dest in arg_state.action.choices:
|
|
722
|
+
subparser = arg_state.action.choices[action.dest]
|
|
723
|
+
parser_help[subparser] = action.help or ""
|
|
724
|
+
|
|
727
725
|
return [
|
|
728
|
-
|
|
726
|
+
CompletionItem(name, display_meta=parser_help.get(subparser, ""))
|
|
727
|
+
for name, subparser in arg_state.action.choices.items()
|
|
729
728
|
]
|
|
730
729
|
|
|
731
|
-
|
|
732
|
-
return
|
|
730
|
+
# Standard choices
|
|
731
|
+
return [
|
|
732
|
+
choice if isinstance(choice, CompletionItem) else CompletionItem(choice) for choice in arg_state.action.choices
|
|
733
|
+
]
|
|
733
734
|
|
|
734
735
|
def _prepare_callable_params(
|
|
735
736
|
self,
|
|
736
|
-
|
|
737
|
+
to_call: UnboundChoicesProvider[CmdOrSetT] | UnboundCompleter[CmdOrSetT],
|
|
737
738
|
arg_state: _ArgumentState,
|
|
738
739
|
text: str,
|
|
739
740
|
consumed_arg_values: dict[str, list[str]],
|
|
740
|
-
cmd_set: CommandSet | None,
|
|
741
|
+
cmd_set: CommandSet[Any] | None,
|
|
741
742
|
) -> tuple[list[Any], dict[str, Any]]:
|
|
742
743
|
"""Resolve the instance and arguments required to call a choices/completer function."""
|
|
743
744
|
args: list[Any] = []
|
|
744
745
|
kwargs: dict[str, Any] = {}
|
|
745
746
|
|
|
746
747
|
# Resolve the 'self' instance for the method
|
|
747
|
-
self_arg = self._cmd2_app._resolve_func_self(
|
|
748
|
+
self_arg = self._cmd2_app._resolve_func_self(to_call, cmd_set)
|
|
748
749
|
if self_arg is None:
|
|
749
|
-
raise CompletionError("Could not find CommandSet instance matching defining type
|
|
750
|
+
raise CompletionError("Could not find CommandSet instance matching defining type")
|
|
750
751
|
|
|
751
752
|
args.append(self_arg)
|
|
752
753
|
|
|
753
754
|
# Check if the function expects 'arg_tokens'
|
|
754
|
-
to_call_params = inspect.signature(
|
|
755
|
+
to_call_params = inspect.signature(to_call).parameters
|
|
755
756
|
if ARG_TOKENS in to_call_params:
|
|
756
757
|
arg_tokens = {**self._parent_tokens, **consumed_arg_values}
|
|
757
758
|
arg_tokens.setdefault(arg_state.action.dest, []).append(text)
|
|
@@ -768,33 +769,40 @@ class ArgparseCompleter:
|
|
|
768
769
|
arg_state: _ArgumentState,
|
|
769
770
|
consumed_arg_values: dict[str, list[str]],
|
|
770
771
|
*,
|
|
771
|
-
cmd_set: CommandSet | None = None,
|
|
772
|
+
cmd_set: CommandSet[Any] | None = None,
|
|
772
773
|
) -> Completions:
|
|
773
774
|
"""Completion routine for an argparse argument.
|
|
774
775
|
|
|
775
776
|
:return: a Completions object
|
|
776
777
|
:raises CompletionError: if the completer or choices function this calls raises one
|
|
777
778
|
"""
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
779
|
+
# Check if the argument uses a completer
|
|
780
|
+
completer = arg_state.action.get_completer() # type: ignore[attr-defined]
|
|
781
|
+
if completer is not None:
|
|
782
|
+
args, kwargs = self._prepare_callable_params(
|
|
783
|
+
completer,
|
|
784
|
+
arg_state,
|
|
785
|
+
text,
|
|
786
|
+
consumed_arg_values,
|
|
787
|
+
cmd_set,
|
|
788
|
+
)
|
|
785
789
|
args.extend([text, line, begidx, endidx])
|
|
786
|
-
completions =
|
|
790
|
+
completions: Completions = completer(*args, **kwargs)
|
|
787
791
|
|
|
788
|
-
# Otherwise it uses a choices
|
|
792
|
+
# Otherwise it uses a choices provider or choices list
|
|
789
793
|
else:
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
794
|
+
choices_provider = arg_state.action.get_choices_provider() # type: ignore[attr-defined]
|
|
795
|
+
if choices_provider is not None:
|
|
796
|
+
args, kwargs = self._prepare_callable_params(
|
|
797
|
+
choices_provider,
|
|
798
|
+
arg_state,
|
|
799
|
+
text,
|
|
800
|
+
consumed_arg_values,
|
|
801
|
+
cmd_set,
|
|
802
|
+
)
|
|
803
|
+
all_choices = list(choices_provider(*args, **kwargs))
|
|
796
804
|
else:
|
|
797
|
-
all_choices =
|
|
805
|
+
all_choices = self._choices_to_items(arg_state)
|
|
798
806
|
|
|
799
807
|
# Filter used values and run basic completion
|
|
800
808
|
used_values = consumed_arg_values.get(arg_state.action.dest, [])
|