cmd2 3.0.0rc1__tar.gz → 3.1.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 (331) hide show
  1. {cmd2-3.0.0rc1 → cmd2-3.1.0}/.pre-commit-config.yaml +2 -2
  2. {cmd2-3.0.0rc1 → cmd2-3.1.0}/CHANGELOG.md +20 -1
  3. {cmd2-3.0.0rc1 → cmd2-3.1.0}/Makefile +7 -7
  4. {cmd2-3.0.0rc1 → cmd2-3.1.0}/PKG-INFO +7 -6
  5. {cmd2-3.0.0rc1 → cmd2-3.1.0}/README.md +4 -4
  6. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/argparse_completer.py +1 -1
  7. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/argparse_custom.py +1 -1
  8. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/cmd2.py +66 -46
  9. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/parsing.py +3 -3
  10. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/py_bridge.py +1 -1
  11. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/transcript.py +1 -1
  12. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2.egg-info/PKG-INFO +7 -6
  13. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2.egg-info/requires.txt +1 -1
  14. cmd2-3.1.0/docs/examples/examples.md +3 -0
  15. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/examples/getting_started.md +1 -3
  16. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/generating_output.md +1 -1
  17. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/history.md +1 -1
  18. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/initialization.md +1 -3
  19. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/modular_commands.md +17 -16
  20. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/settings.md +1 -3
  21. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/index.md +19 -26
  22. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/migrating/why.md +5 -0
  23. {cmd2-3.0.0rc1 → cmd2-3.1.0}/mkdocs.yml +4 -12
  24. {cmd2-3.0.0rc1 → cmd2-3.1.0}/package.json +1 -1
  25. {cmd2-3.0.0rc1 → cmd2-3.1.0}/pyproject.toml +30 -33
  26. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tasks.py +4 -51
  27. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_cmd2.py +15 -0
  28. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_completion.py +8 -10
  29. cmd2-3.0.0rc1/docs/examples/examples.md +0 -5
  30. {cmd2-3.0.0rc1 → cmd2-3.1.0}/.prettierignore +0 -0
  31. {cmd2-3.0.0rc1 → cmd2-3.1.0}/.prettierrc +0 -0
  32. {cmd2-3.0.0rc1 → cmd2-3.1.0}/GEMINI.md +0 -0
  33. {cmd2-3.0.0rc1 → cmd2-3.1.0}/LICENSE +0 -0
  34. {cmd2-3.0.0rc1 → cmd2-3.1.0}/MANIFEST.in +0 -0
  35. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/__init__.py +0 -0
  36. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/clipboard.py +0 -0
  37. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/colors.py +0 -0
  38. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/command_definition.py +0 -0
  39. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/constants.py +0 -0
  40. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/decorators.py +0 -0
  41. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/exceptions.py +0 -0
  42. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/history.py +0 -0
  43. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/plugin.py +0 -0
  44. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/py.typed +0 -0
  45. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/rich_utils.py +0 -0
  46. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/rl_utils.py +0 -0
  47. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/string_utils.py +0 -0
  48. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/styles.py +0 -0
  49. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/terminal_utils.py +0 -0
  50. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2/utils.py +0 -0
  51. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2.egg-info/SOURCES.txt +0 -0
  52. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2.egg-info/dependency_links.txt +0 -0
  53. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2.egg-info/top_level.txt +0 -0
  54. {cmd2-3.0.0rc1 → cmd2-3.1.0}/cmd2.png +0 -0
  55. {cmd2-3.0.0rc1 → cmd2-3.1.0}/codecov.yml +0 -0
  56. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/argparse_completer.md +0 -0
  57. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/argparse_custom.md +0 -0
  58. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/clipboard.md +0 -0
  59. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/cmd.md +0 -0
  60. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/colors.md +0 -0
  61. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/command_definition.md +0 -0
  62. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/constants.md +0 -0
  63. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/decorators.md +0 -0
  64. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/exceptions.md +0 -0
  65. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/history.md +0 -0
  66. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/index.md +0 -0
  67. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/parsing.md +0 -0
  68. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/plugin.md +0 -0
  69. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/py_bridge.md +0 -0
  70. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/rich_utils.md +0 -0
  71. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/rl_utils.md +0 -0
  72. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/string_utils.md +0 -0
  73. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/styles.md +0 -0
  74. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/terminal_utils.md +0 -0
  75. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/transcript.md +0 -0
  76. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/api/utils.md +0 -0
  77. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/doc_conventions.md +0 -0
  78. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/examples/alternate_event_loops.md +0 -0
  79. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/examples/index.md +0 -0
  80. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/argument_processing.md +0 -0
  81. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/builtin_commands.md +0 -0
  82. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/clipboard.md +0 -0
  83. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/commands.md +0 -0
  84. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/completion.md +0 -0
  85. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/disable_commands.md +0 -0
  86. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/embedded_python_shells.md +0 -0
  87. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/help.md +0 -0
  88. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/hooks.md +0 -0
  89. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/index.md +0 -0
  90. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/misc.md +0 -0
  91. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/multiline_commands.md +0 -0
  92. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/os.md +0 -0
  93. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/packaging.md +0 -0
  94. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/plugins.md +0 -0
  95. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/prompt.md +0 -0
  96. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/redirection.md +0 -0
  97. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/scripting.md +0 -0
  98. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/shortcuts_aliases_macros.md +0 -0
  99. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/startup_commands.md +0 -0
  100. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/table_creation.md +0 -0
  101. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/theme.md +0 -0
  102. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/features/transcripts.md +0 -0
  103. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/javascripts/readthedocs.js +0 -0
  104. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/migrating/incompatibilities.md +0 -0
  105. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/migrating/index.md +0 -0
  106. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/migrating/minimum.md +0 -0
  107. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/migrating/next_steps.md +0 -0
  108. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/mixins/index.md +0 -0
  109. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/mixins/mixin_template.md +0 -0
  110. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/overrides/main.html +0 -0
  111. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/overview/alternatives.md +0 -0
  112. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/overview/index.md +0 -0
  113. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/overview/installation.md +0 -0
  114. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/overview/integrating.md +0 -0
  115. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/overview/resources.md +0 -0
  116. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/stylesheets/cmd2.css +0 -0
  117. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/stylesheets/readthedocs.css +0 -0
  118. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/testing.md +0 -0
  119. {cmd2-3.0.0rc1 → cmd2-3.1.0}/docs/upgrades.md +0 -0
  120. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.cmd2rc +0 -0
  121. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/@plugins_snapshot.json +0 -0
  122. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_ast.data.json +0 -0
  123. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_ast.meta.json +0 -0
  124. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_codecs.data.json +0 -0
  125. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_codecs.meta.json +0 -0
  126. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_collections_abc.data.json +0 -0
  127. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_collections_abc.meta.json +0 -0
  128. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_typeshed/__init__.data.json +0 -0
  129. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_typeshed/__init__.meta.json +0 -0
  130. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_typeshed/importlib.data.json +0 -0
  131. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/_typeshed/importlib.meta.json +0 -0
  132. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/abc.data.json +0 -0
  133. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/abc.meta.json +0 -0
  134. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/argparse.data.json +0 -0
  135. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/argparse.meta.json +0 -0
  136. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/builtins.data.json +0 -0
  137. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/builtins.meta.json +0 -0
  138. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/codecs.data.json +0 -0
  139. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/codecs.meta.json +0 -0
  140. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/collections/__init__.data.json +0 -0
  141. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/collections/__init__.meta.json +0 -0
  142. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/collections/abc.data.json +0 -0
  143. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/collections/abc.meta.json +0 -0
  144. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/contextlib.data.json +0 -0
  145. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/contextlib.meta.json +0 -0
  146. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/dataclasses.data.json +0 -0
  147. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/dataclasses.meta.json +0 -0
  148. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/__init__.data.json +0 -0
  149. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/__init__.meta.json +0 -0
  150. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/_policybase.data.json +0 -0
  151. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/_policybase.meta.json +0 -0
  152. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/charset.data.json +0 -0
  153. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/charset.meta.json +0 -0
  154. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/contentmanager.data.json +0 -0
  155. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/contentmanager.meta.json +0 -0
  156. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/errors.data.json +0 -0
  157. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/errors.meta.json +0 -0
  158. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/header.data.json +0 -0
  159. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/header.meta.json +0 -0
  160. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/message.data.json +0 -0
  161. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/message.meta.json +0 -0
  162. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/policy.data.json +0 -0
  163. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/email/policy.meta.json +0 -0
  164. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/enum.data.json +0 -0
  165. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/enum.meta.json +0 -0
  166. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/genericpath.data.json +0 -0
  167. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/genericpath.meta.json +0 -0
  168. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/__init__.data.json +0 -0
  169. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/__init__.meta.json +0 -0
  170. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/_abc.data.json +0 -0
  171. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/_abc.meta.json +0 -0
  172. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/abc.data.json +0 -0
  173. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/abc.meta.json +0 -0
  174. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/machinery.data.json +0 -0
  175. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/machinery.meta.json +0 -0
  176. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/metadata/__init__.data.json +0 -0
  177. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/metadata/__init__.meta.json +0 -0
  178. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/metadata/_meta.data.json +0 -0
  179. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/metadata/_meta.meta.json +0 -0
  180. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/readers.data.json +0 -0
  181. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/readers.meta.json +0 -0
  182. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/resources/__init__.data.json +0 -0
  183. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/resources/__init__.meta.json +0 -0
  184. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/resources/abc.data.json +0 -0
  185. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/importlib/resources/abc.meta.json +0 -0
  186. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/io.data.json +0 -0
  187. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/io.meta.json +0 -0
  188. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/os/__init__.data.json +0 -0
  189. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/os/__init__.meta.json +0 -0
  190. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/os/path.data.json +0 -0
  191. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/os/path.meta.json +0 -0
  192. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/pathlib.data.json +0 -0
  193. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/pathlib.meta.json +0 -0
  194. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/posixpath.data.json +0 -0
  195. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/posixpath.meta.json +0 -0
  196. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/re.data.json +0 -0
  197. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/re.meta.json +0 -0
  198. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/resource.data.json +0 -0
  199. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/resource.meta.json +0 -0
  200. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sre_compile.data.json +0 -0
  201. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sre_compile.meta.json +0 -0
  202. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sre_constants.data.json +0 -0
  203. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sre_constants.meta.json +0 -0
  204. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sre_parse.data.json +0 -0
  205. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sre_parse.meta.json +0 -0
  206. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/subprocess.data.json +0 -0
  207. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/subprocess.meta.json +0 -0
  208. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sys/__init__.data.json +0 -0
  209. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sys/__init__.meta.json +0 -0
  210. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sys/_monitoring.data.json +0 -0
  211. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/sys/_monitoring.meta.json +0 -0
  212. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/types.data.json +0 -0
  213. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/types.meta.json +0 -0
  214. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/typing.data.json +0 -0
  215. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/typing.meta.json +0 -0
  216. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/typing_extensions.data.json +0 -0
  217. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/typing_extensions.meta.json +0 -0
  218. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/zipfile/__init__.data.json +0 -0
  219. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/zipfile/__init__.meta.json +0 -0
  220. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/zipfile/_path.data.json +0 -0
  221. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/3.12/zipfile/_path.meta.json +0 -0
  222. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/.mypy_cache/CACHEDIR.TAG +0 -0
  223. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/README.md +0 -0
  224. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/argparse_completion.py +0 -0
  225. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/argparse_example.py +0 -0
  226. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/async_printing.py +0 -0
  227. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/basic_completion.py +0 -0
  228. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/cmd2_history.dat +0 -0
  229. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/cmd_as_argument.py +0 -0
  230. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/color.py +0 -0
  231. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/command_sets.py +0 -0
  232. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/custom_parser.py +0 -0
  233. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/custom_types.py +0 -0
  234. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/default_categories.py +0 -0
  235. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/dynamic_commands.py +0 -0
  236. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/environment.py +0 -0
  237. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/event_loops.py +0 -0
  238. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/exit_code.py +0 -0
  239. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/getting_started.py +0 -0
  240. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/hello_cmd2.py +0 -0
  241. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/help_categories.py +0 -0
  242. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/hooks.py +0 -0
  243. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/migrating.py +0 -0
  244. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/mixin.py +0 -0
  245. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/modular_commands/__init__.py +0 -0
  246. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/modular_commands/commandset_basic.py +0 -0
  247. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/modular_commands/commandset_complex.py +0 -0
  248. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/modular_commands/commandset_custominit.py +0 -0
  249. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/modular_commands.py +0 -0
  250. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/paged_output.py +0 -0
  251. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/persistent_history.py +0 -0
  252. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/pretty_print.py +0 -0
  253. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/python_scripting.py +0 -0
  254. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/read_input.py +0 -0
  255. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/remove_builtin_commands.py +0 -0
  256. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/remove_settable.py +0 -0
  257. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/rich_tables.py +0 -0
  258. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/rich_theme.py +0 -0
  259. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/arg_printer.py +0 -0
  260. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/conditional.py +0 -0
  261. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/nested.txt +0 -0
  262. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/quit.txt +0 -0
  263. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/save_help_text.py +0 -0
  264. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/script.py +0 -0
  265. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/scripts/script.txt +0 -0
  266. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/tmux_launch.sh +0 -0
  267. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/tmux_split.sh +0 -0
  268. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/transcript_example.py +0 -0
  269. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/transcripts/exampleSession.txt +0 -0
  270. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/transcripts/pirate.transcript +0 -0
  271. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/transcripts/quit.txt +0 -0
  272. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/transcripts/transcript_regex.txt +0 -0
  273. {cmd2-3.0.0rc1 → cmd2-3.1.0}/examples/unicode_commands.py +0 -0
  274. {cmd2-3.0.0rc1 → cmd2-3.1.0}/ruff.toml +0 -0
  275. {cmd2-3.0.0rc1 → cmd2-3.1.0}/setup.cfg +0 -0
  276. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/.cmd2rc +0 -0
  277. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/__init__.py +0 -0
  278. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/conftest.py +0 -0
  279. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/echo.py +0 -0
  280. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/environment.py +0 -0
  281. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/help.py +0 -0
  282. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/py_locals.py +0 -0
  283. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/pyscript_dir.py +0 -0
  284. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/raises_exception.py +0 -0
  285. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/recursive.py +0 -0
  286. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/self_in_py.py +0 -0
  287. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/stdout_capture.py +0 -0
  288. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/pyscript/stop.py +0 -0
  289. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/relative_multiple.txt +0 -0
  290. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/script.py +0 -0
  291. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/script.txt +0 -0
  292. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/binary.bin +0 -0
  293. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/empty.txt +0 -0
  294. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/help.txt +0 -0
  295. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/nested.txt +0 -0
  296. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/one_down.txt +0 -0
  297. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/postcmds.txt +0 -0
  298. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/precmds.txt +0 -0
  299. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/scripts/utf8.txt +0 -0
  300. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_argparse.py +0 -0
  301. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_argparse_completer.py +0 -0
  302. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_argparse_custom.py +0 -0
  303. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_argparse_subcommands.py +0 -0
  304. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_categories.py +0 -0
  305. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_commandset.py +0 -0
  306. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_future_annotations.py +0 -0
  307. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_history.py +0 -0
  308. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_parsing.py +0 -0
  309. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_plugin.py +0 -0
  310. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_rich_utils.py +0 -0
  311. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_run_pyscript.py +0 -0
  312. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_string_utils.py +0 -0
  313. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_terminal_utils.py +0 -0
  314. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_transcript.py +0 -0
  315. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_utils.py +0 -0
  316. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/test_utils_defining_class.py +0 -0
  317. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/bol_eol.txt +0 -0
  318. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/characterclass.txt +0 -0
  319. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/dotstar.txt +0 -0
  320. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/extension_notation.txt +0 -0
  321. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/failure.txt +0 -0
  322. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/from_cmdloop.txt +0 -0
  323. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/multiline_no_regex.txt +0 -0
  324. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/multiline_regex.txt +0 -0
  325. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/no_output.txt +0 -0
  326. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/no_output_last.txt +0 -0
  327. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/singleslash.txt +0 -0
  328. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/slashes_escaped.txt +0 -0
  329. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/slashslash.txt +0 -0
  330. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/spaces.txt +0 -0
  331. {cmd2-3.0.0rc1 → cmd2-3.1.0}/tests/transcripts/word_boundaries.txt +0 -0
@@ -9,7 +9,7 @@ repos:
9
9
  - id: trailing-whitespace
10
10
 
11
11
  - repo: https://github.com/astral-sh/ruff-pre-commit
12
- rev: "v0.13.2"
12
+ rev: "v0.14.10"
13
13
  hooks:
14
14
  - id: ruff-format
15
15
  args: [--config=ruff.toml]
@@ -21,5 +21,5 @@ repos:
21
21
  hooks:
22
22
  - id: prettier
23
23
  additional_dependencies:
24
- - prettier@3.6.2
24
+ - prettier@3.7.4
25
25
  - prettier-plugin-toml@2.0.6
@@ -1,4 +1,11 @@
1
- ## 3.0.0 (October TBD, 2025)
1
+ ## 3.1.0 (December 25, 2025)
2
+
3
+ - Potentially Breaking Changes
4
+ - `cmd2` no longer has a dependency on `cmd` and `cmd2.Cmd` no longer inherits from `cmd.Cmd`
5
+ - We don't _think_ this should impact users, but there is theoretically a possibility
6
+ - This opens the door for more impactful changes in the next major release
7
+
8
+ ## 3.0.0 (December 7, 2025)
2
9
 
3
10
  ### Summary
4
11
 
@@ -16,6 +23,8 @@ time reading the [rich documentation](https://rich.readthedocs.io/).
16
23
  [rich_tables.py](https://github.com/python-cmd2/cmd2/blob/main/examples/rich_tables.py)
17
24
  example for more info)
18
25
  - Moved all string-related functions from `utils.py` to a new `string_utils.py` module
26
+ - Removed redundant `string` from some of the names so `quote_string` is now just
27
+ `quote` and `quote_string_if_needed` is now `quote_if_needed`
19
28
  - Consolidated all string styling functions from `ansi.py` into `string_utils.py`
20
29
  - Replaced all text style enums from `ansi.py` with modern `rich` styles
21
30
  - Renamed `ansi.py` to `terminal_utils.py` to better reflect its purpose
@@ -25,6 +34,16 @@ time reading the [rich documentation](https://rich.readthedocs.io/).
25
34
  - Removed redundant setting of a parser's `prog` value in the `with_argparser()` decorator, as
26
35
  this is now handled centrally in `Cmd._build_parser()`
27
36
  - The `auto_load_commands` argument to `cmd2.Cmd.__init__` now defaults to `False`
37
+ - `argparse_custom` module breaking changes:
38
+ - `descriptive_header: str` replaced with `descriptive_headers: Sequence[str | rich.Column]`
39
+ - Applies to parameter name when adding an argument to a parser as well as
40
+ `set_descriptive_headers` and `get_descriptive_headers`
41
+ - `CompletionItem.description: str` changed to
42
+ `CompletionItem.descriptive_data: Sequence[str | rich.Column]`
43
+ - `decorators` module breaking changes:
44
+ - `_set_parser_prog` renamed to `set_parser_prog` (without the leading underscore) and moved
45
+ to `argparse_custom` module
46
+ - Renamed history `--output_file` to `--output-file` to follow common command-line practices
28
47
 
29
48
  - Enhancements
30
49
  - Enhanced all print methods (`poutput()`, `perror()`, `ppaged()`, etc.) to natively render
@@ -2,8 +2,8 @@
2
2
  .PHONY: install
3
3
  install: ## Install the virtual environment with dependencies
4
4
  @echo "🚀 Creating uv Python virtual environment"
5
- @uv python install 3.13
6
- @uv sync --python=3.13
5
+ @uv python install 3.14
6
+ @uv sync --python=3.14
7
7
  @echo "🚀 Installing Git pre-commit hooks locally"
8
8
  @uv run pre-commit install
9
9
  @echo "🚀 Installing Prettier using npm"
@@ -46,7 +46,7 @@ docs: ## Build and serve the documentation
46
46
  .PHONY: build
47
47
  build: clean-build ## Build wheel file
48
48
  @echo "🚀 Creating wheel file"
49
- @uvx --from build pyproject-build --installer uv
49
+ @uv build
50
50
 
51
51
  .PHONY: clean-build
52
52
  clean-build: ## Clean build artifacts
@@ -66,14 +66,14 @@ validate-tag: ## Check to make sure that a tag exists for the current HEAD and i
66
66
  @uv run inv validatetag
67
67
 
68
68
  .PHONY: publish-test
69
- publish-test: validate-tag build ## Test publishing a release to PyPI.
69
+ publish-test: validate-tag build ## Test publishing a release to PyPI, uses token from ~/.pypirc file.
70
70
  @echo "🚀 Publishing: Dry run."
71
- @uvx twine upload --repository testpypi dist/*
71
+ @uv run uv-publish --repository testpypi
72
72
 
73
73
  .PHONY: publish
74
- publish: validate-tag build ## Publish a release to PyPI.
74
+ publish: validate-tag build ## Publish a release to PyPI, uses token from ~/.pypirc file.
75
75
  @echo "🚀 Publishing."
76
- @uvx twine upload dist/*
76
+ @uv run uv-publish
77
77
 
78
78
  .PHONY: help
79
79
  help:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 3.0.0rc1
3
+ Version: 3.1.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
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
19
20
  Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
20
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
22
  Requires-Python: >=3.10
@@ -23,7 +24,7 @@ Description-Content-Type: text/markdown
23
24
  License-File: LICENSE
24
25
  Requires-Dist: backports.strenum; python_version == "3.10"
25
26
  Requires-Dist: gnureadline>=8; platform_system == "Darwin"
26
- Requires-Dist: pyperclip>=1.8
27
+ Requires-Dist: pyperclip>=1.8.2
27
28
  Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
28
29
  Requires-Dist: rich>=14.1.0
29
30
  Requires-Dist: rich-argparse>=1.7.1
@@ -56,10 +57,10 @@ applications. It provides a simple API which is an extension of Python's built-i
56
57
  of cmd to make your life easier and eliminates much of the boilerplate code which would be necessary
57
58
  when using cmd.
58
59
 
59
- > :warning: **cmd2 is now "feature complete" for the `2.x` branch and is actively working on the
60
- > 3.0.0 release on the `main` branch. New features will only be addressed in 3.x moving forwards. If
61
- > need be, we will still fix bugs in 2.x. A beta version, 3.0.0b2, is available for testing and we
62
- > would appreciate feedback.**
60
+ > :warning: **`cmd2` 3.0.0 has been released and there are some significant backwards
61
+ > incompatibilities from version `2.x`. Please see the
62
+ > [Migration Guide](https://cmd2.readthedocs.io/en/latest/upgrades/) for tips on upgrading from
63
+ > `cmd2` 2.x to 3.x.**
63
64
 
64
65
  ## The developers toolbox
65
66
 
@@ -25,10 +25,10 @@ applications. It provides a simple API which is an extension of Python's built-i
25
25
  of cmd to make your life easier and eliminates much of the boilerplate code which would be necessary
26
26
  when using cmd.
27
27
 
28
- > :warning: **cmd2 is now "feature complete" for the `2.x` branch and is actively working on the
29
- > 3.0.0 release on the `main` branch. New features will only be addressed in 3.x moving forwards. If
30
- > need be, we will still fix bugs in 2.x. A beta version, 3.0.0b2, is available for testing and we
31
- > would appreciate feedback.**
28
+ > :warning: **`cmd2` 3.0.0 has been released and there are some significant backwards
29
+ > incompatibilities from version `2.x`. Please see the
30
+ > [Migration Guide](https://cmd2.readthedocs.io/en/latest/upgrades/) for tips on upgrading from
31
+ > `cmd2` 2.x to 3.x.**
32
32
 
33
33
  ## The developers toolbox
34
34
 
@@ -39,7 +39,7 @@ from .exceptions import CompletionError
39
39
  from .styles import Cmd2Style
40
40
 
41
41
  # If no descriptive headers are supplied, then this will be used instead
42
- DEFAULT_DESCRIPTIVE_HEADERS: Sequence[str | Column] = ('Description',)
42
+ DEFAULT_DESCRIPTIVE_HEADERS: Sequence[str | Column] = ['Description']
43
43
 
44
44
  # Name of the choice/completer function argument that, if present, will be passed a dictionary of
45
45
  # command line tokens up through the token being completed mapped to their argparse destination name.
@@ -804,7 +804,7 @@ def _add_argument_wrapper(
804
804
  choices_provider: ChoicesProviderFunc | None = None,
805
805
  completer: CompleterFunc | None = None,
806
806
  suppress_tab_hint: bool = False,
807
- descriptive_headers: list[Column | str] | None = None,
807
+ descriptive_headers: Sequence[str | Column] | None = None,
808
808
  **kwargs: Any,
809
809
  ) -> argparse.Action:
810
810
  """Wrap ActionsContainer.add_argument() which supports more settings used by cmd2.
@@ -1,24 +1,26 @@
1
- """Variant on standard library's cmd with extra features.
2
-
3
- To use, simply import cmd2.Cmd instead of cmd.Cmd; use precisely as though you
4
- were using the standard library's cmd, while enjoying the extra features.
5
-
6
- Searchable command history (commands: "history")
7
- Run commands from file, save to file, edit commands in file
8
- Multi-line commands
9
- Special-character shortcut commands (beyond cmd's "?" and "!")
10
- Settable environment parameters
11
- Parsing commands with `argparse` argument parsers (flags)
12
- Redirection to file or paste buffer (clipboard) with > or >>
13
- Easy transcript-based testing of applications (see examples/transcript_example.py)
14
- Bash-style ``select`` available
1
+ """cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python.
2
+
3
+ cmd2 is a tool for building interactive command line applications in Python. Its goal is to make it quick and easy for
4
+ developers to build feature-rich and user-friendly interactive command line applications. It provides a simple API which
5
+ is an extension of Python's built-in cmd module. cmd2 provides a wealth of features on top of cmd to make your life easier
6
+ and eliminates much of the boilerplate code which would be necessary when using cmd.
7
+
8
+ Extra features include:
9
+ - Searchable command history (commands: "history")
10
+ - Run commands from file, save to file, edit commands in file
11
+ - Multi-line commands
12
+ - Special-character shortcut commands (beyond cmd's "?" and "!")
13
+ - Settable environment parameters
14
+ - Parsing commands with `argparse` argument parsers (flags)
15
+ - Redirection to file or paste buffer (clipboard) with > or >>
16
+ - Easy transcript-based testing of applications (see examples/transcript_example.py)
17
+ - Bash-style ``select`` available
15
18
 
16
19
  Note, if self.stdout is different than sys.stdout, then redirection with > and |
17
20
  will only work if `self.poutput()` is used in place of `print`.
18
21
 
19
- - Catherine Devlin, Jan 03 2008 - catherinedevlin.blogspot.com
20
-
21
- Git repository on GitHub at https://github.com/python-cmd2/cmd2
22
+ GitHub: https://github.com/python-cmd2/cmd2
23
+ Documentation: https://cmd2.readthedocs.io/
22
24
  """
23
25
 
24
26
  # This module has many imports, quite a few of which are only
@@ -26,7 +28,6 @@ Git repository on GitHub at https://github.com/python-cmd2/cmd2
26
28
  # import this module, many of these imports are lazy-loaded
27
29
  # i.e. we only import the module when we use it.
28
30
  import argparse
29
- import cmd
30
31
  import contextlib
31
32
  import copy
32
33
  import functools
@@ -64,7 +65,7 @@ from typing import (
64
65
  )
65
66
 
66
67
  import rich.box
67
- from rich.console import Group
68
+ from rich.console import Group, RenderableType
68
69
  from rich.highlighter import ReprHighlighter
69
70
  from rich.rule import Rule
70
71
  from rich.style import Style, StyleType
@@ -286,7 +287,7 @@ class _CommandParsers:
286
287
  del self._parsers[full_method_name]
287
288
 
288
289
 
289
- class Cmd(cmd.Cmd):
290
+ class Cmd:
290
291
  """An easy but powerful framework for writing line-oriented command interpreters.
291
292
 
292
293
  Extends the Python Standard Library's cmd package by adding a lot of useful features
@@ -304,6 +305,8 @@ class Cmd(cmd.Cmd):
304
305
  # List for storing transcript test file names
305
306
  testfiles: ClassVar[list[str]] = []
306
307
 
308
+ DEFAULT_PROMPT = '(Cmd) '
309
+
307
310
  def __init__(
308
311
  self,
309
312
  completekey: str = 'tab',
@@ -326,6 +329,7 @@ class Cmd(cmd.Cmd):
326
329
  auto_load_commands: bool = False,
327
330
  allow_clipboard: bool = True,
328
331
  suggest_similar_command: bool = False,
332
+ intro: RenderableType = '',
329
333
  ) -> None:
330
334
  """Easy but powerful framework for writing line-oriented command interpreters, extends Python's cmd package.
331
335
 
@@ -376,6 +380,7 @@ class Cmd(cmd.Cmd):
376
380
  :param suggest_similar_command: If ``True``, ``cmd2`` will attempt to suggest the most
377
381
  similar command when the user types a command that does
378
382
  not exist. Default: ``False``.
383
+ "param intro: Intro banner to print when starting the application.
379
384
  """
380
385
  # Check if py or ipy need to be disabled in this instance
381
386
  if not include_py:
@@ -384,11 +389,28 @@ class Cmd(cmd.Cmd):
384
389
  setattr(self, 'do_ipy', None) # noqa: B010
385
390
 
386
391
  # initialize plugin system
387
- # needs to be done before we call __init__(0)
392
+ # needs to be done before we most of the other stuff below
388
393
  self._initialize_plugin_system()
389
394
 
390
- # Call super class constructor
391
- super().__init__(completekey=completekey, stdin=stdin, stdout=stdout)
395
+ # Configure a few defaults
396
+ self.prompt = Cmd.DEFAULT_PROMPT
397
+ self.intro = intro
398
+ self.use_rawinput = True
399
+
400
+ # What to use for standard input
401
+ if stdin is not None:
402
+ self.stdin = stdin
403
+ else:
404
+ self.stdin = sys.stdin
405
+
406
+ # What to use for standard output
407
+ if stdout is not None:
408
+ self.stdout = stdout
409
+ else:
410
+ self.stdout = sys.stdout
411
+
412
+ # Key used for tab completion
413
+ self.completekey = completekey
392
414
 
393
415
  # Attributes which should NOT be dynamically settable via the set command at runtime
394
416
  self.default_to_shell = False # Attempt to run unrecognized commands as shell commands
@@ -2412,9 +2434,7 @@ class Cmd(cmd.Cmd):
2412
2434
  if len(self.completion_matches) == 1 and self.allow_closing_quote and completion_token_quote:
2413
2435
  self.completion_matches[0] += completion_token_quote
2414
2436
 
2415
- def complete( # type: ignore[override]
2416
- self, text: str, state: int, custom_settings: utils.CustomCompletionSettings | None = None
2417
- ) -> str | None:
2437
+ def complete(self, text: str, state: int, custom_settings: utils.CustomCompletionSettings | None = None) -> str | None:
2418
2438
  """Override of cmd's complete method which returns the next possible completion for 'text'.
2419
2439
 
2420
2440
  This completer function is called by readline as complete(text, state), for state in 0, 1, 2, …,
@@ -2693,10 +2713,6 @@ class Cmd(cmd.Cmd):
2693
2713
  def parseline(self, line: str) -> tuple[str, str, str]:
2694
2714
  """Parse the line into a command name and a string containing the arguments.
2695
2715
 
2696
- NOTE: This is an override of a parent class method. It is only used by other parent class methods.
2697
-
2698
- Different from the parent class method, this ignores self.identchars.
2699
-
2700
2716
  :param line: line read by readline
2701
2717
  :return: tuple containing (command, args, line)
2702
2718
  """
@@ -3086,7 +3102,7 @@ class Cmd(cmd.Cmd):
3086
3102
 
3087
3103
  # Initialize the redirection saved state
3088
3104
  redir_saved_state = utils.RedirectionSavedState(
3089
- cast(TextIO, self.stdout), stdouts_match, self._cur_pipe_proc_reader, self._redirecting
3105
+ self.stdout, stdouts_match, self._cur_pipe_proc_reader, self._redirecting
3090
3106
  )
3091
3107
 
3092
3108
  # The ProcReader for this command
@@ -3141,7 +3157,7 @@ class Cmd(cmd.Cmd):
3141
3157
  new_stdout.close()
3142
3158
  raise RedirectionError(f'Pipe process exited with code {proc.returncode} before command could run')
3143
3159
  redir_saved_state.redirecting = True
3144
- cmd_pipe_proc_reader = utils.ProcReader(proc, cast(TextIO, self.stdout), sys.stderr)
3160
+ cmd_pipe_proc_reader = utils.ProcReader(proc, self.stdout, sys.stderr)
3145
3161
 
3146
3162
  self.stdout = new_stdout
3147
3163
  if stdouts_match:
@@ -3276,7 +3292,7 @@ class Cmd(cmd.Cmd):
3276
3292
 
3277
3293
  return stop if stop is not None else False
3278
3294
 
3279
- def default(self, statement: Statement) -> bool | None: # type: ignore[override]
3295
+ def default(self, statement: Statement) -> bool | None:
3280
3296
  """Execute when the command given isn't a recognized command implemented by a do_* method.
3281
3297
 
3282
3298
  :param statement: Statement object with parsed input
@@ -3293,6 +3309,15 @@ class Cmd(cmd.Cmd):
3293
3309
  self.perror(err_msg, style=None)
3294
3310
  return None
3295
3311
 
3312
+ def completedefault(self, *_ignored: list[str]) -> list[str]:
3313
+ """Call to complete an input line when no command-specific complete_*() method is available.
3314
+
3315
+ This method is only called for non-argparse-based commands.
3316
+
3317
+ By default, it returns an empty list.
3318
+ """
3319
+ return []
3320
+
3296
3321
  def _suggest_similar_command(self, command: str) -> str | None:
3297
3322
  return suggest_similar(command, self.get_visible_commands())
3298
3323
 
@@ -4131,10 +4156,6 @@ class Cmd(cmd.Cmd):
4131
4156
  )
4132
4157
  return help_parser
4133
4158
 
4134
- # Get rid of cmd's complete_help() functions so ArgparseCompleter will complete the help command
4135
- if getattr(cmd.Cmd, 'complete_help', None) is not None:
4136
- delattr(cmd.Cmd, 'complete_help')
4137
-
4138
4159
  @with_argparser(_build_help_parser)
4139
4160
  def do_help(self, args: argparse.Namespace) -> None:
4140
4161
  """List available commands or provide detailed help for a specific command."""
@@ -4640,7 +4661,7 @@ class Cmd(cmd.Cmd):
4640
4661
  **kwargs,
4641
4662
  )
4642
4663
 
4643
- proc_reader = utils.ProcReader(proc, cast(TextIO, self.stdout), sys.stderr)
4664
+ proc_reader = utils.ProcReader(proc, self.stdout, sys.stderr)
4644
4665
  proc_reader.wait()
4645
4666
 
4646
4667
  # Save the return code of the application for use in a pyscript
@@ -5029,7 +5050,7 @@ class Cmd(cmd.Cmd):
5029
5050
  history_action_group.add_argument('-e', '--edit', action='store_true', help='edit and then run selected history items')
5030
5051
  history_action_group.add_argument(
5031
5052
  '-o',
5032
- '--output_file',
5053
+ '--output-file',
5033
5054
  metavar='FILE',
5034
5055
  help='output commands to a script file, implies -s',
5035
5056
  completer=cls.path_complete,
@@ -5359,7 +5380,7 @@ class Cmd(cmd.Cmd):
5359
5380
  transcript += command
5360
5381
 
5361
5382
  # Use a StdSim object to capture output
5362
- stdsim = utils.StdSim(cast(TextIO, self.stdout))
5383
+ stdsim = utils.StdSim(self.stdout)
5363
5384
  self.stdout = cast(TextIO, stdsim)
5364
5385
 
5365
5386
  # then run the command and let the output go into our buffer
@@ -5385,7 +5406,7 @@ class Cmd(cmd.Cmd):
5385
5406
  with self.sigint_protection:
5386
5407
  # Restore altered attributes to their original state
5387
5408
  self.echo = saved_echo
5388
- self.stdout = cast(TextIO, saved_stdout)
5409
+ self.stdout = saved_stdout
5389
5410
 
5390
5411
  # Check if all commands ran
5391
5412
  if commands_run < len(history):
@@ -5880,11 +5901,10 @@ class Cmd(cmd.Cmd):
5880
5901
  """
5881
5902
  self.perror(message_to_print, style=None)
5882
5903
 
5883
- def cmdloop(self, intro: str | None = None) -> int: # type: ignore[override]
5904
+ def cmdloop(self, intro: RenderableType = '') -> int:
5884
5905
  """Deal with extra features provided by cmd2, this is an outer wrapper around _cmdloop().
5885
5906
 
5886
- _cmdloop() provides the main loop equivalent to cmd.cmdloop(). This is a wrapper around that which deals with
5887
- the following extra features provided by cmd2:
5907
+ _cmdloop() provides the main loop. This provides the following extra features provided by cmd2:
5888
5908
  - transcript testing
5889
5909
  - intro banner
5890
5910
  - exit code
@@ -5922,11 +5942,11 @@ class Cmd(cmd.Cmd):
5922
5942
  self._run_transcript_tests([os.path.expanduser(tf) for tf in self._transcript_files])
5923
5943
  else:
5924
5944
  # If an intro was supplied in the method call, allow it to override the default
5925
- if intro is not None:
5945
+ if intro:
5926
5946
  self.intro = intro
5927
5947
 
5928
5948
  # Print the intro, if there is one, right after the preloop
5929
- if self.intro is not None:
5949
+ if self.intro:
5930
5950
  self.poutput(self.intro)
5931
5951
 
5932
5952
  # And then call _cmdloop() to enter the main loop
@@ -105,10 +105,10 @@ class Statement(str): # noqa: SLOT000
105
105
  whether positional or denoted with switches.
106
106
 
107
107
  2. For commands with simple positional arguments, use
108
- [args][cmd2.Statement.args] or [arg_list][cmd2.Statement.arg_list]
108
+ [args][cmd2.parsing.Statement.args] or [arg_list][cmd2.parsing.Statement.arg_list]
109
109
 
110
110
  3. If you don't want to have to worry about quoted arguments, see
111
- [argv][cmd2.Statement.argv] for a trick which strips quotes off for you.
111
+ [argv][cmd2.parsing.Statement.argv] for a trick which strips quotes off for you.
112
112
  """
113
113
 
114
114
  # the arguments, but not the command, nor the output redirection clauses.
@@ -193,7 +193,7 @@ class Statement(str): # noqa: SLOT000
193
193
 
194
194
  @property
195
195
  def expanded_command_line(self) -> str:
196
- """Concatenate [command_and_args][cmd2.Statement.command_and_args] and [post_command][cmd2.Statement.post_command]."""
196
+ """Concatenate [cmd2.parsing.Statement.command_and_args]() and [cmd2.parsing.Statement.post_command]()."""
197
197
  return self.command_and_args + self.post_command
198
198
 
199
199
  @property
@@ -137,7 +137,7 @@ class PyBridge:
137
137
  )
138
138
  finally:
139
139
  with self._cmd2_app.sigint_protection:
140
- self._cmd2_app.stdout = cast(IO[str], copy_cmd_stdout.inner_stream)
140
+ self._cmd2_app.stdout = cast(TextIO, copy_cmd_stdout.inner_stream)
141
141
  if stdouts_match:
142
142
  sys.stdout = self._cmd2_app.stdout
143
143
 
@@ -46,7 +46,7 @@ class Cmd2TestCase(unittest.TestCase):
46
46
 
47
47
  # Trap stdout
48
48
  self._orig_stdout = self.cmdapp.stdout
49
- self.cmdapp.stdout = cast(TextIO, utils.StdSim(cast(TextIO, self.cmdapp.stdout)))
49
+ self.cmdapp.stdout = cast(TextIO, utils.StdSim(self.cmdapp.stdout))
50
50
 
51
51
  def tearDown(self) -> None:
52
52
  """Instructions that will be executed after each test method."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 3.0.0rc1
3
+ Version: 3.1.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
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
19
20
  Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
20
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
22
  Requires-Python: >=3.10
@@ -23,7 +24,7 @@ Description-Content-Type: text/markdown
23
24
  License-File: LICENSE
24
25
  Requires-Dist: backports.strenum; python_version == "3.10"
25
26
  Requires-Dist: gnureadline>=8; platform_system == "Darwin"
26
- Requires-Dist: pyperclip>=1.8
27
+ Requires-Dist: pyperclip>=1.8.2
27
28
  Requires-Dist: pyreadline3>=3.4; platform_system == "Windows"
28
29
  Requires-Dist: rich>=14.1.0
29
30
  Requires-Dist: rich-argparse>=1.7.1
@@ -56,10 +57,10 @@ applications. It provides a simple API which is an extension of Python's built-i
56
57
  of cmd to make your life easier and eliminates much of the boilerplate code which would be necessary
57
58
  when using cmd.
58
59
 
59
- > :warning: **cmd2 is now "feature complete" for the `2.x` branch and is actively working on the
60
- > 3.0.0 release on the `main` branch. New features will only be addressed in 3.x moving forwards. If
61
- > need be, we will still fix bugs in 2.x. A beta version, 3.0.0b2, is available for testing and we
62
- > would appreciate feedback.**
60
+ > :warning: **`cmd2` 3.0.0 has been released and there are some significant backwards
61
+ > incompatibilities from version `2.x`. Please see the
62
+ > [Migration Guide](https://cmd2.readthedocs.io/en/latest/upgrades/) for tips on upgrading from
63
+ > `cmd2` 2.x to 3.x.**
63
64
 
64
65
  ## The developers toolbox
65
66
 
@@ -1,4 +1,4 @@
1
- pyperclip>=1.8
1
+ pyperclip>=1.8.2
2
2
  rich>=14.1.0
3
3
  rich-argparse>=1.7.1
4
4
 
@@ -0,0 +1,3 @@
1
+ # List of cmd2 examples
2
+
3
+ --8<-- "docs/../examples/README.md"
@@ -19,9 +19,7 @@ click the **Copy** button in the top-right):
19
19
  !!! example "getting_started.py"
20
20
 
21
21
  ```py
22
- {%
23
- include "../../examples/getting_started.py"
24
- %}
22
+ --8<-- "examples/getting_started.py"
25
23
  ```
26
24
 
27
25
  ## Basic Application
@@ -71,7 +71,7 @@ def do_echo(self, args):
71
71
 
72
72
  When an error occurs in your program, you can display it on `sys.stderr` by calling the
73
73
  [perror][cmd2.Cmd.perror] method. By default this method applies
74
- [Cmd2Style.ERROR][cmd2.Cmd2Style.ERROR] to the output.
74
+ [Cmd2Style.ERROR][cmd2.styles.Cmd2Style.ERROR] to the output.
75
75
 
76
76
  ## Warning Messages
77
77
 
@@ -189,7 +189,7 @@ each command. This is great when displaying history to the screen because it giv
189
189
  reference to identify previously entered commands. However, when creating a script or a transcript,
190
190
  the command numbers would prevent the script from loading properly. The `-s` or `--script` option
191
191
  instructs the `history` command to suppress the line numbers. This option is automatically set by
192
- the `--output_file`, `--transcript`, and `--edit` options. If you want to output the history
192
+ the `--output-file`, `--transcript`, and `--edit` options. If you want to output the history
193
193
  commands with line numbers to a file, you can do it with output redirection:
194
194
 
195
195
  (Cmd) history 1:4 > history.txt
@@ -5,9 +5,7 @@ Here is a basic example `cmd2` application which demonstrates many capabilities
5
5
  !!! example "examples/getting_started.py"
6
6
 
7
7
  ```py
8
- {%
9
- include "../../examples/getting_started.py"
10
- %}
8
+ --8<-- "examples/getting_started.py"
11
9
  ```
12
10
 
13
11
  ## Cmd class initializer
@@ -211,22 +211,23 @@ if __name__ == '__main__':
211
211
  The following functions are called at different points in the [CommandSet][cmd2.CommandSet] life
212
212
  cycle.
213
213
 
214
- [on_register][cmd2.CommandSet.on_register] - Called by `cmd2.Cmd` as the first step to registering a
215
- `CommandSet`. The commands defined in this class have not be added to the CLI object at this point.
216
- Subclasses can override this to perform any initialization requiring access to the Cmd object (e.g.
217
- configure commands and their parsers based on CLI state data).
218
-
219
- [on_registered][cmd2.CommandSet.on_registered] - Called by `cmd2.Cmd` after a `CommandSet` is
220
- registered and all its commands have been added to the CLI. Subclasses can override this to perform
221
- custom steps related to the newly added commands (e.g. setting them to a disabled state).
222
-
223
- [on_unregister][cmd2.CommandSet.on_unregister] - Called by `cmd2.Cmd` as the first step to
224
- unregistering a `CommandSet`. Subclasses can override this to perform any cleanup steps which
225
- require their commands being registered in the CLI.
226
-
227
- [on_unregistered][cmd2.CommandSet.on_unregistered] - Called by `cmd2.Cmd` after a `CommandSet` has
228
- been unregistered and all its commands removed from the CLI. Subclasses can override this to perform
229
- remaining cleanup steps.
214
+ [on_register][cmd2.command_definition.CommandSet.on_register] - Called by `cmd2.Cmd` as the first
215
+ step to registering a `CommandSet`. The commands defined in this class have not be added to the CLI
216
+ object at this point. Subclasses can override this to perform any initialization requiring access to
217
+ the Cmd object (e.g. configure commands and their parsers based on CLI state data).
218
+
219
+ [on_registered][cmd2.command_definition.CommandSet.on_registered] - Called by `cmd2.Cmd` after a
220
+ `CommandSet` is registered and all its commands have been added to the CLI. Subclasses can override
221
+ this to perform custom steps related to the newly added commands (e.g. setting them to a disabled
222
+ state).
223
+
224
+ [on_unregister][cmd2.command_definition.CommandSet.on_unregister] - Called by `cmd2.Cmd` as the
225
+ first step to unregistering a `CommandSet`. Subclasses can override this to perform any cleanup
226
+ steps which require their commands being registered in the CLI.
227
+
228
+ [on_unregistered][cmd2.command_definition.CommandSet.on_unregistered] - Called by `cmd2.Cmd` after a
229
+ `CommandSet` has been unregistered and all its commands removed from the CLI. Subclasses can
230
+ override this to perform remaining cleanup steps.
230
231
 
231
232
  ## Injecting Subcommands
232
233
 
@@ -105,9 +105,7 @@ Here's an example, from
105
105
  !!! example "examples/environment.py"
106
106
 
107
107
  ```py
108
- {%
109
- include "../../examples/environment.py"
110
- %}
108
+ --8<-- "examples/environment.py"
111
109
  ```
112
110
 
113
111
  If you want to be notified when a setting changes (as we do above), then be sure to supply a method