cmd2 4.2.0__tar.gz → 4.2.2__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.2.0 → cmd2-4.2.2}/.pre-commit-config.yaml +2 -2
- {cmd2-4.2.0 → cmd2-4.2.2}/CHANGELOG.md +15 -1
- {cmd2-4.2.0 → cmd2-4.2.2}/Makefile +9 -9
- {cmd2-4.2.0 → cmd2-4.2.2}/PKG-INFO +1 -1
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/annotated.py +7 -4
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/argparse_utils.py +7 -6
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/cmd2.py +67 -38
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/decorators.py +3 -3
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/parsing.py +4 -4
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/pt_utils.py +1 -1
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/rich_utils.py +1 -1
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.egg-info/PKG-INFO +1 -1
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.egg-info/SOURCES.txt +2 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.egg-info/scm_file_list.json +129 -128
- cmd2-4.2.2/cmd2.egg-info/scm_version.json +8 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/argument_processing.md +8 -8
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/os.md +21 -33
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/startup_commands.md +19 -6
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/upgrades.md +9 -9
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/README.md +4 -2
- cmd2-4.2.2/examples/cmd2_history.dat +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/cmd_as_argument.py +13 -31
- {cmd2-4.2.0 → cmd2-4.2.2}/pyproject.toml +2 -28
- {cmd2-4.2.0 → cmd2-4.2.2}/ruff.toml +2 -1
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_annotated.py +43 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_cmd2.py +91 -1
- cmd2-4.2.2/ty.toml +8 -0
- cmd2-4.2.0/cmd2.egg-info/scm_version.json +0 -8
- {cmd2-4.2.0 → cmd2-4.2.2}/.prettierignore +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/.prettierrc +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/.typos.toml +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/GEMINI.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/LICENSE +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/MANIFEST.in +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/README.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/__init__.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/argparse_completer.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/clipboard.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/colors.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/command_set.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/completion.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/constants.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/exceptions.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/history.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/plugin.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/py.typed +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/py_bridge.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/string_utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/styles.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/theme.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/types.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2/utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.egg-info/dependency_links.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.egg-info/requires.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.egg-info/top_level.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/cmd2.png +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/codecov.yml +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/annotated.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/argparse_completer.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/argparse_utils.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/clipboard.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/cmd.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/colors.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/command_set.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/completion.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/constants.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/decorators.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/exceptions.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/history.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/parsing.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/plugin.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/pt_utils.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/py_bridge.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/rich_utils.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/string_utils.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/styles.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/theme.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/api/utils.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/doc_conventions.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/examples/alternate_event_loops.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/examples/examples.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/examples/getting_started.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/examples/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/annotated.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/async_commands.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/builtin_commands.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/clipboard.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/commands.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/completion.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/disable_commands.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/embedded_python_shells.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/generating_output.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/help.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/history.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/hooks.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/initialization.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/misc.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/modular_commands.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/multiline_commands.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/packaging.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/plugins.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/prompt.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/redirection.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/scripting.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/settings.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/shortcuts_aliases_macros.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/table_creation.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/features/theme.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/javascripts/readthedocs.js +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/migrating/incompatibilities.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/migrating/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/migrating/minimum.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/migrating/next_steps.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/migrating/why.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/mixins/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/mixins/mixin_template.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/overrides/main.html +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/overview/alternatives.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/overview/index.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/overview/installation.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/overview/integrating.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/overview/resources.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/stylesheets/cmd2.css +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/docs/testing.md +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/.cmd2rc +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/annotated_example.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/argparse_completion.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/argparse_example.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/async_call.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/async_commands.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/async_printing.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/basic_completion.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/color.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/command_sets.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/completion_item_choices.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/custom_parser.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/custom_types.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/default_categories.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/dynamic_commands.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/environment.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/event_loops.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/exit_code.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/getting_started.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/hello_cmd2.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/help_categories.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/hooks.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/migrating.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/mixin.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/modular_commands/__init__.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/modular_commands/commandset_basic.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/modular_commands/commandset_complex.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/modular_commands/commandset_custominit.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/modular_commandsets.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/paged_output.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/persistent_history.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/pretty_print.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/python_scripting.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/read_input.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/remove_builtin_commands.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/remove_settable.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/rich_tables.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/rich_theme.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/arg_printer.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/conditional.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/nested.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/quit.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/save_help_text.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/script.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/scripts/script.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/tmux_launch.sh +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/tmux_split.sh +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/examples/unicode_commands.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/mkdocs.yml +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/package.json +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/scripts/validate_tag.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/setup.cfg +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/.cmd2rc +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/__init__.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/conftest.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/echo.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/environment.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/help.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/py_locals.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/pyscript_dir.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/raises_exception.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/recursive.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/self_in_py.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/stop.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/pyscript/test_print.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/relative_multiple.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/script.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/script.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/binary.bin +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/empty.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/help.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/nested.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/one_down.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/postcmds.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/precmds.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/scripts/utf8.txt +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_argparse.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_argparse_completer.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_argparse_subcommands.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_argparse_utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_categories.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_commandset.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_completion.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_dynamic_complete_style.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_future_annotations.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_history.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_parsing.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_plugin.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_pt_utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_py_completion.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_rich_utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_run_pyscript.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_string_utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_theme.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_utils.py +0 -0
- {cmd2-4.2.0 → cmd2-4.2.2}/tests/test_utils_defining_class.py +0 -0
|
@@ -14,7 +14,7 @@ repos:
|
|
|
14
14
|
- id: trailing-whitespace
|
|
15
15
|
|
|
16
16
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
17
|
-
rev: "v0.16.
|
|
17
|
+
rev: "v0.16.3"
|
|
18
18
|
hooks:
|
|
19
19
|
- id: ruff-format
|
|
20
20
|
args: [--config=ruff.toml]
|
|
@@ -30,7 +30,7 @@ repos:
|
|
|
30
30
|
- prettier-plugin-toml@2.0.6
|
|
31
31
|
|
|
32
32
|
- repo: https://github.com/crate-ci/typos
|
|
33
|
-
rev: v1.
|
|
33
|
+
rev: v1.49.0
|
|
34
34
|
hooks:
|
|
35
35
|
- id: typos
|
|
36
36
|
exclude: |
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 4.2.2 (August 25, 2026)
|
|
2
|
+
|
|
3
|
+
- Documentation Improvements
|
|
4
|
+
- Improved documentation in attempt at making some recommended best-practices more discoverable
|
|
5
|
+
- Fixed the broken `cmd_as_argument` example
|
|
6
|
+
|
|
7
|
+
## 4.2.1 (August 22, 2026)
|
|
8
|
+
|
|
9
|
+
- Enhancements
|
|
10
|
+
- Added bracketed paste support so multiple pasted commands execute sequentially and multiline
|
|
11
|
+
commands continue as expected.
|
|
12
|
+
- Bug Fixes
|
|
13
|
+
- Enabled Ctrl-Z suspension at the prompt
|
|
14
|
+
|
|
1
15
|
## 4.2.0 (August 6, 2026)
|
|
2
16
|
|
|
3
17
|
- Enhancements
|
|
@@ -1886,7 +1900,7 @@ time reading the [rich documentation](https://rich.readthedocs.io/).
|
|
|
1886
1900
|
- **with_argument_list** decorator to change argument type from str to List[str]
|
|
1887
1901
|
- **do\_\*** commands get a single argument which is a list of strings, as pre-parsed by
|
|
1888
1902
|
shlex.split()
|
|
1889
|
-
- **
|
|
1903
|
+
- **with_argparser** decorator for strict argparse-based argument parsing of command
|
|
1890
1904
|
arguments
|
|
1891
1905
|
- **do\_\*** commands get a single argument which is the output of argparse.parse_args()
|
|
1892
1906
|
- **with_argparser_and_unknown_args** decorator for argparse-based argument parsing, but
|
|
@@ -18,8 +18,8 @@ check: ## Run code quality tools.
|
|
|
18
18
|
@uv lock --locked
|
|
19
19
|
@echo "🚀 Auto-formatting/Linting code and documentation: Running prek"
|
|
20
20
|
@uv run prek run -a
|
|
21
|
-
@echo "🚀 Static type checking: Running
|
|
22
|
-
@uv run
|
|
21
|
+
@echo "🚀 Static type checking: Running ty"
|
|
22
|
+
@uv run ty check
|
|
23
23
|
|
|
24
24
|
.PHONY: format
|
|
25
25
|
format: ## Perform ruff formatting
|
|
@@ -31,7 +31,7 @@ lint: ## Perform ruff linting
|
|
|
31
31
|
|
|
32
32
|
.PHONY: typecheck
|
|
33
33
|
typecheck: ## Perform type checking
|
|
34
|
-
@uv run
|
|
34
|
+
@uv run ty check
|
|
35
35
|
|
|
36
36
|
.PHONY: test
|
|
37
37
|
test: ## Test the code with pytest.
|
|
@@ -76,7 +76,7 @@ publish: validate-tag build ## Publish a release to PyPI, uses token from ~/.pyp
|
|
|
76
76
|
# Define variables for files/directories to clean
|
|
77
77
|
BUILD_DIRS = build dist *.egg-info
|
|
78
78
|
DOC_DIRS = build
|
|
79
|
-
|
|
79
|
+
TY_DIRS = .ty_cache .red_knot_cache
|
|
80
80
|
TEST_DIRS = .cache .pytest_cache htmlcov
|
|
81
81
|
TEST_FILES = .coverage coverage.xml
|
|
82
82
|
|
|
@@ -90,10 +90,10 @@ clean-docs: ## Clean documentation artifacts
|
|
|
90
90
|
@echo "🚀 Removing documentation artifacts"
|
|
91
91
|
@uv run python -c "import shutil; import os; [shutil.rmtree(d, ignore_errors=True) for d in '$(DOC_DIRS)'.split() if os.path.isdir(d)]"
|
|
92
92
|
|
|
93
|
-
.PHONY: clean-
|
|
94
|
-
clean-
|
|
95
|
-
@echo "🚀 Removing
|
|
96
|
-
@uv run python -c "import shutil; import os; [shutil.rmtree(d, ignore_errors=True) for d in '$(
|
|
93
|
+
.PHONY: clean-ty
|
|
94
|
+
clean-ty: ## Clean ty artifacts
|
|
95
|
+
@echo "🚀 Removing ty artifacts"
|
|
96
|
+
@uv run python -c "import shutil; import os; [shutil.rmtree(d, ignore_errors=True) for d in '$(TY_DIRS)'.split() if os.path.isdir(d)]"
|
|
97
97
|
|
|
98
98
|
.PHONY: clean-pycache
|
|
99
99
|
clean-pycache: ## Clean pycache artifacts
|
|
@@ -112,7 +112,7 @@ clean-test: ## Clean test artifacts
|
|
|
112
112
|
@uv run python -c "from pathlib import Path; [Path(f).unlink(missing_ok=True) for f in '$(TEST_FILES)'.split()]"
|
|
113
113
|
|
|
114
114
|
.PHONY: clean
|
|
115
|
-
clean: clean-build clean-docs clean-
|
|
115
|
+
clean: clean-build clean-docs clean-ty clean-pycache clean-ruff clean-test ## Clean all artifacts
|
|
116
116
|
@echo "🚀 Cleaned all artifacts"
|
|
117
117
|
|
|
118
118
|
.PHONY: help
|
|
@@ -708,10 +708,10 @@ class _CollectionCastingAction(argparse._StoreAction):
|
|
|
708
708
|
|
|
709
709
|
def __call__(
|
|
710
710
|
self,
|
|
711
|
-
|
|
711
|
+
parser: argparse.ArgumentParser, # noqa: ARG002
|
|
712
712
|
namespace: argparse.Namespace,
|
|
713
713
|
values: Any,
|
|
714
|
-
|
|
714
|
+
option_string: str | None = None, # noqa: ARG002
|
|
715
715
|
) -> None:
|
|
716
716
|
result = values
|
|
717
717
|
if self._container_factory is not None and isinstance(values, list):
|
|
@@ -879,7 +879,7 @@ def _resolve_union(
|
|
|
879
879
|
raise TypeError(f"Union type {type_names} is ambiguous for auto-resolution.")
|
|
880
880
|
|
|
881
881
|
parts = [_resolve_base_type(member, allow_unknown_entry=allow_unknown_entry) for member in non_none]
|
|
882
|
-
# Every part is an Enum (guarded above), so each has a converter; the None-filter keeps
|
|
882
|
+
# Every part is an Enum (guarded above), so each has a converter; the None-filter keeps the type checker happy.
|
|
883
883
|
converters = [part.converter for part in parts if part.converter is not None]
|
|
884
884
|
choices = _dedupe_choices(choice for part in parts for choice in (part.choices or []))
|
|
885
885
|
|
|
@@ -2189,7 +2189,7 @@ def _find_argument_block(hint: Any) -> type[ArgumentBlock] | None:
|
|
|
2189
2189
|
return None
|
|
2190
2190
|
|
|
2191
2191
|
|
|
2192
|
-
def _init_field_names(dc_type:
|
|
2192
|
+
def _init_field_names(dc_type: Any) -> list[str]:
|
|
2193
2193
|
"""Names of a dataclass's ``init`` fields in definition order (the flat argument names of a block)."""
|
|
2194
2194
|
return [f.name for f in fields(dc_type) if f.init]
|
|
2195
2195
|
|
|
@@ -3113,6 +3113,9 @@ def with_annotated(
|
|
|
3113
3113
|
except SystemExit as exc:
|
|
3114
3114
|
raise Cmd2ArgparseError from exc
|
|
3115
3115
|
|
|
3116
|
+
if ns is None:
|
|
3117
|
+
raise ValueError("ns is None")
|
|
3118
|
+
|
|
3116
3119
|
setattr(ns, constants.NS_ATTR_STATEMENT, statement)
|
|
3117
3120
|
handler = getattr(ns, constants.NS_ATTR_SUBCOMMAND_FUNC, None)
|
|
3118
3121
|
if base_command and handler is not None:
|
|
@@ -747,8 +747,8 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
747
747
|
super().__init__(
|
|
748
748
|
prog=prog,
|
|
749
749
|
usage=usage,
|
|
750
|
-
description=description, # type: ignore[arg-type]
|
|
751
|
-
epilog=epilog, # type: ignore[arg-type]
|
|
750
|
+
description=description, # type: ignore[arg-type, ty:invalid-argument-type]
|
|
751
|
+
epilog=epilog, # type: ignore[arg-type, ty:invalid-argument-type]
|
|
752
752
|
parents=parents,
|
|
753
753
|
formatter_class=formatter_class,
|
|
754
754
|
prefix_chars=prefix_chars,
|
|
@@ -772,7 +772,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
772
772
|
self.description: HelpContent | None # type: ignore[assignment]
|
|
773
773
|
self.epilog: HelpContent | None # type: ignore[assignment]
|
|
774
774
|
|
|
775
|
-
def print_usage(self, file: IO[str] | None = None) -> None: # type:ignore[override]
|
|
775
|
+
def print_usage(self, file: IO[str] | None = None) -> None: # type: ignore[override, ty:invalid-method-override]
|
|
776
776
|
"""Override to ensure the formatter is aware of the target file."""
|
|
777
777
|
if file is None:
|
|
778
778
|
file = self._thread_locals.current_output_file
|
|
@@ -780,7 +780,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
780
780
|
with self.output_to(file):
|
|
781
781
|
super().print_usage(file)
|
|
782
782
|
|
|
783
|
-
def print_help(self, file: IO[str] | None = None) -> None: # type:ignore[override]
|
|
783
|
+
def print_help(self, file: IO[str] | None = None) -> None: # type: ignore[override, ty:invalid-method-override]
|
|
784
784
|
"""Override to ensure the formatter is aware of the target file."""
|
|
785
785
|
if file is None:
|
|
786
786
|
file = self._thread_locals.current_output_file
|
|
@@ -831,7 +831,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
831
831
|
temp_parser = Cmd2ArgumentParser(
|
|
832
832
|
prog=self.prog,
|
|
833
833
|
usage=None,
|
|
834
|
-
formatter_class=self.formatter_class,
|
|
834
|
+
formatter_class=cast(type[Cmd2HelpFormatter], self.formatter_class),
|
|
835
835
|
add_help=False,
|
|
836
836
|
)
|
|
837
837
|
|
|
@@ -1037,7 +1037,8 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
|
|
|
1037
1037
|
|
|
1038
1038
|
def _get_formatter(self, *_args: Any, **_kwargs: Any) -> Cmd2HelpFormatter:
|
|
1039
1039
|
"""Override with customizations for Cmd2HelpFormatter."""
|
|
1040
|
-
|
|
1040
|
+
formatter_class = cast(type[Cmd2HelpFormatter], self.formatter_class)
|
|
1041
|
+
return formatter_class(prog=self.prog, file=self._thread_locals.current_output_file)
|
|
1041
1042
|
|
|
1042
1043
|
def format_help(self, *args: Any, **kwargs: Any) -> str:
|
|
1043
1044
|
"""Override to add a newline."""
|
|
@@ -78,6 +78,8 @@ from prompt_toolkit.formatted_text import ANSI, AnyFormattedText
|
|
|
78
78
|
from prompt_toolkit.history import InMemoryHistory
|
|
79
79
|
from prompt_toolkit.input import DummyInput, create_input
|
|
80
80
|
from prompt_toolkit.key_binding import KeyBindings
|
|
81
|
+
from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent
|
|
82
|
+
from prompt_toolkit.keys import Keys
|
|
81
83
|
from prompt_toolkit.output import DummyOutput, create_output
|
|
82
84
|
from prompt_toolkit.patch_stdout import patch_stdout
|
|
83
85
|
from prompt_toolkit.shortcuts import CompleteStyle, PromptSession, choice, set_title
|
|
@@ -740,6 +742,50 @@ class Cmd:
|
|
|
740
742
|
# No macro found or already processed. The statement is complete.
|
|
741
743
|
return False
|
|
742
744
|
|
|
745
|
+
def _create_key_bindings(self, completekey: str) -> KeyBindings:
|
|
746
|
+
"""Create and configure custom key bindings for the PromptSession."""
|
|
747
|
+
key_bindings = KeyBindings()
|
|
748
|
+
|
|
749
|
+
if completekey != self.DEFAULT_COMPLETEKEY:
|
|
750
|
+
|
|
751
|
+
@key_bindings.add(completekey)
|
|
752
|
+
def _trigger_completion(event: KeyPressEvent) -> None: # pragma: no cover
|
|
753
|
+
"""Trigger completion using the custom completion key."""
|
|
754
|
+
b = event.current_buffer
|
|
755
|
+
if b.complete_state:
|
|
756
|
+
b.complete_next()
|
|
757
|
+
else:
|
|
758
|
+
b.start_completion(select_first=False)
|
|
759
|
+
|
|
760
|
+
@key_bindings.add("enter", filter=filters.completion_is_selected)
|
|
761
|
+
def _accept_completion(event: KeyPressEvent) -> None: # pragma: no cover
|
|
762
|
+
"""Accept a selected completion on Enter without submitting the command."""
|
|
763
|
+
event.current_buffer.complete_state = None
|
|
764
|
+
|
|
765
|
+
@key_bindings.add(Keys.BracketedPaste)
|
|
766
|
+
def _handle_bracketed_paste(event: KeyPressEvent) -> None:
|
|
767
|
+
"""Handle bracketed paste by feeding lines as keystrokes separated by Enter.
|
|
768
|
+
|
|
769
|
+
By default, prompt_toolkit inserts pasted text as a single buffer blob.
|
|
770
|
+
Translating newlines into Enter keystrokes allows multiple pasted commands
|
|
771
|
+
to execute sequentially and multiline commands to continue as expected.
|
|
772
|
+
"""
|
|
773
|
+
data = event.data.replace("\r\n", "\n").replace("\r", "\n")
|
|
774
|
+
if "\n" not in data:
|
|
775
|
+
event.current_buffer.insert_text(data)
|
|
776
|
+
return
|
|
777
|
+
|
|
778
|
+
key_presses = []
|
|
779
|
+
for i, line in enumerate(data.split("\n")):
|
|
780
|
+
if i > 0:
|
|
781
|
+
key_presses.append(KeyPress(Keys.ControlM, "\r"))
|
|
782
|
+
if line:
|
|
783
|
+
key_presses.append(KeyPress(Keys.Any, line))
|
|
784
|
+
|
|
785
|
+
event.key_processor.feed_multiple(key_presses)
|
|
786
|
+
|
|
787
|
+
return key_bindings
|
|
788
|
+
|
|
743
789
|
def _create_main_session(
|
|
744
790
|
self,
|
|
745
791
|
*,
|
|
@@ -756,26 +802,6 @@ class Cmd:
|
|
|
756
802
|
Otherwise, uses dummy drivers to support non-interactive streams like
|
|
757
803
|
pipes or files.
|
|
758
804
|
"""
|
|
759
|
-
# Configure custom key bindings
|
|
760
|
-
key_bindings = KeyBindings()
|
|
761
|
-
|
|
762
|
-
# Add a binding for 'enter' that triggers only when a completion is selected.
|
|
763
|
-
# This allows accepting a completion without submitting the command.
|
|
764
|
-
@key_bindings.add("enter", filter=filters.completion_is_selected)
|
|
765
|
-
def _(event: Any) -> None: # pragma: no cover
|
|
766
|
-
event.current_buffer.complete_state = None
|
|
767
|
-
|
|
768
|
-
if completekey != self.DEFAULT_COMPLETEKEY:
|
|
769
|
-
# Configure prompt_toolkit `KeyBindings` with the custom key for completion
|
|
770
|
-
@key_bindings.add(completekey)
|
|
771
|
-
def _(event: Any) -> None: # pragma: no cover
|
|
772
|
-
"""Trigger completion."""
|
|
773
|
-
b = event.current_buffer
|
|
774
|
-
if b.complete_state:
|
|
775
|
-
b.complete_next()
|
|
776
|
-
else:
|
|
777
|
-
b.start_completion(select_first=False)
|
|
778
|
-
|
|
779
805
|
# Base configuration
|
|
780
806
|
kwargs: dict[str, Any] = {
|
|
781
807
|
"auto_suggest": AutoSuggestFromHistory() if auto_suggest else None,
|
|
@@ -785,8 +811,9 @@ class Cmd:
|
|
|
785
811
|
"complete_in_thread": complete_in_thread,
|
|
786
812
|
"complete_while_typing": False,
|
|
787
813
|
"completer": Cmd2Completer(self),
|
|
814
|
+
"enable_suspend": True,
|
|
788
815
|
"history": Cmd2History(item.raw for item in self.history),
|
|
789
|
-
"key_bindings":
|
|
816
|
+
"key_bindings": self._create_key_bindings(completekey),
|
|
790
817
|
"lexer": Cmd2Lexer(self),
|
|
791
818
|
"multiline": filters.Condition(self._should_continue_multiline),
|
|
792
819
|
"prompt_continuation": self.continuation_prompt,
|
|
@@ -849,7 +876,7 @@ class Cmd:
|
|
|
849
876
|
all_commandset_defs = CommandSet.__subclasses__()
|
|
850
877
|
existing_commandset_types = [type(command_set) for command_set in self._installed_command_sets]
|
|
851
878
|
|
|
852
|
-
def load_commandset_by_type(commandset_types:
|
|
879
|
+
def load_commandset_by_type(commandset_types: Sequence[type[CommandSet[Any]]]) -> None:
|
|
853
880
|
for cmdset_type in commandset_types:
|
|
854
881
|
# check if the type has sub-classes. We will only auto-load leaf class types.
|
|
855
882
|
subclasses = cmdset_type.__subclasses__()
|
|
@@ -2547,11 +2574,11 @@ class Cmd:
|
|
|
2547
2574
|
completer.complete, tokens=raw_tokens[1:] if spec.preserve_quotes else tokens[1:], cmd_set=cmd_set
|
|
2548
2575
|
)
|
|
2549
2576
|
else:
|
|
2550
|
-
completer_func = self.completedefault # type: ignore[assignment]
|
|
2577
|
+
completer_func = self.completedefault # type: ignore[assignment, ty:invalid-assignment]
|
|
2551
2578
|
|
|
2552
2579
|
# Not a recognized macro or command
|
|
2553
2580
|
else:
|
|
2554
|
-
completer_func = self.completedefault # type: ignore[assignment]
|
|
2581
|
+
completer_func = self.completedefault # type: ignore[assignment, ty:invalid-assignment]
|
|
2555
2582
|
|
|
2556
2583
|
# Otherwise we are completing the command token or performing custom completion
|
|
2557
2584
|
else:
|
|
@@ -2968,7 +2995,7 @@ class Cmd:
|
|
|
2968
2995
|
with self.sigint_protection:
|
|
2969
2996
|
if py_bridge_call:
|
|
2970
2997
|
# Start saving command's stdout at this point
|
|
2971
|
-
self.stdout.pause_storage = False # type: ignore[attr-defined]
|
|
2998
|
+
self.stdout.pause_storage = False # type: ignore[attr-defined, ty:invalid-assignment]
|
|
2972
2999
|
|
|
2973
3000
|
redir_saved_state = self._redirect_output(statement)
|
|
2974
3001
|
|
|
@@ -3007,7 +3034,7 @@ class Cmd:
|
|
|
3007
3034
|
|
|
3008
3035
|
if py_bridge_call:
|
|
3009
3036
|
# Stop saving command's stdout before command finalization hooks run
|
|
3010
|
-
self.stdout.pause_storage = True # type: ignore[attr-defined]
|
|
3037
|
+
self.stdout.pause_storage = True # type: ignore[attr-defined, ty:invalid-assignment]
|
|
3011
3038
|
except (SkipPostcommandHooks, EmptyStatement):
|
|
3012
3039
|
# Don't do anything, but do allow command finalization hooks to run
|
|
3013
3040
|
pass
|
|
@@ -3512,7 +3539,7 @@ class Cmd:
|
|
|
3512
3539
|
self.active_session = self.main_session
|
|
3513
3540
|
|
|
3514
3541
|
# We're not at a terminal, so we're likely reading from a file or a pipe.
|
|
3515
|
-
prompt_obj = prompt
|
|
3542
|
+
prompt_obj = prompt if isinstance(prompt, (ANSI, str)) else prompt()
|
|
3516
3543
|
prompt_str = prompt_obj.value if isinstance(prompt_obj, ANSI) else prompt_obj
|
|
3517
3544
|
|
|
3518
3545
|
# If this is an interactive pipe, then display the prompt first
|
|
@@ -3613,6 +3640,7 @@ class Cmd:
|
|
|
3613
3640
|
complete_in_thread=self.main_session.complete_in_thread,
|
|
3614
3641
|
complete_while_typing=self.main_session.complete_while_typing,
|
|
3615
3642
|
completer=completer_to_use,
|
|
3643
|
+
enable_suspend=self.main_session.enable_suspend,
|
|
3616
3644
|
history=InMemoryHistory(history) if history is not None else InMemoryHistory(),
|
|
3617
3645
|
key_bindings=self.main_session.key_bindings,
|
|
3618
3646
|
input=self.main_session.input,
|
|
@@ -3635,6 +3663,7 @@ class Cmd:
|
|
|
3635
3663
|
"""
|
|
3636
3664
|
temp_session: PromptSession[str] = PromptSession(
|
|
3637
3665
|
color_depth=self.main_session.color_depth,
|
|
3666
|
+
enable_suspend=self.main_session.enable_suspend,
|
|
3638
3667
|
input=self.main_session.input,
|
|
3639
3668
|
output=self.main_session.output,
|
|
3640
3669
|
style=self.main_session.style,
|
|
@@ -3800,7 +3829,7 @@ class Cmd:
|
|
|
3800
3829
|
"An alias is a command that enables replacement of a word by another string.",
|
|
3801
3830
|
)
|
|
3802
3831
|
alias_parser = argparse_utils.DEFAULT_ARGUMENT_PARSER(description=alias_description)
|
|
3803
|
-
alias_parser.epilog = TextGroup(
|
|
3832
|
+
alias_parser.epilog = TextGroup( # type: ignore[assignment, ty:invalid-assignment]
|
|
3804
3833
|
"See Also",
|
|
3805
3834
|
"macro",
|
|
3806
3835
|
)
|
|
@@ -3832,7 +3861,7 @@ class Cmd:
|
|
|
3832
3861
|
"for the actual command the alias resolves to."
|
|
3833
3862
|
),
|
|
3834
3863
|
)
|
|
3835
|
-
alias_create_parser.epilog = TextGroup("Notes", alias_create_notes)
|
|
3864
|
+
alias_create_parser.epilog = TextGroup("Notes", alias_create_notes) # type: ignore[assignment, ty:invalid-assignment]
|
|
3836
3865
|
|
|
3837
3866
|
# Add arguments
|
|
3838
3867
|
alias_create_parser.add_argument("name", help="name of this alias")
|
|
@@ -4014,7 +4043,7 @@ class Cmd:
|
|
|
4014
4043
|
"A macro is similar to an alias, but it can contain argument placeholders.",
|
|
4015
4044
|
)
|
|
4016
4045
|
macro_parser = argparse_utils.DEFAULT_ARGUMENT_PARSER(description=macro_description)
|
|
4017
|
-
macro_parser.epilog = TextGroup(
|
|
4046
|
+
macro_parser.epilog = TextGroup( # type: ignore[assignment, ty:invalid-assignment]
|
|
4018
4047
|
"See Also",
|
|
4019
4048
|
"alias",
|
|
4020
4049
|
)
|
|
@@ -4077,7 +4106,7 @@ class Cmd:
|
|
|
4077
4106
|
"This default behavior changes if custom completion for macro arguments has been implemented."
|
|
4078
4107
|
),
|
|
4079
4108
|
)
|
|
4080
|
-
macro_create_parser.epilog = TextGroup("Notes", macro_create_notes)
|
|
4109
|
+
macro_create_parser.epilog = TextGroup("Notes", macro_create_notes) # type: ignore[assignment, ty:invalid-assignment]
|
|
4081
4110
|
|
|
4082
4111
|
# Add arguments
|
|
4083
4112
|
macro_create_parser.add_argument("name", help="name of this macro")
|
|
@@ -4572,7 +4601,7 @@ class Cmd:
|
|
|
4572
4601
|
@staticmethod
|
|
4573
4602
|
def _build__eof_parser() -> Cmd2ArgumentParser:
|
|
4574
4603
|
_eof_parser = argparse_utils.DEFAULT_ARGUMENT_PARSER(description="Called when Ctrl-D is pressed.")
|
|
4575
|
-
_eof_parser.epilog = TextGroup(
|
|
4604
|
+
_eof_parser.epilog = TextGroup( # type: ignore[assignment, ty:invalid-assignment]
|
|
4576
4605
|
"Note",
|
|
4577
4606
|
"This command is for internal use and is not intended to be called from the command line.",
|
|
4578
4607
|
)
|
|
@@ -5032,7 +5061,7 @@ class Cmd:
|
|
|
5032
5061
|
# Check if we are running Python code
|
|
5033
5062
|
if py_code_to_run:
|
|
5034
5063
|
try: # noqa: SIM105
|
|
5035
|
-
interp.runcode(py_code_to_run) # type: ignore[arg-type]
|
|
5064
|
+
interp.runcode(py_code_to_run) # type: ignore[arg-type, ty:invalid-argument-type]
|
|
5036
5065
|
except BaseException: # noqa: BLE001, S110
|
|
5037
5066
|
# We don't care about any exception that happened in the Python code
|
|
5038
5067
|
pass
|
|
@@ -5418,11 +5447,11 @@ class Cmd:
|
|
|
5418
5447
|
try:
|
|
5419
5448
|
import lzma as decompress_lib
|
|
5420
5449
|
|
|
5421
|
-
decompress_exceptions: tuple[type[Exception]] = (decompress_lib.LZMAError,)
|
|
5450
|
+
decompress_exceptions: tuple[type[Exception], ...] = (decompress_lib.LZMAError,)
|
|
5422
5451
|
except ModuleNotFoundError: # pragma: no cover
|
|
5423
5452
|
import bz2 as decompress_lib # type: ignore[no-redef]
|
|
5424
5453
|
|
|
5425
|
-
decompress_exceptions: tuple[type[Exception]] = (OSError, ValueError) # type: ignore[no-redef]
|
|
5454
|
+
decompress_exceptions: tuple[type[Exception], ...] = (OSError, ValueError) # type: ignore[no-redef]
|
|
5426
5455
|
|
|
5427
5456
|
try:
|
|
5428
5457
|
history_json = decompress_lib.decompress(compressed_bytes).decode(encoding="utf-8")
|
|
@@ -5471,7 +5500,7 @@ class Cmd:
|
|
|
5471
5500
|
def _build_edit_parser(cls) -> Cmd2ArgumentParser:
|
|
5472
5501
|
edit_description = "Run a text editor and optionally open a file with it."
|
|
5473
5502
|
edit_parser = argparse_utils.DEFAULT_ARGUMENT_PARSER(description=edit_description)
|
|
5474
|
-
edit_parser.epilog = TextGroup(
|
|
5503
|
+
edit_parser.epilog = TextGroup( # type: ignore[assignment, ty:invalid-assignment]
|
|
5475
5504
|
"Note",
|
|
5476
5505
|
Text.assemble(
|
|
5477
5506
|
"To set a new editor, run: ",
|
|
@@ -5593,7 +5622,7 @@ class Cmd:
|
|
|
5593
5622
|
_relative_run_script_parser = cls._build_base_run_script_parser()
|
|
5594
5623
|
|
|
5595
5624
|
# Append to existing description
|
|
5596
|
-
_relative_run_script_parser.description = Group(
|
|
5625
|
+
_relative_run_script_parser.description = Group( # type: ignore[assignment, ty:invalid-assignment]
|
|
5597
5626
|
cast(Group, _relative_run_script_parser.description),
|
|
5598
5627
|
"\n",
|
|
5599
5628
|
(
|
|
@@ -5602,7 +5631,7 @@ class Cmd:
|
|
|
5602
5631
|
),
|
|
5603
5632
|
)
|
|
5604
5633
|
|
|
5605
|
-
_relative_run_script_parser.epilog = TextGroup(
|
|
5634
|
+
_relative_run_script_parser.epilog = TextGroup( # type: ignore[assignment, ty:invalid-assignment]
|
|
5606
5635
|
"Note",
|
|
5607
5636
|
"This command is intended to be used from within a text script.",
|
|
5608
5637
|
)
|
|
@@ -310,7 +310,7 @@ def with_argparser(
|
|
|
310
310
|
:return: Function that takes raw input and converts to an argparse Namespace to passed to the wrapped function.
|
|
311
311
|
"""
|
|
312
312
|
|
|
313
|
-
@functools.wraps(func)
|
|
313
|
+
@functools.wraps(func) # type: ignore[arg-type, ty:invalid-argument-type]
|
|
314
314
|
def cmd_wrapper(*args: Any, **kwargs: Any) -> bool | None:
|
|
315
315
|
"""Command function wrapper which translates command line into argparse Namespace and call actual command function.
|
|
316
316
|
|
|
@@ -345,9 +345,9 @@ def with_argparser(
|
|
|
345
345
|
parsing_results: tuple[argparse.Namespace] | tuple[argparse.Namespace, list[str]]
|
|
346
346
|
with arg_parser.output_to(cmd_app.stdout):
|
|
347
347
|
if with_unknown_args:
|
|
348
|
-
parsing_results = arg_parser.parse_known_args(command_arg_list, initial_namespace)
|
|
348
|
+
parsing_results = arg_parser.parse_known_args(command_arg_list, initial_namespace) # type: ignore[assignment, ty:invalid-assignment]
|
|
349
349
|
else:
|
|
350
|
-
parsing_results = (arg_parser.parse_args(command_arg_list, initial_namespace),)
|
|
350
|
+
parsing_results = (arg_parser.parse_args(command_arg_list, initial_namespace),) # type: ignore[assignment, ty:invalid-assignment]
|
|
351
351
|
except SystemExit as exc:
|
|
352
352
|
raise Cmd2ArgparseError from exc
|
|
353
353
|
|
|
@@ -248,7 +248,7 @@ class PartialStatement:
|
|
|
248
248
|
|
|
249
249
|
Note:
|
|
250
250
|
Unlike [cmd2.parsing.Statement][], this is a simple data object
|
|
251
|
-
and does not inherit from
|
|
251
|
+
and does not inherit from `str`.
|
|
252
252
|
|
|
253
253
|
"""
|
|
254
254
|
|
|
@@ -552,7 +552,7 @@ class StatementParser:
|
|
|
552
552
|
def parse_command_only(self, rawinput: str) -> PartialStatement:
|
|
553
553
|
"""Identify the command and arguments from raw input.
|
|
554
554
|
|
|
555
|
-
Partially parse input into a [cmd2.PartialStatement][] object.
|
|
555
|
+
Partially parse input into a [cmd2.parsing.PartialStatement][] object.
|
|
556
556
|
|
|
557
557
|
The command is identified, and shortcuts and aliases are expanded.
|
|
558
558
|
Multiline commands are identified, but terminators and output
|
|
@@ -561,7 +561,7 @@ class StatementParser:
|
|
|
561
561
|
This method is optimized for completion code and gracefully handles
|
|
562
562
|
unclosed quotes without raising exceptions.
|
|
563
563
|
|
|
564
|
-
|
|
564
|
+
`cmd2.parsing.PartialStatement.args` will include all output redirection
|
|
565
565
|
clauses and command terminators.
|
|
566
566
|
|
|
567
567
|
Note:
|
|
@@ -571,7 +571,7 @@ class StatementParser:
|
|
|
571
571
|
whitespace only if all quotes are closed.
|
|
572
572
|
|
|
573
573
|
:param rawinput: the command line as entered by the user
|
|
574
|
-
:return: a
|
|
574
|
+
:return: a `PartialStatement` object representing the split input
|
|
575
575
|
|
|
576
576
|
"""
|
|
577
577
|
# Expand shortcuts and aliases
|
|
@@ -148,7 +148,7 @@ class Cmd2Completer(Completer):
|
|
|
148
148
|
self._cmd_app = cmd_app
|
|
149
149
|
self.custom_settings = custom_settings
|
|
150
150
|
|
|
151
|
-
def get_completions(self, document: Document,
|
|
151
|
+
def get_completions(self, document: Document, complete_event: object) -> Iterable[Completion]: # noqa: ARG002
|
|
152
152
|
"""Get completions for the current input."""
|
|
153
153
|
# Find the beginning of the current word based on delimiters
|
|
154
154
|
line = document.text
|
|
@@ -14,6 +14,7 @@ mkdocs.yml
|
|
|
14
14
|
package.json
|
|
15
15
|
pyproject.toml
|
|
16
16
|
ruff.toml
|
|
17
|
+
ty.toml
|
|
17
18
|
cmd2/__init__.py
|
|
18
19
|
cmd2/annotated.py
|
|
19
20
|
cmd2/argparse_completer.py
|
|
@@ -128,6 +129,7 @@ examples/async_call.py
|
|
|
128
129
|
examples/async_commands.py
|
|
129
130
|
examples/async_printing.py
|
|
130
131
|
examples/basic_completion.py
|
|
132
|
+
examples/cmd2_history.dat
|
|
131
133
|
examples/cmd_as_argument.py
|
|
132
134
|
examples/color.py
|
|
133
135
|
examples/command_sets.py
|