cmd2 3.4.0__tar.gz → 3.5.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 (229) hide show
  1. {cmd2-3.4.0 → cmd2-3.5.1}/CHANGELOG.md +11 -0
  2. {cmd2-3.4.0 → cmd2-3.5.1}/PKG-INFO +3 -3
  3. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/argparse_completer.py +2 -2
  4. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/cmd2.py +5 -11
  5. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/constants.py +3 -3
  6. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/parsing.py +10 -10
  7. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/rich_utils.py +10 -63
  8. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/utils.py +1 -1
  9. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2.egg-info/PKG-INFO +3 -3
  10. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2.egg-info/SOURCES.txt +0 -1
  11. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2.egg-info/requires.txt +2 -2
  12. {cmd2-3.4.0 → cmd2-3.5.1}/pyproject.toml +2 -2
  13. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_cmd2.py +21 -30
  14. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_rich_utils.py +97 -37
  15. cmd2-3.4.0/examples/cmd2_history.dat +0 -0
  16. {cmd2-3.4.0 → cmd2-3.5.1}/.pre-commit-config.yaml +0 -0
  17. {cmd2-3.4.0 → cmd2-3.5.1}/.prettierignore +0 -0
  18. {cmd2-3.4.0 → cmd2-3.5.1}/.prettierrc +0 -0
  19. {cmd2-3.4.0 → cmd2-3.5.1}/GEMINI.md +0 -0
  20. {cmd2-3.4.0 → cmd2-3.5.1}/LICENSE +0 -0
  21. {cmd2-3.4.0 → cmd2-3.5.1}/MANIFEST.in +0 -0
  22. {cmd2-3.4.0 → cmd2-3.5.1}/Makefile +0 -0
  23. {cmd2-3.4.0 → cmd2-3.5.1}/README.md +0 -0
  24. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/__init__.py +0 -0
  25. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/argparse_custom.py +0 -0
  26. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/clipboard.py +0 -0
  27. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/colors.py +0 -0
  28. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/command_definition.py +0 -0
  29. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/decorators.py +0 -0
  30. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/exceptions.py +0 -0
  31. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/history.py +0 -0
  32. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/plugin.py +0 -0
  33. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/py.typed +0 -0
  34. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/py_bridge.py +0 -0
  35. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/rl_utils.py +0 -0
  36. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/string_utils.py +0 -0
  37. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/styles.py +0 -0
  38. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/terminal_utils.py +0 -0
  39. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2/transcript.py +0 -0
  40. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2.egg-info/dependency_links.txt +0 -0
  41. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2.egg-info/top_level.txt +0 -0
  42. {cmd2-3.4.0 → cmd2-3.5.1}/cmd2.png +0 -0
  43. {cmd2-3.4.0 → cmd2-3.5.1}/codecov.yml +0 -0
  44. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/argparse_completer.md +0 -0
  45. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/argparse_custom.md +0 -0
  46. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/clipboard.md +0 -0
  47. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/cmd.md +0 -0
  48. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/colors.md +0 -0
  49. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/command_definition.md +0 -0
  50. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/constants.md +0 -0
  51. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/decorators.md +0 -0
  52. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/exceptions.md +0 -0
  53. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/history.md +0 -0
  54. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/index.md +0 -0
  55. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/parsing.md +0 -0
  56. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/plugin.md +0 -0
  57. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/py_bridge.md +0 -0
  58. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/rich_utils.md +0 -0
  59. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/rl_utils.md +0 -0
  60. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/string_utils.md +0 -0
  61. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/styles.md +0 -0
  62. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/terminal_utils.md +0 -0
  63. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/transcript.md +0 -0
  64. {cmd2-3.4.0 → cmd2-3.5.1}/docs/api/utils.md +0 -0
  65. {cmd2-3.4.0 → cmd2-3.5.1}/docs/doc_conventions.md +0 -0
  66. {cmd2-3.4.0 → cmd2-3.5.1}/docs/examples/alternate_event_loops.md +0 -0
  67. {cmd2-3.4.0 → cmd2-3.5.1}/docs/examples/examples.md +0 -0
  68. {cmd2-3.4.0 → cmd2-3.5.1}/docs/examples/getting_started.md +0 -0
  69. {cmd2-3.4.0 → cmd2-3.5.1}/docs/examples/index.md +0 -0
  70. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/argument_processing.md +0 -0
  71. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/builtin_commands.md +0 -0
  72. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/clipboard.md +0 -0
  73. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/commands.md +0 -0
  74. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/completion.md +0 -0
  75. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/disable_commands.md +0 -0
  76. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/embedded_python_shells.md +0 -0
  77. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/generating_output.md +0 -0
  78. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/help.md +0 -0
  79. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/history.md +0 -0
  80. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/hooks.md +0 -0
  81. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/index.md +0 -0
  82. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/initialization.md +0 -0
  83. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/misc.md +0 -0
  84. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/modular_commands.md +0 -0
  85. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/multiline_commands.md +0 -0
  86. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/os.md +0 -0
  87. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/packaging.md +0 -0
  88. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/plugins.md +0 -0
  89. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/prompt.md +0 -0
  90. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/redirection.md +0 -0
  91. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/scripting.md +0 -0
  92. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/settings.md +0 -0
  93. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/shortcuts_aliases_macros.md +0 -0
  94. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/startup_commands.md +0 -0
  95. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/table_creation.md +0 -0
  96. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/theme.md +0 -0
  97. {cmd2-3.4.0 → cmd2-3.5.1}/docs/features/transcripts.md +0 -0
  98. {cmd2-3.4.0 → cmd2-3.5.1}/docs/index.md +0 -0
  99. {cmd2-3.4.0 → cmd2-3.5.1}/docs/javascripts/readthedocs.js +0 -0
  100. {cmd2-3.4.0 → cmd2-3.5.1}/docs/migrating/incompatibilities.md +0 -0
  101. {cmd2-3.4.0 → cmd2-3.5.1}/docs/migrating/index.md +0 -0
  102. {cmd2-3.4.0 → cmd2-3.5.1}/docs/migrating/minimum.md +0 -0
  103. {cmd2-3.4.0 → cmd2-3.5.1}/docs/migrating/next_steps.md +0 -0
  104. {cmd2-3.4.0 → cmd2-3.5.1}/docs/migrating/why.md +0 -0
  105. {cmd2-3.4.0 → cmd2-3.5.1}/docs/mixins/index.md +0 -0
  106. {cmd2-3.4.0 → cmd2-3.5.1}/docs/mixins/mixin_template.md +0 -0
  107. {cmd2-3.4.0 → cmd2-3.5.1}/docs/overrides/main.html +0 -0
  108. {cmd2-3.4.0 → cmd2-3.5.1}/docs/overview/alternatives.md +0 -0
  109. {cmd2-3.4.0 → cmd2-3.5.1}/docs/overview/index.md +0 -0
  110. {cmd2-3.4.0 → cmd2-3.5.1}/docs/overview/installation.md +0 -0
  111. {cmd2-3.4.0 → cmd2-3.5.1}/docs/overview/integrating.md +0 -0
  112. {cmd2-3.4.0 → cmd2-3.5.1}/docs/overview/resources.md +0 -0
  113. {cmd2-3.4.0 → cmd2-3.5.1}/docs/stylesheets/cmd2.css +0 -0
  114. {cmd2-3.4.0 → cmd2-3.5.1}/docs/testing.md +0 -0
  115. {cmd2-3.4.0 → cmd2-3.5.1}/docs/upgrades.md +0 -0
  116. {cmd2-3.4.0 → cmd2-3.5.1}/examples/.cmd2rc +0 -0
  117. {cmd2-3.4.0 → cmd2-3.5.1}/examples/README.md +0 -0
  118. {cmd2-3.4.0 → cmd2-3.5.1}/examples/argparse_completion.py +0 -0
  119. {cmd2-3.4.0 → cmd2-3.5.1}/examples/argparse_example.py +0 -0
  120. {cmd2-3.4.0 → cmd2-3.5.1}/examples/async_call.py +0 -0
  121. {cmd2-3.4.0 → cmd2-3.5.1}/examples/async_printing.py +0 -0
  122. {cmd2-3.4.0 → cmd2-3.5.1}/examples/basic_completion.py +0 -0
  123. {cmd2-3.4.0 → cmd2-3.5.1}/examples/cmd_as_argument.py +0 -0
  124. {cmd2-3.4.0 → cmd2-3.5.1}/examples/color.py +0 -0
  125. {cmd2-3.4.0 → cmd2-3.5.1}/examples/command_sets.py +0 -0
  126. {cmd2-3.4.0 → cmd2-3.5.1}/examples/custom_parser.py +0 -0
  127. {cmd2-3.4.0 → cmd2-3.5.1}/examples/custom_types.py +0 -0
  128. {cmd2-3.4.0 → cmd2-3.5.1}/examples/default_categories.py +0 -0
  129. {cmd2-3.4.0 → cmd2-3.5.1}/examples/dynamic_commands.py +0 -0
  130. {cmd2-3.4.0 → cmd2-3.5.1}/examples/environment.py +0 -0
  131. {cmd2-3.4.0 → cmd2-3.5.1}/examples/event_loops.py +0 -0
  132. {cmd2-3.4.0 → cmd2-3.5.1}/examples/exit_code.py +0 -0
  133. {cmd2-3.4.0 → cmd2-3.5.1}/examples/getting_started.py +0 -0
  134. {cmd2-3.4.0 → cmd2-3.5.1}/examples/hello_cmd2.py +0 -0
  135. {cmd2-3.4.0 → cmd2-3.5.1}/examples/help_categories.py +0 -0
  136. {cmd2-3.4.0 → cmd2-3.5.1}/examples/hooks.py +0 -0
  137. {cmd2-3.4.0 → cmd2-3.5.1}/examples/migrating.py +0 -0
  138. {cmd2-3.4.0 → cmd2-3.5.1}/examples/mixin.py +0 -0
  139. {cmd2-3.4.0 → cmd2-3.5.1}/examples/modular_commands/__init__.py +0 -0
  140. {cmd2-3.4.0 → cmd2-3.5.1}/examples/modular_commands/commandset_basic.py +0 -0
  141. {cmd2-3.4.0 → cmd2-3.5.1}/examples/modular_commands/commandset_complex.py +0 -0
  142. {cmd2-3.4.0 → cmd2-3.5.1}/examples/modular_commands/commandset_custominit.py +0 -0
  143. {cmd2-3.4.0 → cmd2-3.5.1}/examples/modular_commands.py +0 -0
  144. {cmd2-3.4.0 → cmd2-3.5.1}/examples/paged_output.py +0 -0
  145. {cmd2-3.4.0 → cmd2-3.5.1}/examples/persistent_history.py +0 -0
  146. {cmd2-3.4.0 → cmd2-3.5.1}/examples/pretty_print.py +0 -0
  147. {cmd2-3.4.0 → cmd2-3.5.1}/examples/python_scripting.py +0 -0
  148. {cmd2-3.4.0 → cmd2-3.5.1}/examples/read_input.py +0 -0
  149. {cmd2-3.4.0 → cmd2-3.5.1}/examples/remove_builtin_commands.py +0 -0
  150. {cmd2-3.4.0 → cmd2-3.5.1}/examples/remove_settable.py +0 -0
  151. {cmd2-3.4.0 → cmd2-3.5.1}/examples/rich_tables.py +0 -0
  152. {cmd2-3.4.0 → cmd2-3.5.1}/examples/rich_theme.py +0 -0
  153. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/arg_printer.py +0 -0
  154. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/conditional.py +0 -0
  155. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/nested.txt +0 -0
  156. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/quit.txt +0 -0
  157. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/save_help_text.py +0 -0
  158. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/script.py +0 -0
  159. {cmd2-3.4.0 → cmd2-3.5.1}/examples/scripts/script.txt +0 -0
  160. {cmd2-3.4.0 → cmd2-3.5.1}/examples/tmux_launch.sh +0 -0
  161. {cmd2-3.4.0 → cmd2-3.5.1}/examples/tmux_split.sh +0 -0
  162. {cmd2-3.4.0 → cmd2-3.5.1}/examples/transcript_example.py +0 -0
  163. {cmd2-3.4.0 → cmd2-3.5.1}/examples/transcripts/exampleSession.txt +0 -0
  164. {cmd2-3.4.0 → cmd2-3.5.1}/examples/transcripts/pirate.transcript +0 -0
  165. {cmd2-3.4.0 → cmd2-3.5.1}/examples/transcripts/quit.txt +0 -0
  166. {cmd2-3.4.0 → cmd2-3.5.1}/examples/transcripts/transcript_regex.txt +0 -0
  167. {cmd2-3.4.0 → cmd2-3.5.1}/examples/unicode_commands.py +0 -0
  168. {cmd2-3.4.0 → cmd2-3.5.1}/mkdocs.yml +0 -0
  169. {cmd2-3.4.0 → cmd2-3.5.1}/package.json +0 -0
  170. {cmd2-3.4.0 → cmd2-3.5.1}/ruff.toml +0 -0
  171. {cmd2-3.4.0 → cmd2-3.5.1}/scripts/validate_tag.py +0 -0
  172. {cmd2-3.4.0 → cmd2-3.5.1}/setup.cfg +0 -0
  173. {cmd2-3.4.0 → cmd2-3.5.1}/tests/.cmd2rc +0 -0
  174. {cmd2-3.4.0 → cmd2-3.5.1}/tests/__init__.py +0 -0
  175. {cmd2-3.4.0 → cmd2-3.5.1}/tests/conftest.py +0 -0
  176. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/echo.py +0 -0
  177. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/environment.py +0 -0
  178. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/help.py +0 -0
  179. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/py_locals.py +0 -0
  180. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/pyscript_dir.py +0 -0
  181. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/raises_exception.py +0 -0
  182. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/recursive.py +0 -0
  183. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/self_in_py.py +0 -0
  184. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/stdout_capture.py +0 -0
  185. {cmd2-3.4.0 → cmd2-3.5.1}/tests/pyscript/stop.py +0 -0
  186. {cmd2-3.4.0 → cmd2-3.5.1}/tests/relative_multiple.txt +0 -0
  187. {cmd2-3.4.0 → cmd2-3.5.1}/tests/script.py +0 -0
  188. {cmd2-3.4.0 → cmd2-3.5.1}/tests/script.txt +0 -0
  189. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/binary.bin +0 -0
  190. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/empty.txt +0 -0
  191. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/help.txt +0 -0
  192. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/nested.txt +0 -0
  193. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/one_down.txt +0 -0
  194. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/postcmds.txt +0 -0
  195. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/precmds.txt +0 -0
  196. {cmd2-3.4.0 → cmd2-3.5.1}/tests/scripts/utf8.txt +0 -0
  197. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_argparse.py +0 -0
  198. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_argparse_completer.py +0 -0
  199. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_argparse_custom.py +0 -0
  200. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_argparse_subcommands.py +0 -0
  201. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_async_alert.py +0 -0
  202. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_categories.py +0 -0
  203. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_commandset.py +0 -0
  204. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_completion.py +0 -0
  205. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_future_annotations.py +0 -0
  206. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_history.py +0 -0
  207. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_parsing.py +0 -0
  208. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_plugin.py +0 -0
  209. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_run_pyscript.py +0 -0
  210. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_string_utils.py +0 -0
  211. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_terminal_utils.py +0 -0
  212. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_transcript.py +0 -0
  213. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_utils.py +0 -0
  214. {cmd2-3.4.0 → cmd2-3.5.1}/tests/test_utils_defining_class.py +0 -0
  215. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/bol_eol.txt +0 -0
  216. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/characterclass.txt +0 -0
  217. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/dotstar.txt +0 -0
  218. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/extension_notation.txt +0 -0
  219. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/failure.txt +0 -0
  220. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/from_cmdloop.txt +0 -0
  221. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/multiline_no_regex.txt +0 -0
  222. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/multiline_regex.txt +0 -0
  223. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/no_output.txt +0 -0
  224. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/no_output_last.txt +0 -0
  225. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/singleslash.txt +0 -0
  226. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/slashes_escaped.txt +0 -0
  227. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/slashslash.txt +0 -0
  228. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/spaces.txt +0 -0
  229. {cmd2-3.4.0 → cmd2-3.5.1}/tests/transcripts/word_boundaries.txt +0 -0
@@ -1,3 +1,14 @@
1
+ ## 3.5.1 (April 24, 2026)
2
+
3
+ - Bug Fixes
4
+ - Fixed `ArgparseCompleter.print_help()` not passing file stream to recursive call.
5
+ - Fixed issue where `constants.REDIRECTION_TOKENS` was being mutated.
6
+
7
+ ## 3.5.0 (April 13, 2026)
8
+
9
+ - Bug Fixes
10
+ - Fixed issue where Rich stripped colors from text in test environments where TERM=dumb.
11
+
1
12
  ## 3.4.0 (March 3, 2026)
2
13
 
3
14
  - Enhancements
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 3.4.0
3
+ Version: 3.5.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
@@ -26,8 +26,8 @@ Requires-Dist: backports.strenum; python_version == "3.10"
26
26
  Requires-Dist: gnureadline>=8; platform_system == "Darwin"
27
27
  Requires-Dist: pyperclip>=1.8.2
28
28
  Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
29
- Requires-Dist: rich>=14.3.0
30
- Requires-Dist: rich-argparse>=1.7.1
29
+ Requires-Dist: rich>=15.0.0
30
+ Requires-Dist: rich-argparse>=1.7.2
31
31
  Requires-Dist: typing-extensions; python_version == "3.10"
32
32
  Dynamic: license-file
33
33
 
@@ -368,7 +368,7 @@ class ArgparseCompleter:
368
368
  action = remaining_positionals.popleft()
369
369
 
370
370
  # Are we at a subcommand? If so, forward to the matching completer
371
- if action == self._subcommand_action:
371
+ if self._subcommand_action is not None and action == self._subcommand_action:
372
372
  if token in self._subcommand_action.choices:
373
373
  # Merge self._parent_tokens and consumed_arg_values
374
374
  parent_tokens = {**self._parent_tokens, **consumed_arg_values}
@@ -637,7 +637,7 @@ class ArgparseCompleter:
637
637
  if parser:
638
638
  completer_type = self._cmd2_app._determine_ap_completer_type(parser)
639
639
  completer = completer_type(parser, self._cmd2_app)
640
- completer.print_help(tokens[1:])
640
+ completer.print_help(tokens[1:], file=file)
641
641
  return
642
642
 
643
643
  self._parser.print_help(file=file)
@@ -1666,10 +1666,8 @@ class Cmd:
1666
1666
  **On Failure**
1667
1667
  - Two empty lists
1668
1668
  """
1669
- import copy
1670
-
1671
1669
  unclosed_quote = ''
1672
- quotes_to_try = copy.copy(constants.QUOTES)
1670
+ quotes_to_try = [*constants.QUOTES]
1673
1671
 
1674
1672
  tmp_line = line[:endidx]
1675
1673
  tmp_endidx = endidx
@@ -3721,8 +3719,7 @@ class Cmd:
3721
3719
  return
3722
3720
 
3723
3721
  # Unquote redirection and terminator tokens
3724
- tokens_to_unquote = constants.REDIRECTION_TOKENS
3725
- tokens_to_unquote.extend(self.statement_parser.terminators)
3722
+ tokens_to_unquote = [*constants.REDIRECTION_TOKENS, *self.statement_parser.terminators]
3726
3723
  utils.unquote_specific_tokens(args.command_args, tokens_to_unquote)
3727
3724
 
3728
3725
  # Build the alias value string
@@ -3801,8 +3798,7 @@ class Cmd:
3801
3798
  """List some or all aliases as 'alias create' commands."""
3802
3799
  self.last_result = {} # dict[alias_name, alias_value]
3803
3800
 
3804
- tokens_to_quote = constants.REDIRECTION_TOKENS
3805
- tokens_to_quote.extend(self.statement_parser.terminators)
3801
+ tokens_to_quote = [*constants.REDIRECTION_TOKENS, *self.statement_parser.terminators]
3806
3802
 
3807
3803
  to_list = utils.remove_duplicates(args.names) if args.names else sorted(self.aliases, key=self.default_sort_key)
3808
3804
 
@@ -3964,8 +3960,7 @@ class Cmd:
3964
3960
  return
3965
3961
 
3966
3962
  # Unquote redirection and terminator tokens
3967
- tokens_to_unquote = constants.REDIRECTION_TOKENS
3968
- tokens_to_unquote.extend(self.statement_parser.terminators)
3963
+ tokens_to_unquote = [*constants.REDIRECTION_TOKENS, *self.statement_parser.terminators]
3969
3964
  utils.unquote_specific_tokens(args.command_args, tokens_to_unquote)
3970
3965
 
3971
3966
  # Build the macro value string
@@ -4087,8 +4082,7 @@ class Cmd:
4087
4082
  """List macros."""
4088
4083
  self.last_result = {} # dict[macro_name, macro_value]
4089
4084
 
4090
- tokens_to_quote = constants.REDIRECTION_TOKENS
4091
- tokens_to_quote.extend(self.statement_parser.terminators)
4085
+ tokens_to_quote = [*constants.REDIRECTION_TOKENS, *self.statement_parser.terminators]
4092
4086
 
4093
4087
  to_list = utils.remove_duplicates(args.names) if args.names else sorted(self.macros, key=self.default_sort_key)
4094
4088
 
@@ -7,12 +7,12 @@ INFINITY = float('inf')
7
7
 
8
8
  # Used for command parsing, output redirection, tab completion and word
9
9
  # breaks. Do not change.
10
- QUOTES = ['"', "'"]
10
+ QUOTES = ('"', "'")
11
11
  REDIRECTION_PIPE = '|'
12
12
  REDIRECTION_OUTPUT = '>'
13
13
  REDIRECTION_APPEND = '>>'
14
- REDIRECTION_CHARS = [REDIRECTION_PIPE, REDIRECTION_OUTPUT]
15
- REDIRECTION_TOKENS = [REDIRECTION_PIPE, REDIRECTION_OUTPUT, REDIRECTION_APPEND]
14
+ REDIRECTION_CHARS = (REDIRECTION_PIPE, REDIRECTION_OUTPUT)
15
+ REDIRECTION_TOKENS = (REDIRECTION_PIPE, REDIRECTION_OUTPUT, REDIRECTION_APPEND)
16
16
  COMMENT_CHAR = '#'
17
17
  MULTILINE_TERMINATOR = ';'
18
18
 
@@ -298,10 +298,12 @@ class StatementParser:
298
298
  # the string (\Z matches the end of the string even if it
299
299
  # contains multiple lines)
300
300
  #
301
- invalid_command_chars = []
302
- invalid_command_chars.extend(constants.QUOTES)
303
- invalid_command_chars.extend(constants.REDIRECTION_CHARS)
304
- invalid_command_chars.extend(self.terminators)
301
+ invalid_command_chars = (
302
+ *constants.QUOTES,
303
+ *constants.REDIRECTION_CHARS,
304
+ *self.terminators,
305
+ )
306
+
305
307
  # escape each item so it will for sure get treated as a literal
306
308
  second_group_items = [re.escape(x) for x in invalid_command_chars]
307
309
  # add the whitespace and end of string, not escaped because they
@@ -352,9 +354,8 @@ class StatementParser:
352
354
  return False, errmsg
353
355
 
354
356
  errmsg = 'cannot contain: whitespace, quotes, '
355
- errchars = []
356
- errchars.extend(constants.REDIRECTION_CHARS)
357
- errchars.extend(self.terminators)
357
+
358
+ errchars = (*constants.REDIRECTION_CHARS, *self.terminators)
358
359
  errmsg += ', '.join([shlex.quote(x) for x in errchars])
359
360
 
360
361
  match = self._command_pattern.search(word)
@@ -677,9 +678,8 @@ class StatementParser:
677
678
  :param tokens: the tokens as parsed by shlex
678
679
  :return: a new list of tokens, further split using punctuation
679
680
  """
680
- punctuation: list[str] = []
681
- punctuation.extend(self.terminators)
682
- punctuation.extend(constants.REDIRECTION_CHARS)
681
+ # Using a set for faster lookups
682
+ punctuation = {*self.terminators, *constants.REDIRECTION_CHARS}
683
683
 
684
684
  punctuated_tokens = []
685
685
 
@@ -136,8 +136,9 @@ class Cmd2BaseConsole(Console):
136
136
  :param kwargs: keyword arguments passed to the parent Console class.
137
137
  :raises TypeError: if disallowed keyword argument is passed in.
138
138
  """
139
- # Don't allow force_terminal or force_interactive to be passed in, as their
140
- # behavior is controlled by the ALLOW_STYLE setting.
139
+ # These settings are controlled by the ALLOW_STYLE setting and cannot be overridden.
140
+ if "color_system" in kwargs:
141
+ raise TypeError("Passing 'color_system' is not allowed. Its behavior is controlled by the 'ALLOW_STYLE' setting.")
141
142
  if "force_terminal" in kwargs:
142
143
  raise TypeError(
143
144
  "Passing 'force_terminal' is not allowed. Its behavior is controlled by the 'ALLOW_STYLE' setting."
@@ -157,18 +158,24 @@ class Cmd2BaseConsole(Console):
157
158
 
158
159
  force_terminal: bool | None = None
159
160
  force_interactive: bool | None = None
161
+ allow_style = False
160
162
 
161
163
  if ALLOW_STYLE == AllowStyle.ALWAYS:
162
164
  force_terminal = True
165
+ allow_style = True
163
166
 
164
167
  # Turn off interactive mode if dest is not actually a terminal which supports it
165
168
  tmp_console = Console(file=file)
166
169
  force_interactive = tmp_console.is_interactive
170
+ elif ALLOW_STYLE == AllowStyle.TERMINAL:
171
+ tmp_console = Console(file=file)
172
+ allow_style = tmp_console.is_terminal
167
173
  elif ALLOW_STYLE == AllowStyle.NEVER:
168
174
  force_terminal = False
169
175
 
170
176
  super().__init__(
171
177
  file=file,
178
+ color_system="truecolor" if allow_style else None,
172
179
  force_terminal=force_terminal,
173
180
  force_interactive=force_interactive,
174
181
  theme=APP_THEME,
@@ -412,6 +419,7 @@ def rich_text_to_string(text: Text) -> str:
412
419
  """
413
420
  console = Console(
414
421
  force_terminal=True,
422
+ color_system="truecolor",
415
423
  soft_wrap=True,
416
424
  no_color=False,
417
425
  theme=APP_THEME,
@@ -477,64 +485,3 @@ def prepare_objects_for_rendering(*objects: Any) -> tuple[Any, ...]:
477
485
  object_list[i] = Text.from_ansi(renderable_as_str)
478
486
 
479
487
  return tuple(object_list)
480
-
481
-
482
- ###################################################################################
483
- # Rich Library Monkey Patches
484
- #
485
- # These patches fix specific bugs in the Rich library. They are conditional and
486
- # will only be applied if the bug is detected. When the bugs are fixed in a
487
- # future Rich release, these patches and their corresponding tests should be
488
- # removed.
489
- ###################################################################################
490
-
491
- ###################################################################################
492
- # Text.from_ansi() monkey patch
493
- ###################################################################################
494
-
495
- # Save original Text.from_ansi() so we can call it in our wrapper
496
- _orig_text_from_ansi = Text.from_ansi
497
-
498
-
499
- @classmethod # type: ignore[misc]
500
- def _from_ansi_wrapper(cls: type[Text], text: str, *args: Any, **kwargs: Any) -> Text: # noqa: ARG001
501
- r"""Wrap Text.from_ansi() to fix its trailing newline bug.
502
-
503
- This wrapper handles an issue where Text.from_ansi() removes the
504
- trailing line break from a string (e.g. "Hello\n" becomes "Hello").
505
-
506
- There is currently a pull request on Rich to fix this.
507
- https://github.com/Textualize/rich/pull/3793
508
- """
509
- result = _orig_text_from_ansi(text, *args, **kwargs)
510
-
511
- # If the original string ends with a recognized line break character,
512
- # then restore the missing newline. We use "\n" because Text.from_ansi()
513
- # converts all line breaks into newlines.
514
- # Source: https://docs.python.org/3/library/stdtypes.html#str.splitlines
515
- line_break_chars = {
516
- "\n", # Line Feed
517
- "\r", # Carriage Return
518
- "\v", # Vertical Tab
519
- "\f", # Form Feed
520
- "\x1c", # File Separator
521
- "\x1d", # Group Separator
522
- "\x1e", # Record Separator
523
- "\x85", # Next Line (NEL)
524
- "\u2028", # Line Separator
525
- "\u2029", # Paragraph Separator
526
- }
527
- if text and text[-1] in line_break_chars:
528
- result.append("\n")
529
-
530
- return result
531
-
532
-
533
- def _from_ansi_has_newline_bug() -> bool:
534
- """Check if Test.from_ansi() strips the trailing line break from a string."""
535
- return Text.from_ansi("\n") == Text.from_ansi("")
536
-
537
-
538
- # Only apply the monkey patch if the bug is present
539
- if _from_ansi_has_newline_bug():
540
- Text.from_ansi = _from_ansi_wrapper # type: ignore[assignment]
@@ -75,7 +75,7 @@ class Settable:
75
75
  settable_object: object,
76
76
  *,
77
77
  settable_attrib_name: str | None = None,
78
- onchange_cb: Callable[[str, _T, _T], Any] | None = None,
78
+ onchange_cb: Callable[[str, Any, Any], Any] | None = None,
79
79
  choices: Iterable[Any] | None = None,
80
80
  choices_provider: ChoicesProviderFunc | None = None,
81
81
  completer: CompleterFunc | None = None,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 3.4.0
3
+ Version: 3.5.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
@@ -26,8 +26,8 @@ Requires-Dist: backports.strenum; python_version == "3.10"
26
26
  Requires-Dist: gnureadline>=8; platform_system == "Darwin"
27
27
  Requires-Dist: pyperclip>=1.8.2
28
28
  Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
29
- Requires-Dist: rich>=14.3.0
30
- Requires-Dist: rich-argparse>=1.7.1
29
+ Requires-Dist: rich>=15.0.0
30
+ Requires-Dist: rich-argparse>=1.7.2
31
31
  Requires-Dist: typing-extensions; python_version == "3.10"
32
32
  Dynamic: license-file
33
33
 
@@ -119,7 +119,6 @@ examples/argparse_example.py
119
119
  examples/async_call.py
120
120
  examples/async_printing.py
121
121
  examples/basic_completion.py
122
- examples/cmd2_history.dat
123
122
  examples/cmd_as_argument.py
124
123
  examples/color.py
125
124
  examples/command_sets.py
@@ -1,6 +1,6 @@
1
1
  pyperclip>=1.8.2
2
- rich>=14.3.0
3
- rich-argparse>=1.7.1
2
+ rich>=15.0.0
3
+ rich-argparse>=1.7.2
4
4
 
5
5
  [:platform_system == "Darwin"]
6
6
  gnureadline>=8
@@ -33,8 +33,8 @@ dependencies = [
33
33
  "gnureadline>=8; platform_system == 'Darwin'",
34
34
  "pyperclip>=1.8.2",
35
35
  "pyreadline3>=3.4; platform_system == 'Windows'",
36
- "rich>=14.3.0",
37
- "rich-argparse>=1.7.1",
36
+ "rich>=15.0.0",
37
+ "rich-argparse>=1.7.2",
38
38
  "typing-extensions; python_version == '3.10'",
39
39
  ]
40
40
 
@@ -2964,7 +2964,6 @@ class AnsiApp(cmd2.Cmd):
2964
2964
 
2965
2965
  def do_echo_error(self, args) -> None:
2966
2966
  self.poutput(args, style=Cmd2Style.ERROR)
2967
- # perror uses colors by default
2968
2967
  self.perror(args)
2969
2968
 
2970
2969
 
@@ -2974,21 +2973,18 @@ def test_ansi_pouterr_always_tty(mocker, capsys) -> None:
2974
2973
  mocker.patch.object(app.stdout, 'isatty', return_value=True)
2975
2974
  mocker.patch.object(sys.stderr, 'isatty', return_value=True)
2976
2975
 
2976
+ expected_plain = 'oopsie\n'
2977
+ expected_styled = su.stylize('oopsie\n', Cmd2Style.ERROR)
2978
+
2977
2979
  app.onecmd_plus_hooks('echo_error oopsie')
2978
2980
  out, err = capsys.readouterr()
2979
- # if colors are on, the output should have some ANSI style sequences in it
2980
- assert len(out) > len('oopsie\n')
2981
- assert 'oopsie' in out
2982
- assert len(err) > len('oopsie\n')
2983
- assert 'oopsie' in err
2981
+ assert out == expected_styled
2982
+ assert err == expected_styled
2984
2983
 
2985
- # but this one shouldn't
2986
2984
  app.onecmd_plus_hooks('echo oopsie')
2987
2985
  out, err = capsys.readouterr()
2988
- assert out == 'oopsie\n'
2989
- # errors always have colors
2990
- assert len(err) > len('oopsie\n')
2991
- assert 'oopsie' in err
2986
+ assert out == expected_plain
2987
+ assert err == expected_styled
2992
2988
 
2993
2989
 
2994
2990
  @with_ansi_style(ru.AllowStyle.ALWAYS)
@@ -2997,21 +2993,18 @@ def test_ansi_pouterr_always_notty(mocker, capsys) -> None:
2997
2993
  mocker.patch.object(app.stdout, 'isatty', return_value=False)
2998
2994
  mocker.patch.object(sys.stderr, 'isatty', return_value=False)
2999
2995
 
2996
+ expected_plain = 'oopsie\n'
2997
+ expected_styled = su.stylize('oopsie\n', Cmd2Style.ERROR)
2998
+
3000
2999
  app.onecmd_plus_hooks('echo_error oopsie')
3001
3000
  out, err = capsys.readouterr()
3002
- # if colors are on, the output should have some ANSI style sequences in it
3003
- assert len(out) > len('oopsie\n')
3004
- assert 'oopsie' in out
3005
- assert len(err) > len('oopsie\n')
3006
- assert 'oopsie' in err
3001
+ assert out == expected_styled
3002
+ assert err == expected_styled
3007
3003
 
3008
- # but this one shouldn't
3009
3004
  app.onecmd_plus_hooks('echo oopsie')
3010
3005
  out, err = capsys.readouterr()
3011
- assert out == 'oopsie\n'
3012
- # errors always have colors
3013
- assert len(err) > len('oopsie\n')
3014
- assert 'oopsie' in err
3006
+ assert out == expected_plain
3007
+ assert err == expected_styled
3015
3008
 
3016
3009
 
3017
3010
  @with_ansi_style(ru.AllowStyle.TERMINAL)
@@ -3020,20 +3013,18 @@ def test_ansi_terminal_tty(mocker, capsys) -> None:
3020
3013
  mocker.patch.object(app.stdout, 'isatty', return_value=True)
3021
3014
  mocker.patch.object(sys.stderr, 'isatty', return_value=True)
3022
3015
 
3016
+ expected_plain = 'oopsie\n'
3017
+ expected_styled = su.stylize('oopsie\n', Cmd2Style.ERROR)
3018
+
3023
3019
  app.onecmd_plus_hooks('echo_error oopsie')
3024
- # if colors are on, the output should have some ANSI style sequences in it
3025
3020
  out, err = capsys.readouterr()
3026
- assert len(out) > len('oopsie\n')
3027
- assert 'oopsie' in out
3028
- assert len(err) > len('oopsie\n')
3029
- assert 'oopsie' in err
3021
+ assert out == expected_styled
3022
+ assert err == expected_styled
3030
3023
 
3031
- # but this one shouldn't
3032
3024
  app.onecmd_plus_hooks('echo oopsie')
3033
3025
  out, err = capsys.readouterr()
3034
- assert out == 'oopsie\n'
3035
- assert len(err) > len('oopsie\n')
3036
- assert 'oopsie' in err
3026
+ assert out == expected_plain
3027
+ assert err == expected_styled
3037
3028
 
3038
3029
 
3039
3030
  @with_ansi_style(ru.AllowStyle.TERMINAL)
@@ -1,5 +1,7 @@
1
1
  """Unit testing for cmd2/rich_utils.py module"""
2
2
 
3
+ from unittest import mock
4
+
3
5
  import pytest
4
6
  import rich.box
5
7
  from rich.console import Console
@@ -18,6 +20,10 @@ from .conftest import with_ansi_style
18
20
 
19
21
  def test_cmd2_base_console() -> None:
20
22
  # Test the keyword arguments which are not allowed.
23
+ with pytest.raises(TypeError) as excinfo:
24
+ ru.Cmd2BaseConsole(color_system="auto")
25
+ assert 'color_system' in str(excinfo.value)
26
+
21
27
  with pytest.raises(TypeError) as excinfo:
22
28
  ru.Cmd2BaseConsole(force_terminal=True)
23
29
  assert 'force_terminal' in str(excinfo.value)
@@ -74,7 +80,12 @@ def test_indented_table() -> None:
74
80
  [
75
81
  (Text("Hello"), "Hello"),
76
82
  (Text("Hello\n"), "Hello\n"),
77
- (Text("Hello", style="blue"), "\x1b[34mHello\x1b[0m"),
83
+ # Test standard color support
84
+ (Text("Standard", style="blue"), "\x1b[34mStandard\x1b[0m"),
85
+ # Test 256-color support
86
+ (Text("256-color", style=Color.NAVY_BLUE), "\x1b[38;5;17m256-color\x1b[0m"),
87
+ # Test 24-bit color (TrueColor) support
88
+ (Text("TrueColor", style="#123456"), "\x1b[38;2;18;52;86mTrueColor\x1b[0m"),
78
89
  ],
79
90
  )
80
91
  def test_rich_text_to_string(rich_text: Text, string: str) -> None:
@@ -110,42 +121,6 @@ def test_set_theme() -> None:
110
121
  assert ru.APP_THEME.styles[rich_style_key] == theme[rich_style_key]
111
122
 
112
123
 
113
- def test_from_ansi_wrapper() -> None:
114
- # Check if we are still patching Text.from_ansi(). If this check fails, then Rich
115
- # has fixed the bug. Therefore, we can remove this test function and ru._from_ansi_wrapper.
116
- assert Text.from_ansi.__func__ is ru._from_ansi_wrapper.__func__ # type: ignore[attr-defined]
117
-
118
- # Line breaks recognized by str.splitlines().
119
- # Source: https://docs.python.org/3/library/stdtypes.html#str.splitlines
120
- line_breaks = {
121
- "\n", # Line Feed
122
- "\r", # Carriage Return
123
- "\r\n", # Carriage Return + Line Feed
124
- "\v", # Vertical Tab
125
- "\f", # Form Feed
126
- "\x1c", # File Separator
127
- "\x1d", # Group Separator
128
- "\x1e", # Record Separator
129
- "\x85", # Next Line (NEL)
130
- "\u2028", # Line Separator
131
- "\u2029", # Paragraph Separator
132
- }
133
-
134
- # Test all line breaks
135
- for lb in line_breaks:
136
- input_string = f"Text{lb}"
137
- expected_output = input_string.replace(lb, "\n")
138
- assert Text.from_ansi(input_string).plain == expected_output
139
-
140
- # Test string without trailing line break
141
- input_string = "No trailing\nline break"
142
- assert Text.from_ansi(input_string).plain == input_string
143
-
144
- # Test empty string
145
- input_string = ""
146
- assert Text.from_ansi(input_string).plain == input_string
147
-
148
-
149
124
  @with_ansi_style(ru.AllowStyle.ALWAYS)
150
125
  def test_cmd2_base_console_print() -> None:
151
126
  """Test that Cmd2BaseConsole.print() correctly propagates formatting overrides to structured renderables."""
@@ -192,3 +167,88 @@ def test_cmd2_base_console_log() -> None:
192
167
  # Verify stack offset: the log line should point to this file, not rich_utils.py
193
168
  # Rich logs include the filename and line number on the right.
194
169
  assert "test_rich_utils.py" in result
170
+
171
+
172
+ @with_ansi_style(ru.AllowStyle.ALWAYS)
173
+ def test_cmd2_base_console_init_always_interactive_true() -> None:
174
+ """Test Cmd2BaseConsole initialization when ALLOW_STYLE is ALWAYS and is_interactive is True."""
175
+ with (
176
+ mock.patch('rich.console.Console.__init__', return_value=None) as mock_base_init,
177
+ mock.patch('cmd2.rich_utils.Console', autospec=True) as mock_detect_console_class,
178
+ ):
179
+ mock_detect_console = mock_detect_console_class.return_value
180
+ mock_detect_console.is_interactive = True
181
+
182
+ ru.Cmd2BaseConsole()
183
+
184
+ # Verify arguments passed to super().__init__
185
+ _, kwargs = mock_base_init.call_args
186
+ assert kwargs['color_system'] == "truecolor"
187
+ assert kwargs['force_terminal'] is True
188
+ assert kwargs['force_interactive'] is True
189
+
190
+
191
+ @with_ansi_style(ru.AllowStyle.ALWAYS)
192
+ def test_cmd2_base_console_init_always_interactive_false() -> None:
193
+ """Test Cmd2BaseConsole initialization when ALLOW_STYLE is ALWAYS and is_interactive is False."""
194
+ with (
195
+ mock.patch('rich.console.Console.__init__', return_value=None) as mock_base_init,
196
+ mock.patch('cmd2.rich_utils.Console', autospec=True) as mock_detect_console_class,
197
+ ):
198
+ mock_detect_console = mock_detect_console_class.return_value
199
+ mock_detect_console.is_interactive = False
200
+
201
+ ru.Cmd2BaseConsole()
202
+
203
+ _, kwargs = mock_base_init.call_args
204
+ assert kwargs['color_system'] == "truecolor"
205
+ assert kwargs['force_terminal'] is True
206
+ assert kwargs['force_interactive'] is False
207
+
208
+
209
+ @with_ansi_style(ru.AllowStyle.TERMINAL)
210
+ def test_cmd2_base_console_init_terminal_true() -> None:
211
+ """Test Cmd2BaseConsole initialization when ALLOW_STYLE is TERMINAL and it is a terminal."""
212
+ with (
213
+ mock.patch('rich.console.Console.__init__', return_value=None) as mock_base_init,
214
+ mock.patch('cmd2.rich_utils.Console', autospec=True) as mock_detect_console_class,
215
+ ):
216
+ mock_detect_console = mock_detect_console_class.return_value
217
+ mock_detect_console.is_terminal = True
218
+
219
+ ru.Cmd2BaseConsole()
220
+
221
+ _, kwargs = mock_base_init.call_args
222
+ assert kwargs['color_system'] == "truecolor"
223
+ assert kwargs['force_terminal'] is None
224
+ assert kwargs['force_interactive'] is None
225
+
226
+
227
+ @with_ansi_style(ru.AllowStyle.TERMINAL)
228
+ def test_cmd2_base_console_init_terminal_false() -> None:
229
+ """Test Cmd2BaseConsole initialization when ALLOW_STYLE is TERMINAL and it is not a terminal."""
230
+ with (
231
+ mock.patch('rich.console.Console.__init__', return_value=None) as mock_base_init,
232
+ mock.patch('cmd2.rich_utils.Console', autospec=True) as mock_detect_console_class,
233
+ ):
234
+ mock_detect_console = mock_detect_console_class.return_value
235
+ mock_detect_console.is_terminal = False
236
+
237
+ ru.Cmd2BaseConsole()
238
+
239
+ _, kwargs = mock_base_init.call_args
240
+ assert kwargs['color_system'] is None
241
+ assert kwargs['force_terminal'] is None
242
+ assert kwargs['force_interactive'] is None
243
+
244
+
245
+ @with_ansi_style(ru.AllowStyle.NEVER)
246
+ def test_cmd2_base_console_init_never() -> None:
247
+ """Test Cmd2BaseConsole initialization when ALLOW_STYLE is NEVER."""
248
+ with mock.patch('rich.console.Console.__init__', return_value=None) as mock_base_init:
249
+ ru.Cmd2BaseConsole()
250
+
251
+ _, kwargs = mock_base_init.call_args
252
+ assert kwargs['color_system'] is None
253
+ assert kwargs['force_terminal'] is False
254
+ assert kwargs['force_interactive'] is None
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes