cmd2 4.2.3__tar.gz → 4.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. {cmd2-4.2.3 → cmd2-4.3.0}/.pre-commit-config.yaml +2 -2
  2. {cmd2-4.2.3 → cmd2-4.3.0}/.prettierrc +1 -0
  3. {cmd2-4.2.3 → cmd2-4.3.0}/AGENTS.md +2 -0
  4. {cmd2-4.2.3 → cmd2-4.3.0}/CHANGELOG.md +44 -0
  5. cmd2-4.3.0/CLAUDE.md +126 -0
  6. {cmd2-4.2.3 → cmd2-4.3.0}/GEMINI.md +2 -0
  7. {cmd2-4.2.3 → cmd2-4.3.0}/Makefile +3 -3
  8. {cmd2-4.2.3 → cmd2-4.3.0}/PKG-INFO +9 -3
  9. {cmd2-4.2.3 → cmd2-4.3.0}/README.md +8 -2
  10. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/annotated.py +13 -14
  11. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/argparse_completer.py +6 -6
  12. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/argparse_utils.py +18 -18
  13. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/cmd2.py +274 -106
  14. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/decorators.py +3 -3
  15. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/rich_utils.py +10 -12
  16. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/types.py +7 -4
  17. cmd2-4.3.0/cmd2/utils.py +1643 -0
  18. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2.egg-info/PKG-INFO +9 -3
  19. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2.egg-info/SOURCES.txt +5 -0
  20. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2.egg-info/scm_file_list.json +4 -1
  21. cmd2-4.3.0/cmd2.egg-info/scm_version.json +8 -0
  22. cmd2-4.3.0/docs/.DS_Store +0 -0
  23. cmd2-4.3.0/docs/assets/cmd2-logo.png +0 -0
  24. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/annotated.md +2 -27
  25. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/argument_processing.md +1 -5
  26. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/redirection.md +4 -0
  27. {cmd2-4.2.3 → cmd2-4.3.0}/docs/testing.md +22 -0
  28. {cmd2-4.2.3 → cmd2-4.3.0}/examples/annotated_example.py +4 -4
  29. cmd2-4.3.0/examples/cmd2_history.dat +0 -0
  30. {cmd2-4.2.3 → cmd2-4.3.0}/examples/getting_started.py +4 -4
  31. {cmd2-4.2.3 → cmd2-4.3.0}/mkdocs.yml +2 -1
  32. {cmd2-4.2.3 → cmd2-4.3.0}/pyproject.toml +32 -4
  33. {cmd2-4.2.3 → cmd2-4.3.0}/tests/conftest.py +49 -0
  34. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_annotated.py +8 -8
  35. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_cmd2.py +552 -31
  36. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_history.py +13 -12
  37. cmd2-4.3.0/tests/test_pipeline_job_control.py +1381 -0
  38. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_run_pyscript.py +1 -1
  39. cmd2-4.3.0/tests/test_suite_environment.py +122 -0
  40. cmd2-4.3.0/tests/test_utils.py +1978 -0
  41. cmd2-4.3.0/ty.toml +9 -0
  42. cmd2-4.2.3/cmd2/utils.py +0 -858
  43. cmd2-4.2.3/cmd2.egg-info/scm_version.json +0 -8
  44. cmd2-4.2.3/examples/cmd2_history.dat +0 -0
  45. cmd2-4.2.3/tests/test_utils.py +0 -435
  46. cmd2-4.2.3/ty.toml +0 -7
  47. {cmd2-4.2.3 → cmd2-4.3.0}/.prettierignore +0 -0
  48. {cmd2-4.2.3 → cmd2-4.3.0}/.typos.toml +0 -0
  49. {cmd2-4.2.3 → cmd2-4.3.0}/LICENSE +0 -0
  50. {cmd2-4.2.3 → cmd2-4.3.0}/MANIFEST.in +0 -0
  51. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/__init__.py +0 -0
  52. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/clipboard.py +0 -0
  53. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/colors.py +0 -0
  54. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/command_set.py +0 -0
  55. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/completion.py +0 -0
  56. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/constants.py +0 -0
  57. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/exceptions.py +0 -0
  58. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/history.py +0 -0
  59. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/parsing.py +0 -0
  60. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/plugin.py +0 -0
  61. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/pt_utils.py +0 -0
  62. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/py.typed +0 -0
  63. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/py_bridge.py +0 -0
  64. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/string_utils.py +0 -0
  65. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/styles.py +0 -0
  66. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2/theme.py +0 -0
  67. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2.egg-info/dependency_links.txt +0 -0
  68. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2.egg-info/requires.txt +0 -0
  69. {cmd2-4.2.3 → cmd2-4.3.0}/cmd2.egg-info/top_level.txt +0 -0
  70. {cmd2-4.2.3 → cmd2-4.3.0}/codecov.yml +0 -0
  71. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/annotated.md +0 -0
  72. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/argparse_completer.md +0 -0
  73. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/argparse_utils.md +0 -0
  74. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/clipboard.md +0 -0
  75. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/cmd.md +0 -0
  76. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/colors.md +0 -0
  77. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/command_set.md +0 -0
  78. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/completion.md +0 -0
  79. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/constants.md +0 -0
  80. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/decorators.md +0 -0
  81. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/exceptions.md +0 -0
  82. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/history.md +0 -0
  83. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/index.md +0 -0
  84. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/parsing.md +0 -0
  85. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/plugin.md +0 -0
  86. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/pt_utils.md +0 -0
  87. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/py_bridge.md +0 -0
  88. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/rich_utils.md +0 -0
  89. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/string_utils.md +0 -0
  90. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/styles.md +0 -0
  91. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/theme.md +0 -0
  92. {cmd2-4.2.3 → cmd2-4.3.0}/docs/api/utils.md +0 -0
  93. {cmd2-4.2.3 → cmd2-4.3.0}/docs/assets/cmd2-readme-demo.gif +0 -0
  94. {cmd2-4.2.3 → cmd2-4.3.0}/docs/assets/getting-started-demo.gif +0 -0
  95. {cmd2-4.2.3 → cmd2-4.3.0}/docs/doc_conventions.md +0 -0
  96. {cmd2-4.2.3 → cmd2-4.3.0}/docs/examples/alternate_event_loops.md +0 -0
  97. {cmd2-4.2.3 → cmd2-4.3.0}/docs/examples/examples.md +0 -0
  98. {cmd2-4.2.3 → cmd2-4.3.0}/docs/examples/getting_started.md +0 -0
  99. {cmd2-4.2.3 → cmd2-4.3.0}/docs/examples/index.md +0 -0
  100. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/async_commands.md +0 -0
  101. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/builtin_commands.md +0 -0
  102. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/clipboard.md +0 -0
  103. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/commands.md +0 -0
  104. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/completion.md +0 -0
  105. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/disable_commands.md +0 -0
  106. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/embedded_python_shells.md +0 -0
  107. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/generating_output.md +0 -0
  108. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/help.md +0 -0
  109. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/history.md +0 -0
  110. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/hooks.md +0 -0
  111. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/index.md +0 -0
  112. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/initialization.md +0 -0
  113. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/misc.md +0 -0
  114. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/modular_commands.md +0 -0
  115. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/multiline_commands.md +0 -0
  116. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/os.md +0 -0
  117. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/packaging.md +0 -0
  118. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/plugins.md +0 -0
  119. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/prompt.md +0 -0
  120. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/scripting.md +0 -0
  121. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/settings.md +0 -0
  122. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/shortcuts_aliases_macros.md +0 -0
  123. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/startup_commands.md +0 -0
  124. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/table_creation.md +0 -0
  125. {cmd2-4.2.3 → cmd2-4.3.0}/docs/features/theme.md +0 -0
  126. {cmd2-4.2.3 → cmd2-4.3.0}/docs/index.md +0 -0
  127. {cmd2-4.2.3 → cmd2-4.3.0}/docs/javascripts/readthedocs.js +0 -0
  128. {cmd2-4.2.3 → cmd2-4.3.0}/docs/migrating/incompatibilities.md +0 -0
  129. {cmd2-4.2.3 → cmd2-4.3.0}/docs/migrating/index.md +0 -0
  130. {cmd2-4.2.3 → cmd2-4.3.0}/docs/migrating/minimum.md +0 -0
  131. {cmd2-4.2.3 → cmd2-4.3.0}/docs/migrating/next_steps.md +0 -0
  132. {cmd2-4.2.3 → cmd2-4.3.0}/docs/migrating/why.md +0 -0
  133. {cmd2-4.2.3 → cmd2-4.3.0}/docs/mixins/index.md +0 -0
  134. {cmd2-4.2.3 → cmd2-4.3.0}/docs/mixins/mixin_template.md +0 -0
  135. {cmd2-4.2.3 → cmd2-4.3.0}/docs/overrides/main.html +0 -0
  136. {cmd2-4.2.3 → cmd2-4.3.0}/docs/overview/alternatives.md +0 -0
  137. {cmd2-4.2.3 → cmd2-4.3.0}/docs/overview/index.md +0 -0
  138. {cmd2-4.2.3 → cmd2-4.3.0}/docs/overview/installation.md +0 -0
  139. {cmd2-4.2.3 → cmd2-4.3.0}/docs/overview/integrating.md +0 -0
  140. {cmd2-4.2.3 → cmd2-4.3.0}/docs/overview/resources.md +0 -0
  141. {cmd2-4.2.3 → cmd2-4.3.0}/docs/stylesheets/cmd2.css +0 -0
  142. {cmd2-4.2.3 → cmd2-4.3.0}/docs/upgrades.md +0 -0
  143. {cmd2-4.2.3 → cmd2-4.3.0}/examples/.cmd2rc +0 -0
  144. {cmd2-4.2.3 → cmd2-4.3.0}/examples/README.md +0 -0
  145. {cmd2-4.2.3 → cmd2-4.3.0}/examples/argparse_completion.py +0 -0
  146. {cmd2-4.2.3 → cmd2-4.3.0}/examples/argparse_example.py +0 -0
  147. {cmd2-4.2.3 → cmd2-4.3.0}/examples/async_call.py +0 -0
  148. {cmd2-4.2.3 → cmd2-4.3.0}/examples/async_commands.py +0 -0
  149. {cmd2-4.2.3 → cmd2-4.3.0}/examples/async_printing.py +0 -0
  150. {cmd2-4.2.3 → cmd2-4.3.0}/examples/basic_completion.py +0 -0
  151. {cmd2-4.2.3 → cmd2-4.3.0}/examples/cmd_as_argument.py +0 -0
  152. {cmd2-4.2.3 → cmd2-4.3.0}/examples/color.py +0 -0
  153. {cmd2-4.2.3 → cmd2-4.3.0}/examples/command_sets.py +0 -0
  154. {cmd2-4.2.3 → cmd2-4.3.0}/examples/completion_item_choices.py +0 -0
  155. {cmd2-4.2.3 → cmd2-4.3.0}/examples/custom_parser.py +0 -0
  156. {cmd2-4.2.3 → cmd2-4.3.0}/examples/custom_types.py +0 -0
  157. {cmd2-4.2.3 → cmd2-4.3.0}/examples/default_categories.py +0 -0
  158. {cmd2-4.2.3 → cmd2-4.3.0}/examples/dynamic_commands.py +0 -0
  159. {cmd2-4.2.3 → cmd2-4.3.0}/examples/environment.py +0 -0
  160. {cmd2-4.2.3 → cmd2-4.3.0}/examples/event_loops.py +0 -0
  161. {cmd2-4.2.3 → cmd2-4.3.0}/examples/exit_code.py +0 -0
  162. {cmd2-4.2.3 → cmd2-4.3.0}/examples/hello_cmd2.py +0 -0
  163. {cmd2-4.2.3 → cmd2-4.3.0}/examples/help_categories.py +0 -0
  164. {cmd2-4.2.3 → cmd2-4.3.0}/examples/hooks.py +0 -0
  165. {cmd2-4.2.3 → cmd2-4.3.0}/examples/migrating.py +0 -0
  166. {cmd2-4.2.3 → cmd2-4.3.0}/examples/mixin.py +0 -0
  167. {cmd2-4.2.3 → cmd2-4.3.0}/examples/modular_commands/__init__.py +0 -0
  168. {cmd2-4.2.3 → cmd2-4.3.0}/examples/modular_commands/commandset_basic.py +0 -0
  169. {cmd2-4.2.3 → cmd2-4.3.0}/examples/modular_commands/commandset_complex.py +0 -0
  170. {cmd2-4.2.3 → cmd2-4.3.0}/examples/modular_commands/commandset_custominit.py +0 -0
  171. {cmd2-4.2.3 → cmd2-4.3.0}/examples/modular_commandsets.py +0 -0
  172. {cmd2-4.2.3 → cmd2-4.3.0}/examples/paged_output.py +0 -0
  173. {cmd2-4.2.3 → cmd2-4.3.0}/examples/persistent_history.py +0 -0
  174. {cmd2-4.2.3 → cmd2-4.3.0}/examples/pretty_print.py +0 -0
  175. {cmd2-4.2.3 → cmd2-4.3.0}/examples/python_scripting.py +0 -0
  176. {cmd2-4.2.3 → cmd2-4.3.0}/examples/read_input.py +0 -0
  177. {cmd2-4.2.3 → cmd2-4.3.0}/examples/remove_builtin_commands.py +0 -0
  178. {cmd2-4.2.3 → cmd2-4.3.0}/examples/remove_settable.py +0 -0
  179. {cmd2-4.2.3 → cmd2-4.3.0}/examples/rich_tables.py +0 -0
  180. {cmd2-4.2.3 → cmd2-4.3.0}/examples/rich_theme.py +0 -0
  181. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/arg_printer.py +0 -0
  182. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/conditional.py +0 -0
  183. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/nested.txt +0 -0
  184. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/quit.txt +0 -0
  185. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/save_help_text.py +0 -0
  186. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/script.py +0 -0
  187. {cmd2-4.2.3 → cmd2-4.3.0}/examples/scripts/script.txt +0 -0
  188. {cmd2-4.2.3 → cmd2-4.3.0}/examples/tmux_launch.sh +0 -0
  189. {cmd2-4.2.3 → cmd2-4.3.0}/examples/tmux_split.sh +0 -0
  190. {cmd2-4.2.3 → cmd2-4.3.0}/examples/unicode_commands.py +0 -0
  191. {cmd2-4.2.3 → cmd2-4.3.0}/package.json +0 -0
  192. {cmd2-4.2.3 → cmd2-4.3.0}/ruff.toml +0 -0
  193. {cmd2-4.2.3 → cmd2-4.3.0}/scripts/validate_tag.py +0 -0
  194. {cmd2-4.2.3 → cmd2-4.3.0}/setup.cfg +0 -0
  195. {cmd2-4.2.3 → cmd2-4.3.0}/tests/.cmd2rc +0 -0
  196. {cmd2-4.2.3 → cmd2-4.3.0}/tests/__init__.py +0 -0
  197. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/echo.py +0 -0
  198. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/environment.py +0 -0
  199. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/help.py +0 -0
  200. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/py_locals.py +0 -0
  201. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/pyscript_dir.py +0 -0
  202. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/raises_exception.py +0 -0
  203. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/recursive.py +0 -0
  204. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/self_in_py.py +0 -0
  205. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/stop.py +0 -0
  206. {cmd2-4.2.3 → cmd2-4.3.0}/tests/pyscript/test_print.py +0 -0
  207. {cmd2-4.2.3 → cmd2-4.3.0}/tests/relative_multiple.txt +0 -0
  208. {cmd2-4.2.3 → cmd2-4.3.0}/tests/script.py +0 -0
  209. {cmd2-4.2.3 → cmd2-4.3.0}/tests/script.txt +0 -0
  210. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/binary.bin +0 -0
  211. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/empty.txt +0 -0
  212. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/help.txt +0 -0
  213. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/nested.txt +0 -0
  214. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/one_down.txt +0 -0
  215. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/postcmds.txt +0 -0
  216. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/precmds.txt +0 -0
  217. {cmd2-4.2.3 → cmd2-4.3.0}/tests/scripts/utf8.txt +0 -0
  218. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_argparse.py +0 -0
  219. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_argparse_completer.py +0 -0
  220. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_argparse_subcommands.py +0 -0
  221. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_argparse_utils.py +0 -0
  222. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_categories.py +0 -0
  223. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_commandset.py +0 -0
  224. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_completion.py +0 -0
  225. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_dynamic_complete_style.py +0 -0
  226. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_future_annotations.py +0 -0
  227. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_parsing.py +0 -0
  228. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_plugin.py +0 -0
  229. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_pt_utils.py +0 -0
  230. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_py_completion.py +0 -0
  231. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_rich_utils.py +0 -0
  232. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_string_utils.py +0 -0
  233. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_theme.py +0 -0
  234. {cmd2-4.2.3 → cmd2-4.3.0}/tests/test_utils_defining_class.py +0 -0
@@ -15,7 +15,7 @@ repos:
15
15
  - id: trailing-whitespace
16
16
 
17
17
  - repo: https://github.com/astral-sh/ruff-pre-commit
18
- rev: "v0.16.5"
18
+ rev: "v0.17.0"
19
19
  hooks:
20
20
  - id: ruff-format
21
21
  args: [--config=ruff.toml]
@@ -31,7 +31,7 @@ repos:
31
31
  - prettier-plugin-toml@2.0.6
32
32
 
33
33
  - repo: https://github.com/crate-ci/typos
34
- rev: v1.50.0
34
+ rev: v1.51.1
35
35
  hooks:
36
36
  - id: typos
37
37
  exclude: |
@@ -1,4 +1,5 @@
1
1
  {
2
+ "endOfLine": "lf",
2
3
  "printWidth": 100,
3
4
  "proseWrap": "always",
4
5
  "overrides": [
@@ -15,6 +15,8 @@ project, which utilizes `uv` for environment and package management.
15
15
  - **New Dependencies:** If a new dependency is required, please state the reason for its inclusion.
16
16
  - Do not commit spec, plan, or markdown documents to git without asking first.
17
17
  - Save plans to `~/.superpowers/plans/` instead of the project directory.
18
+ - This project uses a 127 character maximum line length for all Python code, including for comments.
19
+ - This project uses a 100 character maximum line length for Markdown files.
18
20
 
19
21
  ## Python Code Standards
20
22
 
@@ -1,3 +1,47 @@
1
+ ## 4.3.0 (October 13, 2026)
2
+
3
+ - Stabilized features
4
+ - `@with_annotated` is no longer experimental. It was introduced as an experimental feature in
5
+ 4.0.0 and is now a fully supported way to define a command's arguments, alongside
6
+ `@with_argparser`. This covers the decorator and its supporting API in `cmd2.annotated`,
7
+ including `Argument`, `Option`, `Group`, and `ArgumentBlock`.
8
+ [Annotated Argument Processing](https://cmd2.readthedocs.io/en/latest/features/annotated/).
9
+ - Bug Fixes
10
+ - On POSIX, piping a command's output to an interactive program such as `less`
11
+ (`help -v | less`) now runs that program as the terminal's foreground job, as a shell pipeline
12
+ does. It had run in a separate session that never received the terminal, so Ctrl-Z and `fg`
13
+ did not suspend and resume it together with cmd2. The program now owns the terminal as it
14
+ starts, so a pager can set its terminal modes, and Ctrl-C and Ctrl-Z reach the whole pipeline.
15
+ Pipes started from a worker thread, or whose output does not go to the terminal, such as one
16
+ nested in a command whose own output is piped, still run in their own session
17
+ - A `shell` command piped to an interactive program, such as `shell git log | less`, now joins
18
+ the pipeline's job, so both processes receive Ctrl-C and Ctrl-Z
19
+ - On Windows, fixed piped output appearing garbled in console programs such as `more`
20
+ (`help -v | more`), a regression in 4.2.4. Pipes are written as UTF-8, but console programs
21
+ decode their input with the console's code page. While a pipe or the pager runs, cmd2 now sets
22
+ the console to UTF-8 (code page 65001, as `chcp 65001` does) and restores its code pages
23
+ afterward, so console programs and UTF-8 tools such as `rg` both read the output correctly
24
+ - When copying a command's output to the clipboard (`help >`) fails, later commands' output is
25
+ no longer written to the temporary file that held it
26
+ - When a pipe's process cannot be started, for instance because no more processes can be created
27
+ or `$SHELL` names a program that cannot run, both ends of the pipe are now closed rather than
28
+ left open
29
+ - When a pipe's process exits before the command runs, what it wrote, such as the shell's
30
+ "command not found", is no longer lost when cmd2 captures the output, as in a pyscript
31
+
32
+ ## 4.2.4 (September 8, 2026)
33
+
34
+ - Bug Fixes
35
+ - Fixed output redirection and piping raising `UnicodeEncodeError` and leaving an empty file
36
+ behind. Command output is rendered by Rich and contains box-drawing characters, which no
37
+ `cp125x` Windows ANSI code page can represent, so redirecting or piping it failed. This
38
+ affects current Windows 11 with default settings on Python 3.11 through 3.14, not only older
39
+ systems. Redirection targets and pipes now use UTF-8 explicitly
40
+ - Fixed the right prompt being redrawn beside every accepted command line in the scrollback.
41
+ prompt-toolkit includes it in the final frame of each prompt, which is the frame left on the
42
+ terminal; it is now hidden there, as the bottom toolbar already was, and stays on the live
43
+ prompt line only
44
+
1
45
  ## 4.2.3 (September 2, 2026)
2
46
 
3
47
  - Bug Fixes
cmd2-4.3.0/CLAUDE.md ADDED
@@ -0,0 +1,126 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this
4
+ repository.
5
+
6
+ ## Project
7
+
8
+ `cmd2` is a framework for building interactive command-line applications (REPLs) in Python. It
9
+ extends the stdlib `cmd` module and is built on **prompt-toolkit** (interactive input, key bindings,
10
+ completion, toolbars) and **Rich** / **rich-argparse** (all output rendering, help formatting,
11
+ theming). Requires Python >= 3.11. Environment/package management is **uv**.
12
+
13
+ ## Commands
14
+
15
+ All work happens inside the uv-managed venv — run Python via `uv run ...`, and `uvx ...` for one-off
16
+ tools. Never `pip install`; if a new dependency is needed, state why before adding it.
17
+
18
+ ```bash
19
+ make install # create the venv, install prek git hooks + prettier (one time)
20
+ make check # lock check + prek (ruff format/lint, prettier, typos) + ty + mypy
21
+ make test # pytest with coverage over tests/
22
+ make docs-test # verify the docs build cleanly (zensical)
23
+ make docs # build + serve docs with live reload
24
+ make help # list all targets
25
+ ```
26
+
27
+ `make check`, `make test`, and `make docs-test` must all pass before committing. Run `make check`
28
+ before creating or modifying any `.py` file as well.
29
+
30
+ Narrower targets: `make format`, `make lint`, `make mypy`, `make ty`, `make typecheck`.
31
+
32
+ Running a single test or file (coverage flags come from `pyproject.toml` `addopts`, so pass
33
+ `--no-cov` when you just want a fast run):
34
+
35
+ ```bash
36
+ uv run pytest tests/test_cmd2.py --no-cov
37
+ uv run pytest tests/test_cmd2.py::test_base_help -x --no-cov
38
+ uv run pytest -k "toolbar" --no-cov
39
+ ```
40
+
41
+ On Windows-sensitive code, note `make test` runs pytest under `python -Xutf8`.
42
+
43
+ ## Architecture
44
+
45
+ ### Command dispatch
46
+
47
+ `cmd2/cmd2.py` (the `Cmd` class) is the core and by far the largest module. The flow for one line of
48
+ input is:
49
+
50
+ 1. `cmdloop()` → `_cmdloop()` drives a prompt-toolkit `PromptSession` (created in
51
+ `_create_prompt_session`), not readline. Completion, history, lexing, and key bindings are all
52
+ supplied by prompt-toolkit adapters in `cmd2/pt_utils.py` (`Cmd2Completer`, `Cmd2History`,
53
+ `Cmd2Lexer`).
54
+ 2. `onecmd_plus_hooks()` parses the line into a `Statement` (`cmd2/parsing.py` — handles shortcuts,
55
+ aliases, macros, terminators, multiline commands, redirection and pipe tokens), then runs the
56
+ plugin hook chain.
57
+ 3. `_redirect_output()` swaps `self.stdout` for a file or subprocess pipe when the statement has
58
+ redirection, and restores it in the `finally` path.
59
+ 4. `onecmd()` looks up and calls the `do_*` method.
60
+
61
+ Hooks (`cmd2/plugin.py` dataclasses, registered via `register_postparsing_hook`,
62
+ `register_precmd_hook`, `register_postcmd_hook`, `register_cmdfinalization_hook`,
63
+ `register_preloop_hook`, `register_postloop_hook`) are the supported extension points; the legacy
64
+ `precmd`/`postcmd` overrides still exist but are weaker.
65
+
66
+ ### Argument parsing and completion
67
+
68
+ Three layers, all producing a `Cmd2ArgumentParser`:
69
+
70
+ - `cmd2/argparse_utils.py` — `Cmd2ArgumentParser` plus monkey-patching that extends argparse with
71
+ range `nargs` tuples, per-argument completion metadata, and subcommand records.
72
+ - `cmd2/decorators.py` — `@with_argparser`, `@with_argument_list`, `@with_category`,
73
+ `@as_subcommand_to` attach parsers/metadata to `do_*` methods.
74
+ - `cmd2/annotated.py` — the newer Typer-style path (experimental in 4.0.0, stable as of 4.3.0):
75
+ `@with_annotated` builds a parser from a function's type hints, with `Argument`/`Option` metadata
76
+ via `typing.Annotated`.
77
+
78
+ Parsers are built lazily and cached by the `CommandParsers` class in `cmd2.py` (`_build_parser`), so
79
+ that `CommandSet`-supplied subcommands can be attached and detached at runtime.
80
+ `cmd2/argparse_completer.py` walks a parser to produce tab completions; completion results are
81
+ `Completions`/`CompletionItem` objects from `cmd2/completion.py`.
82
+
83
+ ### Output and theming
84
+
85
+ Never print directly — go through `Cmd.print_to` / `poutput` / `perror` / `pwarning` / `pfeedback` /
86
+ `ppaged`, which route to Rich consoles defined in `cmd2/rich_utils.py` (`Cmd2GeneralConsole`,
87
+ `Cmd2RichArgparseConsole`, `Cmd2ExceptionConsole`). Styling flows one way: `cmd2/styles.py`
88
+ (style-name StrEnum + defaults) → `cmd2/theme.py` (single global theme, updated in-place for Rich
89
+ and exposed to prompt-toolkit through a `DynamicStyle`) → `cmd2/pt_utils.py` (`rich_to_pt_style`
90
+ converts Rich styles into prompt-toolkit ones). Adding a color or style means touching
91
+ `styles.py`/`colors.py`/`theme.py`, not hardcoding ANSI.
92
+
93
+ `cmd2/command_toolbar.py` and `cmd2/pager.py` are the trickiest parts of the codebase: they keep a
94
+ prompt-toolkit application alive _during_ synchronous command execution (bottom toolbar refresh,
95
+ paging) while stdout is proxied and redirection may be active. Changes there need care around
96
+ threads, signals, and Windows behavior.
97
+
98
+ ### Modularity
99
+
100
+ `cmd2/command_set.py` (`CommandSet`) lets commands live in separate classes that are registered and
101
+ unregistered at runtime via `Cmd.register_command_set`; `cmd2/py_bridge.py` exposes the app to
102
+ embedded Python/IPython shells and `run_pyscript` while keeping isolation.
103
+
104
+ ## Conventions
105
+
106
+ - Ruff is authoritative for format and lint (`ruff.toml`, line length 127, double quotes). Do not
107
+ suppress lint errors in code you write; broad ignores already exist for `examples/` and `tests/`.
108
+ - Both `mypy --strict` and `ty` must pass on the `cmd2` package. Full type annotations are required
109
+ on all library code (excluded: `tests/`, `examples/`, `docs/`).
110
+ - Docstrings are enforced by pydocstyle rules; public API items are documented in `docs/api/*.md`
111
+ and rendered by mkdocstrings, so keep docstrings accurate when changing signatures.
112
+ - Anything not documented under `docs/api/` is not public API (`cmd2/constants.py` says so
113
+ explicitly).
114
+ - Add user-visible changes to `CHANGELOG.md` under the current in-progress version heading.
115
+ - `main` is the branch for the next release, whether PATCH, MINOR, or MAJOR. Feature branches merge
116
+ into `main`, and all releases are tagged and published from it.
117
+ - Do not commit spec, plan, or markdown documents without asking first. Save plans to
118
+ `~/.superpowers/plans/` rather than the project directory.
119
+ - This project uses a 127 character maximum line length for all Python code, including for comments.
120
+ - This project uses a 100 character maximum line length for Markdown files.
121
+
122
+ ## Commit conventions
123
+
124
+ Never add "Co-Authored-By" lines to commits. Do not include Claude attribution in commit messages,
125
+ PR descriptions, or any git metadata. Do not include Claude session URL in commit messages, PR
126
+ descriptions, or any git metadata.
@@ -15,6 +15,8 @@ Python project, which utilizes `uv` for environment and package management.
15
15
  - **New Dependencies:** If a new dependency is required, please state the reason for its inclusion.
16
16
  - Do not commit spec, plan, or markdown documents to git without asking first.
17
17
  - Save plans to `~/.superpowers/plans/` instead of the project directory.
18
+ - This project uses a 127 character maximum line length for all Python code, including for comments.
19
+ - This project uses a 100 character maximum line length for Markdown files.
18
20
 
19
21
  ## Python Code Standards
20
22
 
@@ -5,8 +5,8 @@
5
5
  .PHONY: install
6
6
  install: ## Install the virtual environment with dependencies
7
7
  @echo "🚀 Creating uv Python virtual environment"
8
- @uv python install 3.14
9
- @uv sync --python=3.14
8
+ @uv python install 3.15
9
+ @uv sync --python=3.15
10
10
  @echo "🚀 Installing Git prek hooks locally"
11
11
  @uv run prek install -f
12
12
  @echo "🚀 Installing Prettier using npm"
@@ -47,7 +47,7 @@ typecheck: ## Perform type checking using both mypy and ty
47
47
  .PHONY: test
48
48
  test: ## Test the code with pytest.
49
49
  @echo "🚀 Testing code: Running pytest"
50
- @uv run python -Xutf8 -m pytest --cov --cov-config=pyproject.toml --cov-report=xml tests
50
+ @uv run python -Xutf8 -m pytest tests
51
51
 
52
52
  .PHONY: docs-test
53
53
  docs-test: ## Test if documentation can be built without warnings or errors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 4.2.3
3
+ Version: 4.3.0
4
4
  Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
5
5
  Author: cmd2 Contributors
6
6
  License-Expression: MIT
@@ -27,7 +27,10 @@ Requires-Dist: rich>=15.0.0
27
27
  Requires-Dist: rich-argparse>=1.7.2
28
28
  Dynamic: license-file
29
29
 
30
- <h1 align="center">cmd2: build feature-rich command-line applications in Python</h1>
30
+ <p align="center">
31
+ <a href="https://github.com/python-cmd2/cmd2"><img src="https://raw.githubusercontent.com/python-cmd2/cmd2/main/docs/assets/cmd2-logo.png" alt="cmd2 logo" width="160"></a>
32
+ </p>
33
+ <h1 align="center">cmd2: build feature-rich command-line apps in Python</h1>
31
34
 
32
35
  [![Latest Version](https://img.shields.io/pypi/v/cmd2.svg?style=flat-square&label=latest%20stable%20version)](https://pypi.python.org/pypi/cmd2/)
33
36
  [![Tests](https://github.com/python-cmd2/cmd2/actions/workflows/tests.yml/badge.svg)](https://github.com/python-cmd2/cmd2/actions/workflows/tests.yml)
@@ -115,7 +118,9 @@ to build a more complete application.
115
118
 
116
119
  - Define commands as Python methods and use familiar
117
120
  [`argparse`](https://cmd2.readthedocs.io/en/latest/features/argument_processing/) parsers for
118
- arguments and subcommands. A single parser definition drives validation, help, and completion.
121
+ arguments and subcommands, or plain type hints via
122
+ [`@with_annotated`](https://cmd2.readthedocs.io/en/latest/features/annotated/). A single parser
123
+ definition drives validation, help, and completion.
119
124
  - Render Rich tables and other styled objects, with consistent helpers for
120
125
  [normal output, errors, warnings, and paging](https://cmd2.readthedocs.io/en/latest/features/generating_output/).
121
126
  - Organize large applications into independently testable and dynamically loadable
@@ -251,6 +256,7 @@ reproduce the bug. At a minimum, please state the following:
251
256
  | [Falcon Toolkit](https://github.com/CrowdStrike/Falcon-Toolkit) | Unleash the power of the CrowdStrike Falcon Platform at the CLI | [CrowdStrike](https://github.com/CrowdStrike) |
252
257
  | [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [expliot_framework](https://gitlab.com/expliot_framework/) |
253
258
  | [Pobshell](https://github.com/pdalloz/pobshell) | A Bash‑like shell for live Python objects: `cd`, `ls`, `cat`, `find` and _CLI piping_ for object code, str values & more | [Peter Dalloz](https://www.linkedin.com/in/pdalloz) |
259
+ | [Wtsh](https://gitee.com/wazzge/wtsh) | WTSH is a shell built with Python cmd2(v4), which uses third-party plugins to construct a universal shell installed via Pip | [wazzge](https://gitee.com/wazzge) |
254
260
 
255
261
  Possibly defunct but still good examples
256
262
 
@@ -1,4 +1,7 @@
1
- <h1 align="center">cmd2: build feature-rich command-line applications in Python</h1>
1
+ <p align="center">
2
+ <a href="https://github.com/python-cmd2/cmd2"><img src="https://raw.githubusercontent.com/python-cmd2/cmd2/main/docs/assets/cmd2-logo.png" alt="cmd2 logo" width="160"></a>
3
+ </p>
4
+ <h1 align="center">cmd2: build feature-rich command-line apps in Python</h1>
2
5
 
3
6
  [![Latest Version](https://img.shields.io/pypi/v/cmd2.svg?style=flat-square&label=latest%20stable%20version)](https://pypi.python.org/pypi/cmd2/)
4
7
  [![Tests](https://github.com/python-cmd2/cmd2/actions/workflows/tests.yml/badge.svg)](https://github.com/python-cmd2/cmd2/actions/workflows/tests.yml)
@@ -86,7 +89,9 @@ to build a more complete application.
86
89
 
87
90
  - Define commands as Python methods and use familiar
88
91
  [`argparse`](https://cmd2.readthedocs.io/en/latest/features/argument_processing/) parsers for
89
- arguments and subcommands. A single parser definition drives validation, help, and completion.
92
+ arguments and subcommands, or plain type hints via
93
+ [`@with_annotated`](https://cmd2.readthedocs.io/en/latest/features/annotated/). A single parser
94
+ definition drives validation, help, and completion.
90
95
  - Render Rich tables and other styled objects, with consistent helpers for
91
96
  [normal output, errors, warnings, and paging](https://cmd2.readthedocs.io/en/latest/features/generating_output/).
92
97
  - Organize large applications into independently testable and dynamically loadable
@@ -222,6 +227,7 @@ reproduce the bug. At a minimum, please state the following:
222
227
  | [Falcon Toolkit](https://github.com/CrowdStrike/Falcon-Toolkit) | Unleash the power of the CrowdStrike Falcon Platform at the CLI | [CrowdStrike](https://github.com/CrowdStrike) |
223
228
  | [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [expliot_framework](https://gitlab.com/expliot_framework/) |
224
229
  | [Pobshell](https://github.com/pdalloz/pobshell) | A Bash‑like shell for live Python objects: `cd`, `ls`, `cat`, `find` and _CLI piping_ for object code, str values & more | [Peter Dalloz](https://www.linkedin.com/in/pdalloz) |
230
+ | [Wtsh](https://gitee.com/wazzge/wtsh) | WTSH is a shell built with Python cmd2(v4), which uses third-party plugins to construct a universal shell installed via Pip | [wazzge](https://gitee.com/wazzge) |
225
231
 
226
232
  Possibly defunct but still good examples
227
233
 
@@ -1,9 +1,5 @@
1
1
  """Build argparse parsers from type-annotated function signatures.
2
2
 
3
- !!! warning "Experimental"
4
-
5
- This module is experimental and its behavior may change in future releases.
6
-
7
3
  The [`with_annotated`][cmd2.annotated.with_annotated] decorator inspects a command function's type hints and
8
4
  default values to build a ``Cmd2ArgumentParser``. [`Argument`][cmd2.annotated.Argument] and
9
5
  [`Option`][cmd2.annotated.Option] metadata classes give finer per-parameter control via
@@ -313,6 +309,7 @@ from .rich_utils import Cmd2HelpFormatter, HelpContent
313
309
  from .types import (
314
310
  BoundCommandFunc,
315
311
  CmdOrSetT,
312
+ CmdOrSetT_contra,
316
313
  UnboundChoicesProvider,
317
314
  UnboundCompleter,
318
315
  )
@@ -712,7 +709,7 @@ def _make_enum_type(enum_class: type[enum.Enum], *, allow_unknown_entry: bool =
712
709
  raise _invalid_choice(value, _value_map)
713
710
 
714
711
  _convert.__name__ = enum_class.__name__
715
- _convert._cmd2_enum_class = enum_class # type: ignore[attr-defined, ty:unresolved-attribute]
712
+ _convert._cmd2_enum_class = enum_class # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
716
713
  return _convert
717
714
 
718
715
 
@@ -988,7 +985,7 @@ def _unwrap_optional(tp: Any) -> tuple[Any, bool]:
988
985
  there alone, so this helper never validates union members itself.
989
986
  """
990
987
  origin = get_origin(tp)
991
- if origin is Union or origin is types.UnionType: # type: ignore[comparison-overlap]
988
+ if origin is Union or origin is types.UnionType:
992
989
  all_args = get_args(tp)
993
990
  non_none = [a for a in all_args if a is not type(None)]
994
991
  has_none = len(non_none) < len(all_args)
@@ -1013,14 +1010,14 @@ def _normalize_annotation(annotation: Any) -> _NormalizedAnnotation:
1013
1010
  tp, unwrapped = _unwrap_optional(tp)
1014
1011
  if unwrapped:
1015
1012
  is_optional = True
1016
- if get_origin(tp) is Annotated: # type: ignore[comparison-overlap]
1013
+ if get_origin(tp) is Annotated:
1017
1014
  inner_tp = get_args(tp)[0]
1018
1015
  inner_origin = get_origin(inner_tp)
1019
- inner_is_union = inner_origin is Union or inner_origin is types.UnionType # type: ignore[comparison-overlap]
1016
+ inner_is_union = inner_origin is Union or inner_origin is types.UnionType
1020
1017
  if not (inner_is_union and type(None) in get_args(inner_tp)):
1021
1018
  raise TypeError("Annotated[T, meta] | None is ambiguous. Use Annotated[T | None, meta] instead.")
1022
1019
 
1023
- if get_origin(tp) is Annotated: # type: ignore[comparison-overlap]
1020
+ if get_origin(tp) is Annotated:
1024
1021
  args = get_args(tp)
1025
1022
  tp = args[0]
1026
1023
  for meta in args[1:]:
@@ -1118,7 +1115,7 @@ def _compose_preprocess(preprocess: Callable[[str], str], converter: Callable[[s
1118
1115
  _convert.__name__ = getattr(converter, "__name__", "preprocess")
1119
1116
  enum_class = getattr(converter, "_cmd2_enum_class", None)
1120
1117
  if enum_class is not None:
1121
- _convert._cmd2_enum_class = enum_class # type: ignore[attr-defined, ty:unresolved-attribute]
1118
+ _convert._cmd2_enum_class = enum_class # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
1122
1119
  return _convert
1123
1120
 
1124
1121
 
@@ -2907,23 +2904,25 @@ class _BoundAnnotatedCommand(Protocol[_CommandParams, _CommandReturn_co]):
2907
2904
  def __call__(self, *args: _CommandParams.args, **kwargs: _CommandParams.kwargs) -> _CommandReturn_co: ...
2908
2905
 
2909
2906
 
2910
- class _AnnotatedCommand(Protocol[CmdOrSetT, _CommandParams, _CommandReturn_co]):
2907
+ class _AnnotatedCommand(Protocol[CmdOrSetT_contra, _CommandParams, _CommandReturn_co]):
2911
2908
  """A callable command method with the metadata used by ``with_annotated``."""
2912
2909
 
2913
2910
  __name__: str
2914
2911
  __qualname__: str
2915
2912
 
2916
2913
  def __call__(
2917
- self, __self: CmdOrSetT, /, *args: _CommandParams.args, **kwargs: _CommandParams.kwargs
2914
+ self, __self: CmdOrSetT_contra, /, *args: _CommandParams.args, **kwargs: _CommandParams.kwargs
2918
2915
  ) -> _CommandReturn_co: ...
2919
2916
 
2920
2917
  @overload
2921
2918
  def __get__(
2922
2919
  self, instance: None, owner: Any = ...
2923
- ) -> "_AnnotatedCommand[CmdOrSetT, _CommandParams, _CommandReturn_co]": ...
2920
+ ) -> "_AnnotatedCommand[CmdOrSetT_contra, _CommandParams, _CommandReturn_co]": ...
2924
2921
 
2925
2922
  @overload
2926
- def __get__(self, instance: CmdOrSetT, owner: Any = ...) -> _BoundAnnotatedCommand[_CommandParams, _CommandReturn_co]: ...
2923
+ def __get__(
2924
+ self, instance: CmdOrSetT_contra, owner: Any = ...
2925
+ ) -> _BoundAnnotatedCommand[_CommandParams, _CommandReturn_co]: ...
2927
2926
 
2928
2927
 
2929
2928
  class _WithAnnotatedDecorator(Protocol):
@@ -52,7 +52,7 @@ ARG_TOKENS = "arg_tokens"
52
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
- suppress_hint = arg_action.get_suppress_tab_hint() # type: ignore[attr-defined, ty:unresolved-attribute]
55
+ suppress_hint = arg_action.get_suppress_tab_hint() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
56
56
  if suppress_hint or arg_action.help == argparse.SUPPRESS:
57
57
  return ""
58
58
 
@@ -104,7 +104,7 @@ class _ArgumentState:
104
104
  self.is_remainder = self.action.nargs == argparse.REMAINDER
105
105
 
106
106
  # Check if nargs is a range
107
- nargs_range: tuple[int, int | float] | None = self.action.get_nargs_range() # type: ignore[attr-defined, ty:unresolved-attribute]
107
+ nargs_range: tuple[int, int | float] | None = self.action.get_nargs_range() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
108
108
  if nargs_range is not None:
109
109
  self.min = nargs_range[0]
110
110
  self.max = nargs_range[1]
@@ -575,7 +575,7 @@ class ArgparseCompleter:
575
575
 
576
576
  :raises ValueError: if there is an error with the data.
577
577
  """
578
- table_columns = arg_state.action.get_table_columns() # type: ignore[attr-defined, ty:unresolved-attribute]
578
+ table_columns = arg_state.action.get_table_columns() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
579
579
  has_table_data = any(item.table_data for item in completions)
580
580
 
581
581
  if table_columns is None:
@@ -606,7 +606,7 @@ class ArgparseCompleter:
606
606
 
607
607
  table_columns = cast(
608
608
  Sequence[str | Column] | None,
609
- arg_state.action.get_table_columns(), # type: ignore[attr-defined, ty:unresolved-attribute]
609
+ arg_state.action.get_table_columns(), # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
610
610
  )
611
611
 
612
612
  # Skip table generation if results are outside thresholds or no columns are defined
@@ -761,7 +761,7 @@ class ArgparseCompleter:
761
761
  :raises CompletionError: if the completer or choices function this calls raises one
762
762
  """
763
763
  # Check if the argument uses a completer
764
- completer = arg_state.action.get_completer() # type: ignore[attr-defined, ty:unresolved-attribute]
764
+ completer = arg_state.action.get_completer() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
765
765
  if completer is not None:
766
766
  args, kwargs = self._prepare_callable_params(
767
767
  completer,
@@ -775,7 +775,7 @@ class ArgparseCompleter:
775
775
 
776
776
  # Otherwise it uses a choices provider or choices list
777
777
  else:
778
- choices_provider = arg_state.action.get_choices_provider() # type: ignore[attr-defined, ty:unresolved-attribute]
778
+ choices_provider = arg_state.action.get_choices_provider() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
779
779
  if choices_provider is not None:
780
780
  args, kwargs = self._prepare_callable_params(
781
781
  choices_provider,
@@ -232,8 +232,8 @@ import threading
232
232
  from argparse import ArgumentError
233
233
  from collections.abc import (
234
234
  Callable,
235
+ Generator,
235
236
  Iterable,
236
- Iterator,
237
237
  Sequence,
238
238
  )
239
239
  from dataclasses import dataclass
@@ -564,11 +564,11 @@ def _ActionsContainer_add_argument( # noqa: N802
564
564
  new_arg = orig_actions_container_add_argument(self, *args, **kwargs)
565
565
 
566
566
  # Set the cmd2-specific attributes
567
- new_arg.set_nargs_range(nargs_range) # type: ignore[attr-defined, ty:unresolved-attribute]
568
- new_arg.set_choices_provider(choices_provider) # type: ignore[attr-defined, ty:unresolved-attribute]
569
- new_arg.set_completer(completer) # type: ignore[attr-defined, ty:unresolved-attribute]
570
- new_arg.set_suppress_tab_hint(suppress_tab_hint) # type: ignore[attr-defined, ty:unresolved-attribute]
571
- new_arg.set_table_columns(table_columns) # type: ignore[attr-defined, ty:unresolved-attribute]
567
+ new_arg.set_nargs_range(nargs_range) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
568
+ new_arg.set_choices_provider(choices_provider) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
569
+ new_arg.set_completer(completer) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
570
+ new_arg.set_suppress_tab_hint(suppress_tab_hint) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
571
+ new_arg.set_table_columns(table_columns) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
572
572
 
573
573
  # Set other registered custom attributes
574
574
  for keyword, value in custom_attribs.items():
@@ -666,14 +666,14 @@ def _SubParsersAction_remove_all_parsers( # noqa: N802
666
666
  # Get the next subcommand name. remove_parser() will remove
667
667
  # it and any associated aliases from _name_parser_map.
668
668
  name = next(iter(self._name_parser_map))
669
- record = self.remove_parser(name) # type: ignore[attr-defined, ty:unresolved-attribute]
669
+ record = self.remove_parser(name) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
670
670
  records.append(record)
671
671
 
672
672
  return records
673
673
 
674
674
 
675
- argparse._SubParsersAction.remove_parser = _SubParsersAction_remove_parser # type: ignore[attr-defined, ty:unresolved-attribute]
676
- argparse._SubParsersAction.remove_all_parsers = _SubParsersAction_remove_all_parsers # type: ignore[attr-defined, ty:unresolved-attribute]
675
+ argparse._SubParsersAction.remove_parser = _SubParsersAction_remove_parser # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
676
+ argparse._SubParsersAction.remove_all_parsers = _SubParsersAction_remove_all_parsers # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
677
677
 
678
678
 
679
679
  @dataclass
@@ -695,7 +695,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
695
695
  _thread_locals: ClassVar[_ParserThreadLocals] = _ParserThreadLocals()
696
696
 
697
697
  @contextlib.contextmanager
698
- def output_to(self, file: IO[str] | None) -> Iterator[None]:
698
+ def output_to(self, file: IO[str] | None) -> Generator[None]:
699
699
  """Context manager to temporarily set the output stream during argparse operations.
700
700
 
701
701
  This is helpful for directing output for functions like `parse_args()`, which
@@ -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, ty:invalid-argument-type]
751
- epilog=epilog, # type: ignore[arg-type, ty:invalid-argument-type]
750
+ description=description, # type: ignore[arg-type] # ty: ignore[invalid-argument-type]
751
+ epilog=epilog, # type: ignore[arg-type] # ty: ignore[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, ty:invalid-method-override]
775
+ def print_usage(self, file: IO[str] | None = None) -> None: # type: ignore[override] # ty: ignore[invalid-method-override]
776
776
  """Override to ensure the formatter is aware of the target file."""
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, ty:invalid-method-override]
783
+ def print_help(self, file: IO[str] | None = None) -> None: # type: ignore[override] # ty: ignore[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
@@ -984,7 +984,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
984
984
  try:
985
985
  record = cast(
986
986
  SubcommandRecord,
987
- subparsers_action.remove_parser(subcommand), # type: ignore[attr-defined, ty:unresolved-attribute]
987
+ subparsers_action.remove_parser(subcommand), # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
988
988
  )
989
989
  except ValueError:
990
990
  raise ValueError(f"Subcommand '{subcommand}' does not exist for '{target_parser.prog}'") from None
@@ -1006,7 +1006,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1006
1006
 
1007
1007
  records = cast(
1008
1008
  list[SubcommandRecord],
1009
- subparsers_action.remove_all_parsers(), # type: ignore[attr-defined, ty:unresolved-attribute]
1009
+ subparsers_action.remove_all_parsers(), # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
1010
1010
  )
1011
1011
  # Update command for each detached subcommand
1012
1012
  for record in records:
@@ -1046,7 +1046,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1046
1046
 
1047
1047
  def _get_nargs_pattern(self, action: argparse.Action) -> str:
1048
1048
  """Override to support nargs ranges."""
1049
- nargs_range = action.get_nargs_range() # type: ignore[attr-defined, ty:unresolved-attribute]
1049
+ nargs_range = action.get_nargs_range() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
1050
1050
  if nargs_range:
1051
1051
  range_max = "" if nargs_range[1] == constants.INFINITY else nargs_range[1]
1052
1052
  nargs_pattern = f"(-*A{{{nargs_range[0]},{range_max}}}-*)"
@@ -1066,7 +1066,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
1066
1066
 
1067
1067
  # raise an exception if we weren't able to find a match
1068
1068
  if match is None:
1069
- nargs_range = action.get_nargs_range() # type: ignore[attr-defined, ty:unresolved-attribute]
1069
+ nargs_range = action.get_nargs_range() # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
1070
1070
  if nargs_range is not None:
1071
1071
  raise ArgumentError(action, build_range_error(nargs_range[0], nargs_range[1]))
1072
1072