cmd2 4.2.4__tar.gz → 4.3.1__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 (236) hide show
  1. {cmd2-4.2.4 → cmd2-4.3.1}/.pre-commit-config.yaml +2 -2
  2. {cmd2-4.2.4 → cmd2-4.3.1}/.prettierrc +1 -0
  3. {cmd2-4.2.4 → cmd2-4.3.1}/AGENTS.md +2 -0
  4. {cmd2-4.2.4 → cmd2-4.3.1}/CHANGELOG.md +45 -0
  5. {cmd2-4.2.4 → cmd2-4.3.1}/CLAUDE.md +7 -4
  6. {cmd2-4.2.4 → cmd2-4.3.1}/GEMINI.md +2 -0
  7. {cmd2-4.2.4 → cmd2-4.3.1}/MANIFEST.in +1 -1
  8. {cmd2-4.2.4 → cmd2-4.3.1}/Makefile +3 -3
  9. {cmd2-4.2.4 → cmd2-4.3.1}/PKG-INFO +14 -3
  10. {cmd2-4.2.4 → cmd2-4.3.1}/README.md +13 -2
  11. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/annotated.py +17 -20
  12. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/argparse_completer.py +6 -6
  13. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/argparse_utils.py +21 -21
  14. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/cmd2.py +237 -106
  15. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/decorators.py +3 -3
  16. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/rich_utils.py +10 -12
  17. cmd2-4.3.1/cmd2/utils.py +1643 -0
  18. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2.egg-info/PKG-INFO +14 -3
  19. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2.egg-info/SOURCES.txt +4 -0
  20. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2.egg-info/scm_file_list.json +4 -1
  21. cmd2-4.3.1/cmd2.egg-info/scm_version.json +8 -0
  22. cmd2-4.3.1/docs/assets/cmd2-logo.png +0 -0
  23. cmd2-4.3.1/docs/examples/embedding_in_textual.md +120 -0
  24. {cmd2-4.2.4 → cmd2-4.3.1}/docs/examples/index.md +1 -0
  25. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/annotated.md +2 -27
  26. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/argument_processing.md +1 -5
  27. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/prompt.md +7 -0
  28. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/redirection.md +4 -0
  29. {cmd2-4.2.4 → cmd2-4.3.1}/docs/overview/alternatives.md +6 -0
  30. {cmd2-4.2.4 → cmd2-4.3.1}/docs/testing.md +22 -0
  31. {cmd2-4.2.4 → cmd2-4.3.1}/examples/README.md +5 -0
  32. {cmd2-4.2.4 → cmd2-4.3.1}/examples/annotated_example.py +4 -4
  33. cmd2-4.3.1/examples/cmd2_history.dat +0 -0
  34. {cmd2-4.2.4 → cmd2-4.3.1}/examples/getting_started.py +4 -4
  35. cmd2-4.3.1/examples/textual_tty_embed.py +332 -0
  36. {cmd2-4.2.4 → cmd2-4.3.1}/mkdocs.yml +3 -1
  37. {cmd2-4.2.4 → cmd2-4.3.1}/pyproject.toml +33 -4
  38. {cmd2-4.2.4 → cmd2-4.3.1}/tests/conftest.py +32 -0
  39. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_annotated.py +43 -8
  40. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_cmd2.py +517 -31
  41. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_history.py +13 -12
  42. cmd2-4.3.1/tests/test_pipeline_job_control.py +1396 -0
  43. cmd2-4.3.1/tests/test_suite_environment.py +122 -0
  44. cmd2-4.3.1/tests/test_utils.py +1978 -0
  45. cmd2-4.3.1/ty.toml +9 -0
  46. cmd2-4.2.4/cmd2/utils.py +0 -858
  47. cmd2-4.2.4/cmd2.egg-info/scm_version.json +0 -8
  48. cmd2-4.2.4/examples/cmd2_history.dat +0 -0
  49. cmd2-4.2.4/tests/test_suite_environment.py +0 -59
  50. cmd2-4.2.4/tests/test_utils.py +0 -435
  51. cmd2-4.2.4/ty.toml +0 -7
  52. {cmd2-4.2.4 → cmd2-4.3.1}/.prettierignore +0 -0
  53. {cmd2-4.2.4 → cmd2-4.3.1}/.typos.toml +0 -0
  54. {cmd2-4.2.4 → cmd2-4.3.1}/LICENSE +0 -0
  55. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/__init__.py +0 -0
  56. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/clipboard.py +0 -0
  57. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/colors.py +0 -0
  58. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/command_set.py +0 -0
  59. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/completion.py +0 -0
  60. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/constants.py +0 -0
  61. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/exceptions.py +0 -0
  62. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/history.py +0 -0
  63. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/parsing.py +0 -0
  64. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/plugin.py +0 -0
  65. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/pt_utils.py +0 -0
  66. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/py.typed +0 -0
  67. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/py_bridge.py +0 -0
  68. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/string_utils.py +0 -0
  69. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/styles.py +0 -0
  70. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/theme.py +0 -0
  71. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2/types.py +0 -0
  72. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2.egg-info/dependency_links.txt +0 -0
  73. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2.egg-info/requires.txt +0 -0
  74. {cmd2-4.2.4 → cmd2-4.3.1}/cmd2.egg-info/top_level.txt +0 -0
  75. {cmd2-4.2.4 → cmd2-4.3.1}/codecov.yml +0 -0
  76. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/annotated.md +0 -0
  77. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/argparse_completer.md +0 -0
  78. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/argparse_utils.md +0 -0
  79. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/clipboard.md +0 -0
  80. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/cmd.md +0 -0
  81. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/colors.md +0 -0
  82. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/command_set.md +0 -0
  83. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/completion.md +0 -0
  84. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/constants.md +0 -0
  85. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/decorators.md +0 -0
  86. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/exceptions.md +0 -0
  87. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/history.md +0 -0
  88. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/index.md +0 -0
  89. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/parsing.md +0 -0
  90. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/plugin.md +0 -0
  91. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/pt_utils.md +0 -0
  92. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/py_bridge.md +0 -0
  93. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/rich_utils.md +0 -0
  94. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/string_utils.md +0 -0
  95. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/styles.md +0 -0
  96. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/theme.md +0 -0
  97. {cmd2-4.2.4 → cmd2-4.3.1}/docs/api/utils.md +0 -0
  98. {cmd2-4.2.4 → cmd2-4.3.1}/docs/assets/cmd2-readme-demo.gif +0 -0
  99. {cmd2-4.2.4 → cmd2-4.3.1}/docs/assets/getting-started-demo.gif +0 -0
  100. {cmd2-4.2.4 → cmd2-4.3.1}/docs/doc_conventions.md +0 -0
  101. {cmd2-4.2.4 → cmd2-4.3.1}/docs/examples/alternate_event_loops.md +0 -0
  102. {cmd2-4.2.4 → cmd2-4.3.1}/docs/examples/examples.md +0 -0
  103. {cmd2-4.2.4 → cmd2-4.3.1}/docs/examples/getting_started.md +0 -0
  104. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/async_commands.md +0 -0
  105. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/builtin_commands.md +0 -0
  106. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/clipboard.md +0 -0
  107. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/commands.md +0 -0
  108. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/completion.md +0 -0
  109. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/disable_commands.md +0 -0
  110. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/embedded_python_shells.md +0 -0
  111. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/generating_output.md +0 -0
  112. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/help.md +0 -0
  113. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/history.md +0 -0
  114. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/hooks.md +0 -0
  115. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/index.md +0 -0
  116. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/initialization.md +0 -0
  117. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/misc.md +0 -0
  118. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/modular_commands.md +0 -0
  119. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/multiline_commands.md +0 -0
  120. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/os.md +0 -0
  121. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/packaging.md +0 -0
  122. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/plugins.md +0 -0
  123. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/scripting.md +0 -0
  124. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/settings.md +0 -0
  125. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/shortcuts_aliases_macros.md +0 -0
  126. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/startup_commands.md +0 -0
  127. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/table_creation.md +0 -0
  128. {cmd2-4.2.4 → cmd2-4.3.1}/docs/features/theme.md +0 -0
  129. {cmd2-4.2.4 → cmd2-4.3.1}/docs/index.md +0 -0
  130. {cmd2-4.2.4 → cmd2-4.3.1}/docs/javascripts/readthedocs.js +0 -0
  131. {cmd2-4.2.4 → cmd2-4.3.1}/docs/migrating/incompatibilities.md +0 -0
  132. {cmd2-4.2.4 → cmd2-4.3.1}/docs/migrating/index.md +0 -0
  133. {cmd2-4.2.4 → cmd2-4.3.1}/docs/migrating/minimum.md +0 -0
  134. {cmd2-4.2.4 → cmd2-4.3.1}/docs/migrating/next_steps.md +0 -0
  135. {cmd2-4.2.4 → cmd2-4.3.1}/docs/migrating/why.md +0 -0
  136. {cmd2-4.2.4 → cmd2-4.3.1}/docs/mixins/index.md +0 -0
  137. {cmd2-4.2.4 → cmd2-4.3.1}/docs/mixins/mixin_template.md +0 -0
  138. {cmd2-4.2.4 → cmd2-4.3.1}/docs/overrides/main.html +0 -0
  139. {cmd2-4.2.4 → cmd2-4.3.1}/docs/overview/index.md +0 -0
  140. {cmd2-4.2.4 → cmd2-4.3.1}/docs/overview/installation.md +0 -0
  141. {cmd2-4.2.4 → cmd2-4.3.1}/docs/overview/integrating.md +0 -0
  142. {cmd2-4.2.4 → cmd2-4.3.1}/docs/overview/resources.md +0 -0
  143. {cmd2-4.2.4 → cmd2-4.3.1}/docs/stylesheets/cmd2.css +0 -0
  144. {cmd2-4.2.4 → cmd2-4.3.1}/docs/upgrades.md +0 -0
  145. {cmd2-4.2.4 → cmd2-4.3.1}/examples/.cmd2rc +0 -0
  146. {cmd2-4.2.4 → cmd2-4.3.1}/examples/argparse_completion.py +0 -0
  147. {cmd2-4.2.4 → cmd2-4.3.1}/examples/argparse_example.py +0 -0
  148. {cmd2-4.2.4 → cmd2-4.3.1}/examples/async_call.py +0 -0
  149. {cmd2-4.2.4 → cmd2-4.3.1}/examples/async_commands.py +0 -0
  150. {cmd2-4.2.4 → cmd2-4.3.1}/examples/async_printing.py +0 -0
  151. {cmd2-4.2.4 → cmd2-4.3.1}/examples/basic_completion.py +0 -0
  152. {cmd2-4.2.4 → cmd2-4.3.1}/examples/cmd_as_argument.py +0 -0
  153. {cmd2-4.2.4 → cmd2-4.3.1}/examples/color.py +0 -0
  154. {cmd2-4.2.4 → cmd2-4.3.1}/examples/command_sets.py +0 -0
  155. {cmd2-4.2.4 → cmd2-4.3.1}/examples/completion_item_choices.py +0 -0
  156. {cmd2-4.2.4 → cmd2-4.3.1}/examples/custom_parser.py +0 -0
  157. {cmd2-4.2.4 → cmd2-4.3.1}/examples/custom_types.py +0 -0
  158. {cmd2-4.2.4 → cmd2-4.3.1}/examples/default_categories.py +0 -0
  159. {cmd2-4.2.4 → cmd2-4.3.1}/examples/dynamic_commands.py +0 -0
  160. {cmd2-4.2.4 → cmd2-4.3.1}/examples/environment.py +0 -0
  161. {cmd2-4.2.4 → cmd2-4.3.1}/examples/event_loops.py +0 -0
  162. {cmd2-4.2.4 → cmd2-4.3.1}/examples/exit_code.py +0 -0
  163. {cmd2-4.2.4 → cmd2-4.3.1}/examples/hello_cmd2.py +0 -0
  164. {cmd2-4.2.4 → cmd2-4.3.1}/examples/help_categories.py +0 -0
  165. {cmd2-4.2.4 → cmd2-4.3.1}/examples/hooks.py +0 -0
  166. {cmd2-4.2.4 → cmd2-4.3.1}/examples/migrating.py +0 -0
  167. {cmd2-4.2.4 → cmd2-4.3.1}/examples/mixin.py +0 -0
  168. {cmd2-4.2.4 → cmd2-4.3.1}/examples/modular_commands/__init__.py +0 -0
  169. {cmd2-4.2.4 → cmd2-4.3.1}/examples/modular_commands/commandset_basic.py +0 -0
  170. {cmd2-4.2.4 → cmd2-4.3.1}/examples/modular_commands/commandset_complex.py +0 -0
  171. {cmd2-4.2.4 → cmd2-4.3.1}/examples/modular_commands/commandset_custominit.py +0 -0
  172. {cmd2-4.2.4 → cmd2-4.3.1}/examples/modular_commandsets.py +0 -0
  173. {cmd2-4.2.4 → cmd2-4.3.1}/examples/paged_output.py +0 -0
  174. {cmd2-4.2.4 → cmd2-4.3.1}/examples/persistent_history.py +0 -0
  175. {cmd2-4.2.4 → cmd2-4.3.1}/examples/pretty_print.py +0 -0
  176. {cmd2-4.2.4 → cmd2-4.3.1}/examples/python_scripting.py +0 -0
  177. {cmd2-4.2.4 → cmd2-4.3.1}/examples/read_input.py +0 -0
  178. {cmd2-4.2.4 → cmd2-4.3.1}/examples/remove_builtin_commands.py +0 -0
  179. {cmd2-4.2.4 → cmd2-4.3.1}/examples/remove_settable.py +0 -0
  180. {cmd2-4.2.4 → cmd2-4.3.1}/examples/rich_tables.py +0 -0
  181. {cmd2-4.2.4 → cmd2-4.3.1}/examples/rich_theme.py +0 -0
  182. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/arg_printer.py +0 -0
  183. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/conditional.py +0 -0
  184. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/nested.txt +0 -0
  185. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/quit.txt +0 -0
  186. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/save_help_text.py +0 -0
  187. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/script.py +0 -0
  188. {cmd2-4.2.4 → cmd2-4.3.1}/examples/scripts/script.txt +0 -0
  189. {cmd2-4.2.4 → cmd2-4.3.1}/examples/tmux_launch.sh +0 -0
  190. {cmd2-4.2.4 → cmd2-4.3.1}/examples/tmux_split.sh +0 -0
  191. {cmd2-4.2.4 → cmd2-4.3.1}/examples/unicode_commands.py +0 -0
  192. {cmd2-4.2.4 → cmd2-4.3.1}/package.json +0 -0
  193. {cmd2-4.2.4 → cmd2-4.3.1}/ruff.toml +0 -0
  194. {cmd2-4.2.4 → cmd2-4.3.1}/scripts/validate_tag.py +0 -0
  195. {cmd2-4.2.4 → cmd2-4.3.1}/setup.cfg +0 -0
  196. {cmd2-4.2.4 → cmd2-4.3.1}/tests/.cmd2rc +0 -0
  197. {cmd2-4.2.4 → cmd2-4.3.1}/tests/__init__.py +0 -0
  198. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/echo.py +0 -0
  199. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/environment.py +0 -0
  200. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/help.py +0 -0
  201. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/py_locals.py +0 -0
  202. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/pyscript_dir.py +0 -0
  203. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/raises_exception.py +0 -0
  204. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/recursive.py +0 -0
  205. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/self_in_py.py +0 -0
  206. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/stop.py +0 -0
  207. {cmd2-4.2.4 → cmd2-4.3.1}/tests/pyscript/test_print.py +0 -0
  208. {cmd2-4.2.4 → cmd2-4.3.1}/tests/relative_multiple.txt +0 -0
  209. {cmd2-4.2.4 → cmd2-4.3.1}/tests/script.py +0 -0
  210. {cmd2-4.2.4 → cmd2-4.3.1}/tests/script.txt +0 -0
  211. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/binary.bin +0 -0
  212. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/empty.txt +0 -0
  213. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/help.txt +0 -0
  214. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/nested.txt +0 -0
  215. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/one_down.txt +0 -0
  216. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/postcmds.txt +0 -0
  217. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/precmds.txt +0 -0
  218. {cmd2-4.2.4 → cmd2-4.3.1}/tests/scripts/utf8.txt +0 -0
  219. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_argparse.py +0 -0
  220. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_argparse_completer.py +0 -0
  221. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_argparse_subcommands.py +0 -0
  222. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_argparse_utils.py +0 -0
  223. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_categories.py +0 -0
  224. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_commandset.py +0 -0
  225. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_completion.py +0 -0
  226. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_dynamic_complete_style.py +0 -0
  227. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_future_annotations.py +0 -0
  228. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_parsing.py +0 -0
  229. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_plugin.py +0 -0
  230. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_pt_utils.py +0 -0
  231. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_py_completion.py +0 -0
  232. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_rich_utils.py +0 -0
  233. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_run_pyscript.py +0 -0
  234. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_string_utils.py +0 -0
  235. {cmd2-4.2.4 → cmd2-4.3.1}/tests/test_theme.py +0 -0
  236. {cmd2-4.2.4 → cmd2-4.3.1}/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.6"
18
+ rev: "v0.17.1"
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,48 @@
1
+ ## 4.3.1 (October 24, 2026)
2
+
3
+ - Bug Fixes
4
+ - Fixed `@with_annotated` command `--help` output bypassing the application's output stream,
5
+ leaving redirected help files empty and preventing help from being captured by embedded apps.
6
+ - Enhancements
7
+ - Added the
8
+ [textual_tty_embed.py](https://github.com/python-cmd2/cmd2/blob/main/examples/textual_tty_embed.py)
9
+ example, which embeds a `cmd2` application in a [Textual](https://textual.textualize.io/)
10
+ application using [textual-tty](https://github.com/ttygroup/textual-tty). The Textual
11
+ application shows a realtime status panel beside the `cmd2` application, which can display
12
+ much richer information than a bottom toolbar. See the
13
+ [Embedding in Textual](docs/examples/embedding_in_textual.md) documentation for details.
14
+
15
+ ## 4.3.0 (October 13, 2026)
16
+
17
+ - Stabilized features
18
+ - `@with_annotated` is no longer experimental. It was introduced as an experimental feature in
19
+ 4.0.0 and is now a fully supported way to define a command's arguments, alongside
20
+ `@with_argparser`. This covers the decorator and its supporting API in `cmd2.annotated`,
21
+ including `Argument`, `Option`, `Group`, and `ArgumentBlock`.
22
+ [Annotated Argument Processing](https://cmd2.readthedocs.io/en/latest/features/annotated/).
23
+ - Bug Fixes
24
+ - On POSIX, piping a command's output to an interactive program such as `less`
25
+ (`help -v | less`) now runs that program as the terminal's foreground job, as a shell pipeline
26
+ does. It had run in a separate session that never received the terminal, so Ctrl-Z and `fg`
27
+ did not suspend and resume it together with cmd2. The program now owns the terminal as it
28
+ starts, so a pager can set its terminal modes, and Ctrl-C and Ctrl-Z reach the whole pipeline.
29
+ Pipes started from a worker thread, or whose output does not go to the terminal, such as one
30
+ nested in a command whose own output is piped, still run in their own session
31
+ - A `shell` command piped to an interactive program, such as `shell git log | less`, now joins
32
+ the pipeline's job, so both processes receive Ctrl-C and Ctrl-Z
33
+ - On Windows, fixed piped output appearing garbled in console programs such as `more`
34
+ (`help -v | more`), a regression in 4.2.4. Pipes are written as UTF-8, but console programs
35
+ decode their input with the console's code page. While a pipe or the pager runs, cmd2 now sets
36
+ the console to UTF-8 (code page 65001, as `chcp 65001` does) and restores its code pages
37
+ afterward, so console programs and UTF-8 tools such as `rg` both read the output correctly
38
+ - When copying a command's output to the clipboard (`help >`) fails, later commands' output is
39
+ no longer written to the temporary file that held it
40
+ - When a pipe's process cannot be started, for instance because no more processes can be created
41
+ or `$SHELL` names a program that cannot run, both ends of the pipe are now closed rather than
42
+ left open
43
+ - When a pipe's process exits before the command runs, what it wrote, such as the shell's
44
+ "command not found", is no longer lost when cmd2 captures the output, as in a pyscript
45
+
1
46
  ## 4.2.4 (September 8, 2026)
2
47
 
3
48
  - Bug Fixes
@@ -71,8 +71,9 @@ Three layers, all producing a `Cmd2ArgumentParser`:
71
71
  range `nargs` tuples, per-argument completion metadata, and subcommand records.
72
72
  - `cmd2/decorators.py` — `@with_argparser`, `@with_argument_list`, `@with_category`,
73
73
  `@as_subcommand_to` attach parsers/metadata to `do_*` methods.
74
- - `cmd2/annotated.py` — the newer, still-experimental Typer-style path: `@with_annotated` builds a
75
- parser from a function's type hints, with `Argument`/`Option` metadata via `typing.Annotated`.
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`.
76
77
 
77
78
  Parsers are built lazily and cached by the `CommandParsers` class in `cmd2.py` (`_build_parser`), so
78
79
  that `CommandSet`-supplied subcommands can be attached and detached at runtime.
@@ -111,10 +112,12 @@ embedded Python/IPython shells and `run_pyscript` while keeping isolation.
111
112
  - Anything not documented under `docs/api/` is not public API (`cmd2/constants.py` says so
112
113
  explicitly).
113
114
  - Add user-visible changes to `CHANGELOG.md` under the current in-progress version heading.
114
- - `main` is the branch for the next PATCH release; MAJOR/MINOR work happens on a branch named for
115
- the target version. Releases are tagged and published from `main`.
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.
116
117
  - Do not commit spec, plan, or markdown documents without asking first. Save plans to
117
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.
118
121
 
119
122
  ## Commit conventions
120
123
 
@@ -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,4 +5,4 @@ recursive-include docs *
5
5
  prune .github
6
6
  prune build
7
7
  exclude .github .gitignore .readthedocs.yaml
8
- global-exclude htmlcov/** .coverage* __pycache__/** .gitignore
8
+ global-exclude htmlcov/** .coverage* __pycache__/** .gitignore .DS_Store
@@ -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.4
3
+ Version: 4.3.1
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)
@@ -52,6 +55,12 @@ completion, command history, scripting, output styling, and much more.
52
55
  You can use `cmd2` for a small internal tool and grow the same application into an extensible,
53
56
  scriptable interface without replacing the framework or writing the usual CLI boilerplate.
54
57
 
58
+ Want a richer visual display than a prompt and toolbar can offer? Your `cmd2` application can run
59
+ inside a terminal pane of a [Textual](https://textual.textualize.io/) application, right next to
60
+ dashboards and panels that show realtime status and other information. See
61
+ [Embedding in Textual](https://cmd2.readthedocs.io/en/latest/examples/embedding_in_textual/) for an
62
+ example.
63
+
55
64
  ## Quick start
56
65
 
57
66
  Install `cmd2`:
@@ -115,7 +124,9 @@ to build a more complete application.
115
124
 
116
125
  - Define commands as Python methods and use familiar
117
126
  [`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.
127
+ arguments and subcommands, or plain type hints via
128
+ [`@with_annotated`](https://cmd2.readthedocs.io/en/latest/features/annotated/). A single parser
129
+ definition drives validation, help, and completion.
119
130
  - Render Rich tables and other styled objects, with consistent helpers for
120
131
  [normal output, errors, warnings, and paging](https://cmd2.readthedocs.io/en/latest/features/generating_output/).
121
132
  - Organize large applications into independently testable and dynamically loadable
@@ -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)
@@ -23,6 +26,12 @@ completion, command history, scripting, output styling, and much more.
23
26
  You can use `cmd2` for a small internal tool and grow the same application into an extensible,
24
27
  scriptable interface without replacing the framework or writing the usual CLI boilerplate.
25
28
 
29
+ Want a richer visual display than a prompt and toolbar can offer? Your `cmd2` application can run
30
+ inside a terminal pane of a [Textual](https://textual.textualize.io/) application, right next to
31
+ dashboards and panels that show realtime status and other information. See
32
+ [Embedding in Textual](https://cmd2.readthedocs.io/en/latest/examples/embedding_in_textual/) for an
33
+ example.
34
+
26
35
  ## Quick start
27
36
 
28
37
  Install `cmd2`:
@@ -86,7 +95,9 @@ to build a more complete application.
86
95
 
87
96
  - Define commands as Python methods and use familiar
88
97
  [`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.
98
+ arguments and subcommands, or plain type hints via
99
+ [`@with_annotated`](https://cmd2.readthedocs.io/en/latest/features/annotated/). A single parser
100
+ definition drives validation, help, and completion.
90
101
  - Render Rich tables and other styled objects, with consistent helpers for
91
102
  [normal output, errors, warnings, and paging](https://cmd2.readthedocs.io/en/latest/features/generating_output/).
92
103
  - Organize large applications into independently testable and dynamically loadable
@@ -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
@@ -713,7 +709,7 @@ def _make_enum_type(enum_class: type[enum.Enum], *, allow_unknown_entry: bool =
713
709
  raise _invalid_choice(value, _value_map)
714
710
 
715
711
  _convert.__name__ = enum_class.__name__
716
- _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]
717
713
  return _convert
718
714
 
719
715
 
@@ -989,7 +985,7 @@ def _unwrap_optional(tp: Any) -> tuple[Any, bool]:
989
985
  there alone, so this helper never validates union members itself.
990
986
  """
991
987
  origin = get_origin(tp)
992
- if origin is Union or origin is types.UnionType: # type: ignore[comparison-overlap]
988
+ if origin is Union or origin is types.UnionType:
993
989
  all_args = get_args(tp)
994
990
  non_none = [a for a in all_args if a is not type(None)]
995
991
  has_none = len(non_none) < len(all_args)
@@ -1014,14 +1010,14 @@ def _normalize_annotation(annotation: Any) -> _NormalizedAnnotation:
1014
1010
  tp, unwrapped = _unwrap_optional(tp)
1015
1011
  if unwrapped:
1016
1012
  is_optional = True
1017
- if get_origin(tp) is Annotated: # type: ignore[comparison-overlap]
1013
+ if get_origin(tp) is Annotated:
1018
1014
  inner_tp = get_args(tp)[0]
1019
1015
  inner_origin = get_origin(inner_tp)
1020
- 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
1021
1017
  if not (inner_is_union and type(None) in get_args(inner_tp)):
1022
1018
  raise TypeError("Annotated[T, meta] | None is ambiguous. Use Annotated[T | None, meta] instead.")
1023
1019
 
1024
- if get_origin(tp) is Annotated: # type: ignore[comparison-overlap]
1020
+ if get_origin(tp) is Annotated:
1025
1021
  args = get_args(tp)
1026
1022
  tp = args[0]
1027
1023
  for meta in args[1:]:
@@ -1119,7 +1115,7 @@ def _compose_preprocess(preprocess: Callable[[str], str], converter: Callable[[s
1119
1115
  _convert.__name__ = getattr(converter, "__name__", "preprocess")
1120
1116
  enum_class = getattr(converter, "_cmd2_enum_class", None)
1121
1117
  if enum_class is not None:
1122
- _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]
1123
1119
  return _convert
1124
1120
 
1125
1121
 
@@ -3158,28 +3154,29 @@ def with_annotated(
3158
3154
 
3159
3155
  @functools.wraps(command_func)
3160
3156
  def cmd_wrapper(*args: Any, **kwargs: Any) -> _CommandReturn:
3161
- cmd2_app, statement_arg = _parse_positionals(args)
3157
+ cmd_app, statement_arg = _parse_positionals(args)
3162
3158
  owner = args[0] # Cmd or CommandSet instance
3163
- statement, parsed_arglist = cmd2_app.statement_parser.get_command_arg_list(
3159
+ statement, parsed_arglist = cmd_app.statement_parser.get_command_arg_list(
3164
3160
  command_name, statement_arg, preserve_quotes
3165
3161
  )
3166
3162
 
3167
- arg_parser = cmd2_app.command_parsers.get(cast(BoundCommandFunc[...], cmd_wrapper))
3163
+ arg_parser = cmd_app.command_parsers.get(cast(BoundCommandFunc[...], cmd_wrapper))
3168
3164
  if arg_parser is None:
3169
3165
  raise ValueError(f"No argument parser found for {command_name}")
3170
3166
 
3171
3167
  if ns_provider is None:
3172
3168
  namespace = None
3173
3169
  else:
3174
- provider_self = cmd2_app._resolve_func_self(ns_provider, args[0])
3175
- namespace = ns_provider(provider_self if provider_self is not None else cmd2_app)
3170
+ provider_self = cmd_app._resolve_func_self(ns_provider, args[0])
3171
+ namespace = ns_provider(provider_self if provider_self is not None else cmd_app)
3176
3172
 
3177
3173
  try:
3178
- if with_unknown_args:
3179
- ns, unknown = arg_parser.parse_known_args(parsed_arglist, namespace)
3180
- else:
3181
- ns = arg_parser.parse_args(parsed_arglist, namespace)
3182
- unknown = None
3174
+ with arg_parser.output_to(cmd_app.stdout):
3175
+ if with_unknown_args:
3176
+ ns, unknown = arg_parser.parse_known_args(parsed_arglist, namespace)
3177
+ else:
3178
+ ns = arg_parser.parse_args(parsed_arglist, namespace)
3179
+ unknown = None
3183
3180
  except SystemExit as exc:
3184
3181
  raise Cmd2ArgparseError from exc
3185
3182
 
@@ -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,
@@ -768,11 +768,11 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
768
768
  self.completer_class = completer_class
769
769
 
770
770
  # To assist type checkers, recast these to reflect our usage of rich-argparse.
771
- self.formatter_class: type[Cmd2HelpFormatter]
772
- self.description: HelpContent | None # type: ignore[assignment]
773
- self.epilog: HelpContent | None # type: ignore[assignment]
771
+ self.formatter_class: type[Cmd2HelpFormatter] # ty: ignore[invalid-mutable-override]
772
+ self.description: HelpContent | None # type: ignore[assignment] # ty: ignore[invalid-attribute-override]
773
+ self.epilog: HelpContent | None # type: ignore[assignment] # ty: ignore[invalid-attribute-override]
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