cmd2 3.0.0b2__tar.gz → 3.0.0rc1__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 (347) hide show
  1. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/.pre-commit-config.yaml +3 -3
  2. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/CHANGELOG.md +7 -1
  3. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/MANIFEST.in +1 -1
  4. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/PKG-INFO +3 -2
  5. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/README.md +2 -1
  6. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/plugin.py +1 -1
  7. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2.egg-info/PKG-INFO +3 -2
  8. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2.egg-info/SOURCES.txt +5 -18
  9. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/codecov.yml +0 -4
  10. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/index.md +2 -2
  11. cmd2-3.0.0rc1/docs/mixins/index.md +7 -0
  12. cmd2-3.0.0rc1/docs/mixins/mixin_template.md +170 -0
  13. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/upgrades.md +25 -0
  14. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/README.md +2 -0
  15. cmd2-3.0.0rc1/examples/custom_types.py +165 -0
  16. cmd2-3.0.0b2/plugins/template/cmd2_myplugin/myplugin.py → cmd2-3.0.0rc1/examples/mixin.py +29 -11
  17. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/mkdocs.yml +3 -3
  18. cmd2-3.0.0rc1/pyproject.toml +121 -0
  19. cmd2-3.0.0b2/pyproject.toml → cmd2-3.0.0rc1/ruff.toml +6 -131
  20. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tasks.py +6 -11
  21. cmd2-3.0.0b2/docs/plugins/index.md +0 -7
  22. cmd2-3.0.0b2/docs/plugins/plugin_template.md +0 -7
  23. cmd2-3.0.0b2/plugins/README.txt +0 -1
  24. cmd2-3.0.0b2/plugins/tasks.py +0 -139
  25. cmd2-3.0.0b2/plugins/template/CHANGELOG.md +0 -12
  26. cmd2-3.0.0b2/plugins/template/LICENSE +0 -21
  27. cmd2-3.0.0b2/plugins/template/README.md +0 -290
  28. cmd2-3.0.0b2/plugins/template/build-pyenvs.sh +0 -53
  29. cmd2-3.0.0b2/plugins/template/cmd2_myplugin/__init__.py +0 -17
  30. cmd2-3.0.0b2/plugins/template/cmd2_myplugin/pylintrc +0 -10
  31. cmd2-3.0.0b2/plugins/template/examples/example.py +0 -20
  32. cmd2-3.0.0b2/plugins/template/noxfile.py +0 -7
  33. cmd2-3.0.0b2/plugins/template/setup.py +0 -50
  34. cmd2-3.0.0b2/plugins/template/tasks.py +0 -198
  35. cmd2-3.0.0b2/plugins/template/tests/__init__.py +0 -2
  36. cmd2-3.0.0b2/plugins/template/tests/pylintrc +0 -19
  37. cmd2-3.0.0b2/plugins/template/tests/test_myplugin.py +0 -69
  38. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/.prettierignore +0 -0
  39. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/.prettierrc +0 -0
  40. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/GEMINI.md +0 -0
  41. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/LICENSE +0 -0
  42. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/Makefile +0 -0
  43. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/__init__.py +0 -0
  44. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/argparse_completer.py +0 -0
  45. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/argparse_custom.py +0 -0
  46. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/clipboard.py +0 -0
  47. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/cmd2.py +0 -0
  48. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/colors.py +0 -0
  49. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/command_definition.py +0 -0
  50. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/constants.py +0 -0
  51. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/decorators.py +0 -0
  52. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/exceptions.py +0 -0
  53. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/history.py +0 -0
  54. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/parsing.py +0 -0
  55. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/py.typed +0 -0
  56. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/py_bridge.py +0 -0
  57. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/rich_utils.py +0 -0
  58. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/rl_utils.py +0 -0
  59. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/string_utils.py +0 -0
  60. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/styles.py +0 -0
  61. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/terminal_utils.py +0 -0
  62. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/transcript.py +0 -0
  63. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2/utils.py +0 -0
  64. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2.egg-info/dependency_links.txt +0 -0
  65. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2.egg-info/requires.txt +0 -0
  66. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2.egg-info/top_level.txt +0 -0
  67. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/cmd2.png +0 -0
  68. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/argparse_completer.md +0 -0
  69. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/argparse_custom.md +0 -0
  70. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/clipboard.md +0 -0
  71. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/cmd.md +0 -0
  72. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/colors.md +0 -0
  73. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/command_definition.md +0 -0
  74. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/constants.md +0 -0
  75. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/decorators.md +0 -0
  76. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/exceptions.md +0 -0
  77. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/history.md +0 -0
  78. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/index.md +0 -0
  79. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/parsing.md +0 -0
  80. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/plugin.md +0 -0
  81. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/py_bridge.md +0 -0
  82. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/rich_utils.md +0 -0
  83. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/rl_utils.md +0 -0
  84. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/string_utils.md +0 -0
  85. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/styles.md +0 -0
  86. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/terminal_utils.md +0 -0
  87. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/transcript.md +0 -0
  88. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/api/utils.md +0 -0
  89. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/doc_conventions.md +0 -0
  90. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/examples/alternate_event_loops.md +0 -0
  91. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/examples/examples.md +0 -0
  92. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/examples/getting_started.md +0 -0
  93. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/examples/index.md +0 -0
  94. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/argument_processing.md +0 -0
  95. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/builtin_commands.md +0 -0
  96. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/clipboard.md +0 -0
  97. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/commands.md +0 -0
  98. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/completion.md +0 -0
  99. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/disable_commands.md +0 -0
  100. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/embedded_python_shells.md +0 -0
  101. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/generating_output.md +0 -0
  102. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/help.md +0 -0
  103. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/history.md +0 -0
  104. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/hooks.md +0 -0
  105. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/index.md +0 -0
  106. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/initialization.md +0 -0
  107. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/misc.md +0 -0
  108. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/modular_commands.md +0 -0
  109. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/multiline_commands.md +0 -0
  110. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/os.md +0 -0
  111. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/packaging.md +0 -0
  112. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/plugins.md +0 -0
  113. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/prompt.md +0 -0
  114. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/redirection.md +0 -0
  115. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/scripting.md +0 -0
  116. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/settings.md +0 -0
  117. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/shortcuts_aliases_macros.md +0 -0
  118. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/startup_commands.md +0 -0
  119. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/table_creation.md +0 -0
  120. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/theme.md +0 -0
  121. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/features/transcripts.md +0 -0
  122. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/javascripts/readthedocs.js +0 -0
  123. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/migrating/incompatibilities.md +0 -0
  124. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/migrating/index.md +0 -0
  125. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/migrating/minimum.md +0 -0
  126. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/migrating/next_steps.md +0 -0
  127. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/migrating/why.md +0 -0
  128. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/overrides/main.html +0 -0
  129. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/overview/alternatives.md +0 -0
  130. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/overview/index.md +0 -0
  131. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/overview/installation.md +0 -0
  132. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/overview/integrating.md +0 -0
  133. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/overview/resources.md +0 -0
  134. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/stylesheets/cmd2.css +0 -0
  135. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/stylesheets/readthedocs.css +0 -0
  136. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/docs/testing.md +0 -0
  137. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.cmd2rc +0 -0
  138. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/@plugins_snapshot.json +0 -0
  139. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_ast.data.json +0 -0
  140. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_ast.meta.json +0 -0
  141. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_codecs.data.json +0 -0
  142. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_codecs.meta.json +0 -0
  143. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_collections_abc.data.json +0 -0
  144. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_collections_abc.meta.json +0 -0
  145. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_typeshed/__init__.data.json +0 -0
  146. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_typeshed/__init__.meta.json +0 -0
  147. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_typeshed/importlib.data.json +0 -0
  148. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/_typeshed/importlib.meta.json +0 -0
  149. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/abc.data.json +0 -0
  150. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/abc.meta.json +0 -0
  151. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/argparse.data.json +0 -0
  152. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/argparse.meta.json +0 -0
  153. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/builtins.data.json +0 -0
  154. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/builtins.meta.json +0 -0
  155. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/codecs.data.json +0 -0
  156. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/codecs.meta.json +0 -0
  157. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/collections/__init__.data.json +0 -0
  158. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/collections/__init__.meta.json +0 -0
  159. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/collections/abc.data.json +0 -0
  160. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/collections/abc.meta.json +0 -0
  161. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/contextlib.data.json +0 -0
  162. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/contextlib.meta.json +0 -0
  163. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/dataclasses.data.json +0 -0
  164. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/dataclasses.meta.json +0 -0
  165. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/__init__.data.json +0 -0
  166. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/__init__.meta.json +0 -0
  167. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/_policybase.data.json +0 -0
  168. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/_policybase.meta.json +0 -0
  169. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/charset.data.json +0 -0
  170. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/charset.meta.json +0 -0
  171. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/contentmanager.data.json +0 -0
  172. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/contentmanager.meta.json +0 -0
  173. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/errors.data.json +0 -0
  174. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/errors.meta.json +0 -0
  175. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/header.data.json +0 -0
  176. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/header.meta.json +0 -0
  177. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/message.data.json +0 -0
  178. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/message.meta.json +0 -0
  179. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/policy.data.json +0 -0
  180. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/email/policy.meta.json +0 -0
  181. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/enum.data.json +0 -0
  182. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/enum.meta.json +0 -0
  183. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/genericpath.data.json +0 -0
  184. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/genericpath.meta.json +0 -0
  185. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/__init__.data.json +0 -0
  186. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/__init__.meta.json +0 -0
  187. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/_abc.data.json +0 -0
  188. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/_abc.meta.json +0 -0
  189. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/abc.data.json +0 -0
  190. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/abc.meta.json +0 -0
  191. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/machinery.data.json +0 -0
  192. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/machinery.meta.json +0 -0
  193. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/metadata/__init__.data.json +0 -0
  194. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/metadata/__init__.meta.json +0 -0
  195. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/metadata/_meta.data.json +0 -0
  196. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/metadata/_meta.meta.json +0 -0
  197. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/readers.data.json +0 -0
  198. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/readers.meta.json +0 -0
  199. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/resources/__init__.data.json +0 -0
  200. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/resources/__init__.meta.json +0 -0
  201. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/resources/abc.data.json +0 -0
  202. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/importlib/resources/abc.meta.json +0 -0
  203. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/io.data.json +0 -0
  204. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/io.meta.json +0 -0
  205. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/os/__init__.data.json +0 -0
  206. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/os/__init__.meta.json +0 -0
  207. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/os/path.data.json +0 -0
  208. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/os/path.meta.json +0 -0
  209. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/pathlib.data.json +0 -0
  210. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/pathlib.meta.json +0 -0
  211. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/posixpath.data.json +0 -0
  212. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/posixpath.meta.json +0 -0
  213. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/re.data.json +0 -0
  214. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/re.meta.json +0 -0
  215. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/resource.data.json +0 -0
  216. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/resource.meta.json +0 -0
  217. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sre_compile.data.json +0 -0
  218. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sre_compile.meta.json +0 -0
  219. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sre_constants.data.json +0 -0
  220. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sre_constants.meta.json +0 -0
  221. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sre_parse.data.json +0 -0
  222. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sre_parse.meta.json +0 -0
  223. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/subprocess.data.json +0 -0
  224. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/subprocess.meta.json +0 -0
  225. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sys/__init__.data.json +0 -0
  226. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sys/__init__.meta.json +0 -0
  227. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sys/_monitoring.data.json +0 -0
  228. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/sys/_monitoring.meta.json +0 -0
  229. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/types.data.json +0 -0
  230. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/types.meta.json +0 -0
  231. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/typing.data.json +0 -0
  232. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/typing.meta.json +0 -0
  233. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/typing_extensions.data.json +0 -0
  234. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/typing_extensions.meta.json +0 -0
  235. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/zipfile/__init__.data.json +0 -0
  236. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/zipfile/__init__.meta.json +0 -0
  237. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/zipfile/_path.data.json +0 -0
  238. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/3.12/zipfile/_path.meta.json +0 -0
  239. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/.mypy_cache/CACHEDIR.TAG +0 -0
  240. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/argparse_completion.py +0 -0
  241. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/argparse_example.py +0 -0
  242. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/async_printing.py +0 -0
  243. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/basic_completion.py +0 -0
  244. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/cmd2_history.dat +0 -0
  245. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/cmd_as_argument.py +0 -0
  246. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/color.py +0 -0
  247. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/command_sets.py +0 -0
  248. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/custom_parser.py +0 -0
  249. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/default_categories.py +0 -0
  250. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/dynamic_commands.py +0 -0
  251. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/environment.py +0 -0
  252. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/event_loops.py +0 -0
  253. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/exit_code.py +0 -0
  254. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/getting_started.py +0 -0
  255. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/hello_cmd2.py +0 -0
  256. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/help_categories.py +0 -0
  257. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/hooks.py +0 -0
  258. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/migrating.py +0 -0
  259. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/modular_commands/__init__.py +0 -0
  260. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/modular_commands/commandset_basic.py +0 -0
  261. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/modular_commands/commandset_complex.py +0 -0
  262. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/modular_commands/commandset_custominit.py +0 -0
  263. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/modular_commands.py +0 -0
  264. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/paged_output.py +0 -0
  265. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/persistent_history.py +0 -0
  266. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/pretty_print.py +0 -0
  267. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/python_scripting.py +0 -0
  268. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/read_input.py +0 -0
  269. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/remove_builtin_commands.py +0 -0
  270. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/remove_settable.py +0 -0
  271. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/rich_tables.py +0 -0
  272. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/rich_theme.py +0 -0
  273. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/arg_printer.py +0 -0
  274. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/conditional.py +0 -0
  275. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/nested.txt +0 -0
  276. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/quit.txt +0 -0
  277. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/save_help_text.py +0 -0
  278. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/script.py +0 -0
  279. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/scripts/script.txt +0 -0
  280. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/tmux_launch.sh +0 -0
  281. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/tmux_split.sh +0 -0
  282. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/transcript_example.py +0 -0
  283. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/transcripts/exampleSession.txt +0 -0
  284. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/transcripts/pirate.transcript +0 -0
  285. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/transcripts/quit.txt +0 -0
  286. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/transcripts/transcript_regex.txt +0 -0
  287. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/examples/unicode_commands.py +0 -0
  288. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/package.json +0 -0
  289. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/setup.cfg +0 -0
  290. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/.cmd2rc +0 -0
  291. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/__init__.py +0 -0
  292. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/conftest.py +0 -0
  293. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/echo.py +0 -0
  294. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/environment.py +0 -0
  295. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/help.py +0 -0
  296. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/py_locals.py +0 -0
  297. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/pyscript_dir.py +0 -0
  298. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/raises_exception.py +0 -0
  299. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/recursive.py +0 -0
  300. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/self_in_py.py +0 -0
  301. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/stdout_capture.py +0 -0
  302. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/pyscript/stop.py +0 -0
  303. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/relative_multiple.txt +0 -0
  304. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/script.py +0 -0
  305. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/script.txt +0 -0
  306. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/binary.bin +0 -0
  307. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/empty.txt +0 -0
  308. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/help.txt +0 -0
  309. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/nested.txt +0 -0
  310. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/one_down.txt +0 -0
  311. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/postcmds.txt +0 -0
  312. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/precmds.txt +0 -0
  313. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/scripts/utf8.txt +0 -0
  314. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_argparse.py +0 -0
  315. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_argparse_completer.py +0 -0
  316. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_argparse_custom.py +0 -0
  317. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_argparse_subcommands.py +0 -0
  318. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_categories.py +0 -0
  319. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_cmd2.py +0 -0
  320. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_commandset.py +0 -0
  321. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_completion.py +0 -0
  322. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_future_annotations.py +0 -0
  323. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_history.py +0 -0
  324. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_parsing.py +0 -0
  325. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_plugin.py +0 -0
  326. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_rich_utils.py +0 -0
  327. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_run_pyscript.py +0 -0
  328. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_string_utils.py +0 -0
  329. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_terminal_utils.py +0 -0
  330. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_transcript.py +0 -0
  331. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_utils.py +0 -0
  332. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/test_utils_defining_class.py +0 -0
  333. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/bol_eol.txt +0 -0
  334. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/characterclass.txt +0 -0
  335. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/dotstar.txt +0 -0
  336. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/extension_notation.txt +0 -0
  337. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/failure.txt +0 -0
  338. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/from_cmdloop.txt +0 -0
  339. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/multiline_no_regex.txt +0 -0
  340. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/multiline_regex.txt +0 -0
  341. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/no_output.txt +0 -0
  342. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/no_output_last.txt +0 -0
  343. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/singleslash.txt +0 -0
  344. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/slashes_escaped.txt +0 -0
  345. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/slashslash.txt +0 -0
  346. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/spaces.txt +0 -0
  347. {cmd2-3.0.0b2 → cmd2-3.0.0rc1}/tests/transcripts/word_boundaries.txt +0 -0
@@ -9,12 +9,12 @@ repos:
9
9
  - id: trailing-whitespace
10
10
 
11
11
  - repo: https://github.com/astral-sh/ruff-pre-commit
12
- rev: "v0.13.0"
12
+ rev: "v0.13.2"
13
13
  hooks:
14
14
  - id: ruff-format
15
- args: [--config=pyproject.toml]
15
+ args: [--config=ruff.toml]
16
16
  - id: ruff-check
17
- args: [--config=pyproject.toml, --fix, --exit-non-zero-on-fix]
17
+ args: [--config=ruff.toml, --fix, --exit-non-zero-on-fix]
18
18
 
19
19
  - repo: https://github.com/pre-commit/mirrors-prettier
20
20
  rev: "v3.1.0"
@@ -1,4 +1,4 @@
1
- ## 3.0.0 (TBD, 2025)
1
+ ## 3.0.0 (October TBD, 2025)
2
2
 
3
3
  ### Summary
4
4
 
@@ -52,6 +52,12 @@ time reading the [rich documentation](https://rich.readthedocs.io/).
52
52
  - Fixed a redirection bug where `cmd2` could unintentionally overwrite an application's
53
53
  `sys.stdout`
54
54
 
55
+ - Migration Aids - these will help you iteratively migrate to `cmd2` 3.x in stages
56
+ - Published new [cmd2-ansi](https://pypi.org/project/cmd2-ansi/) module which is a backport of
57
+ the `cmd2.ansi` module present in `cmd2` 2.7.0
58
+ - Published new [cmd2-table](https://pypi.org/project/cmd2-table/) module which is a backport of
59
+ the `cmd2.table_creator` module present in `cmd2` 2.7.0
60
+
55
61
  ## 2.7.0 (June 30, 2025)
56
62
 
57
63
  - Enhancements
@@ -1,4 +1,4 @@
1
- include LICENSE README.md CHANGELOG.md mkdocs.yml pyproject.toml tasks.py
1
+ include LICENSE README.md CHANGELOG.md mkdocs.yml pyproject.toml ruff.toml tasks.py
2
2
  recursive-include examples *
3
3
  recursive-include tests *
4
4
  recursive-include docs *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 3.0.0b2
3
+ Version: 3.0.0rc1
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
@@ -58,7 +58,8 @@ when using cmd.
58
58
 
59
59
  > :warning: **cmd2 is now "feature complete" for the `2.x` branch and is actively working on the
60
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.**
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.**
62
63
 
63
64
  ## The developers toolbox
64
65
 
@@ -27,7 +27,8 @@ when using cmd.
27
27
 
28
28
  > :warning: **cmd2 is now "feature complete" for the `2.x` branch and is actively working on the
29
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.**
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.**
31
32
 
32
33
  ## The developers toolbox
33
34
 
@@ -1,4 +1,4 @@
1
- """Classes for the cmd2 plugin system."""
1
+ """Classes for the cmd2 lifecycle hooks that you can register multiple callback functions/methods with."""
2
2
 
3
3
  from dataclasses import (
4
4
  dataclass,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 3.0.0b2
3
+ Version: 3.0.0rc1
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
@@ -58,7 +58,8 @@ when using cmd.
58
58
 
59
59
  > :warning: **cmd2 is now "feature complete" for the `2.x` branch and is actively working on the
60
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.**
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.**
62
63
 
63
64
  ## The developers toolbox
64
65
 
@@ -12,6 +12,7 @@ codecov.yml
12
12
  mkdocs.yml
13
13
  package.json
14
14
  pyproject.toml
15
+ ruff.toml
15
16
  tasks.py
16
17
  cmd2/__init__.py
17
18
  cmd2/argparse_completer.py
@@ -103,14 +104,14 @@ docs/migrating/index.md
103
104
  docs/migrating/minimum.md
104
105
  docs/migrating/next_steps.md
105
106
  docs/migrating/why.md
107
+ docs/mixins/index.md
108
+ docs/mixins/mixin_template.md
106
109
  docs/overrides/main.html
107
110
  docs/overview/alternatives.md
108
111
  docs/overview/index.md
109
112
  docs/overview/installation.md
110
113
  docs/overview/integrating.md
111
114
  docs/overview/resources.md
112
- docs/plugins/index.md
113
- docs/plugins/plugin_template.md
114
115
  docs/stylesheets/cmd2.css
115
116
  docs/stylesheets/readthedocs.css
116
117
  examples/.cmd2rc
@@ -124,6 +125,7 @@ examples/cmd_as_argument.py
124
125
  examples/color.py
125
126
  examples/command_sets.py
126
127
  examples/custom_parser.py
128
+ examples/custom_types.py
127
129
  examples/default_categories.py
128
130
  examples/dynamic_commands.py
129
131
  examples/environment.py
@@ -134,6 +136,7 @@ examples/hello_cmd2.py
134
136
  examples/help_categories.py
135
137
  examples/hooks.py
136
138
  examples/migrating.py
139
+ examples/mixin.py
137
140
  examples/modular_commands.py
138
141
  examples/paged_output.py
139
142
  examples/persistent_history.py
@@ -265,22 +268,6 @@ examples/transcripts/exampleSession.txt
265
268
  examples/transcripts/pirate.transcript
266
269
  examples/transcripts/quit.txt
267
270
  examples/transcripts/transcript_regex.txt
268
- plugins/README.txt
269
- plugins/tasks.py
270
- plugins/template/CHANGELOG.md
271
- plugins/template/LICENSE
272
- plugins/template/README.md
273
- plugins/template/build-pyenvs.sh
274
- plugins/template/noxfile.py
275
- plugins/template/setup.py
276
- plugins/template/tasks.py
277
- plugins/template/cmd2_myplugin/__init__.py
278
- plugins/template/cmd2_myplugin/myplugin.py
279
- plugins/template/cmd2_myplugin/pylintrc
280
- plugins/template/examples/example.py
281
- plugins/template/tests/__init__.py
282
- plugins/template/tests/pylintrc
283
- plugins/template/tests/test_myplugin.py
284
271
  tests/.cmd2rc
285
272
  tests/__init__.py
286
273
  tests/conftest.py
@@ -5,10 +5,6 @@ component_management:
5
5
  name: cmd2 # this is a display name, and can be changed freely
6
6
  paths:
7
7
  - cmd2/**
8
- - component_id: plugins
9
- name: plugins
10
- paths:
11
- - plugins/**
12
8
 
13
9
  # Ignore certain paths, all files under these paths will be skipped during processing
14
10
  ignore:
@@ -53,10 +53,10 @@ app.cmdloop()
53
53
  end="<!--intro-end-->"
54
54
  %}
55
55
 
56
- ## Plugins
56
+ ## Mixins
57
57
 
58
58
  {%
59
- include-markdown "./plugins/index.md"
59
+ include-markdown "./mixins/index.md"
60
60
  start="<!--intro-start-->"
61
61
  end="<!--intro-end-->"
62
62
  %}
@@ -0,0 +1,7 @@
1
+ # Mixins
2
+
3
+ <!--intro-start-->
4
+
5
+ - [cmd2 Mixin Template](mixin_template.md)
6
+
7
+ <!--intro-end-->
@@ -0,0 +1,170 @@
1
+ # cmd2 Mixin Template
2
+
3
+ ## Mixin Classes in General
4
+
5
+ In Python, a mixin is a class designed to provide a specific set of functionalities to other classes
6
+ through multiple inheritance. Mixins are not intended to be instantiated on their own; rather, they
7
+ serve as a way to "mix in" or compose behaviors into a base class without creating a rigid "is-a"
8
+ relationship.
9
+
10
+ For more information about Mixin Classes, we recommend this `Real Python` article on
11
+ [What Are Mixin Classes in Python?](https://realpython.com/python-mixin/).
12
+
13
+ ## Overview of cmd2 mixins
14
+
15
+ If you have some set of re-usable behaviors that you wish to apply to multiple different `cmd2`
16
+ applications, then creating a mixin class to encapsulate this behavior can be a great idea. It is
17
+ one way to extend `cmd2` by relying on multiple inheritance. It is quick and easy, but there are
18
+ some potential pitfalls you should be aware of so you know how to do it correctly.
19
+
20
+ The [mixins.py](https://github.com/python-cmd2/cmd2/blob/main/examples/mixins.py) example is a
21
+ general example that shows you how you can develop a mixin class for `cmd2` applicaitons. In the
22
+ past we have referred to these as "Plugins", but in retrospect that probably isn't the best name for
23
+ them. They are generally mixin classes that add some extra functionality to your class which
24
+ inherits from [cmd2.Cmd][].
25
+
26
+ ## Using this template
27
+
28
+ This file provides a very basic template for how you can create your own cmd2 Mixin class to
29
+ encapsulate re-usable behavior that can be applied to multiple `cmd2` applications via multiple
30
+ inheritance.
31
+
32
+ ## Naming
33
+
34
+ If you decide to publish your Mixin as a Python package, you should consider prefixing the name of
35
+ your project with `cmd2-`. If you take this approach, then within that project, you should have a
36
+ package with a prefix of `cmd2_`.
37
+
38
+ ## Adding functionality
39
+
40
+ There are many ways to add functionality to `cmd2` using a mixin. A mixin is a class that
41
+ encapsulates and injects code into another class. Developers who use a mixin in their `cmd2`
42
+ project, will inject the mixin's code into their subclass of [cmd2.Cmd][].
43
+
44
+ ### Mixin and Initialization
45
+
46
+ The following short example shows how to create a mixin class and how everything gets initialized.
47
+
48
+ Here's the mixin:
49
+
50
+ ```python
51
+ class MyMixin:
52
+ def __init__(self, *args, **kwargs):
53
+ # code placed here runs before cmd2.Cmd initializes
54
+ super().__init__(*args, **kwargs)
55
+ # code placed here runs after cmd2.Cmd initializes
56
+ ```
57
+
58
+ and an example app which uses the mixin:
59
+
60
+ ```python
61
+ import cmd2
62
+
63
+
64
+ class Example(MyMixin, cmd2.Cmd):
65
+ """A cmd2 application class to show how to use a mixin class."""
66
+
67
+ def __init__(self, *args, **kwargs):
68
+ # code placed here runs before cmd2.Cmd or
69
+ # any mixins initialize
70
+ super().__init__(*args, **kwargs)
71
+ # code placed here runs after cmd2.Cmd and
72
+ # all mixins have initialized
73
+ ```
74
+
75
+ Note how the mixin must be inherited (or mixed in) before `cmd2.Cmd`. This is required for two
76
+ reasons:
77
+
78
+ - The `cmd.Cmd.__init__()` method in the python standard library does not call `super().__init__()`.
79
+ Because of this oversight, if you don't inherit from `MyMixin` first, the `MyMixin.__init__()`
80
+ method will never be called.
81
+ - You may want your mixin to be able to override methods from `cmd2.Cmd`. If you mixin the mixin
82
+ class after `cmd2.Cmd`, the python method resolution order will call `cmd2.Cmd` methods before it
83
+ calls those in your mixin.
84
+
85
+ ### Add commands
86
+
87
+ Your mixin can add user visible commands. You do it the same way in a mixin that you would in a
88
+ `cmd2.Cmd` app:
89
+
90
+ ```python
91
+ class MyMixin:
92
+
93
+ def do_say(self, statement):
94
+ """Simple say command"""
95
+ self.poutput(statement)
96
+ ```
97
+
98
+ You have all the same capabilities within the mixin that you do inside a `cmd2.Cmd` app, including
99
+ argument parsing via decorators and custom help methods.
100
+
101
+ ### Add (or hide) settings
102
+
103
+ A mixin may add user controllable settings to the application. Here's an example:
104
+
105
+ ```python
106
+ class MyMixin:
107
+ def __init__(self, *args, **kwargs):
108
+ # code placed here runs before cmd2.Cmd initializes
109
+ super().__init__(*args, **kwargs)
110
+ # code placed here runs after cmd2.Cmd initializes
111
+ self.mysetting = 'somevalue'
112
+ self.settable.update({'mysetting': 'short help message for mysetting'})
113
+ ```
114
+
115
+ You can also hide settings from the user by removing them from `self.settable`.
116
+
117
+ ### Decorators
118
+
119
+ Your mixin can provide a decorator which users of your mixin can use to wrap functionality around
120
+ their own commands.
121
+
122
+ ### Override methods
123
+
124
+ Your mixin can override core `cmd2.Cmd` methods, changing their behavior. This approach should be
125
+ used sparingly, because it is very brittle. If a developer chooses to use multiple mixins in their
126
+ application, and several of the mixins override the same method, only the first mixin to be mixed in
127
+ will have the overridden method called.
128
+
129
+ Hooks are a much better approach.
130
+
131
+ ### Hooks
132
+
133
+ Mixins can register hooks, which are called by `cmd2.Cmd` during various points in the application
134
+ and command processing lifecycle. Mixins should not override any of the legacy `cmd` hook methods,
135
+ instead they should register their hooks as
136
+ [described](https://cmd2.readthedocs.io/en/latest/hooks.html) in the `cmd2` documentation.
137
+
138
+ You should name your hooks so that they begin with the name of your mixin. Hook methods get mixed
139
+ into the `cmd2` application and this naming convention helps avoid unintentional method overriding.
140
+
141
+ Here's a simple example:
142
+
143
+ ```python
144
+ class MyMixin:
145
+
146
+ def __init__(self, *args, **kwargs):
147
+ # code placed here runs before cmd2 initializes
148
+ super().__init__(*args, **kwargs)
149
+ # code placed here runs after cmd2 initializes
150
+ # this is where you register any hook functions
151
+ self.register_postparsing_hook(self.cmd2_mymixin_postparsing_hook)
152
+
153
+ def cmd2_mymixin_postparsing_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
154
+ """Method to be called after parsing user input, but before running the command"""
155
+ self.poutput('in postparsing_hook')
156
+ return data
157
+ ```
158
+
159
+ Registration allows multiple mixins (or even the application itself) to each inject code to be
160
+ called during the application or command processing lifecycle.
161
+
162
+ See the [cmd2 hook documentation](https://cmd2.readthedocs.io/en/latest/hooks.html) for full details
163
+ of the application and command lifecycle, including all available hooks and the ways hooks can
164
+ influence the lifecycle.
165
+
166
+ ### Classes and Functions
167
+
168
+ Your mixin can also provide classes and functions which can be used by developers of `cmd2` based
169
+ applications. Describe these classes and functions in your documentation so users of your mixin will
170
+ know what's available.
@@ -20,6 +20,18 @@ The functionality within the `cmd2.ansi` module has either been removed or chang
20
20
  `rich` and moved to one of the new modules: [cmd2.string_utils][], [cmd2.styles][], or
21
21
  [cmd2.terminal_utils][].
22
22
 
23
+ To ease the migration path from `cmd2` 2.x to 3.x, we have created the `cmd2-ansi` module which is a
24
+ backport of the `cmd2.ansi` module present in `cmd2` 2.7.0 in a standalone fashion. Relevant links:
25
+
26
+ - PyPI: [cmd2-ansi](https://pypi.org/project/cmd2-ansi/)
27
+ - GitHub: [cmd2-ansi](https://github.com/python-cmd2/cmd2-ansi)
28
+
29
+ To use this backport:
30
+
31
+ ```Python
32
+ from cmd2_ansi import ansi
33
+ ```
34
+
23
35
  #### table_creator
24
36
 
25
37
  The `cmd2.table_creator` module no longer exists. Please see rich's documentation on
@@ -31,6 +43,19 @@ demonstrates how to use `rich` tables in a `cmd2` application.
31
43
  offered. We apologize for this backwards incompatibility, but the APIs were fundamentally different
32
44
  and we could not figure out a way to create a backwards-compatibility wrapper.
33
45
 
46
+ To ease the migration path from `cmd2` 2.x to 3.x, we have created the `cmd2-table` module which is
47
+ a backport of the `cmd2.table_creator` module present in `cmd2` 2.7.0 in a standalone fashion.
48
+ Relevant links:
49
+
50
+ - PyPI: [cmd2-table](https://pypi.org/project/cmd2-table/)
51
+ - GitHub: [cmd2-table](https://github.com/python-cmd2/cmd2-table)
52
+
53
+ To use this backport:
54
+
55
+ ```Python
56
+ from cmd2_table import table_creator
57
+ ```
58
+
34
59
  ### Added modules
35
60
 
36
61
  #### colors
@@ -32,6 +32,8 @@ each:
32
32
  subcommands, etc.
33
33
  - [custom_parser.py](https://github.com/python-cmd2/cmd2/blob/main/examples/custom_parser.py)
34
34
  - Demonstrates how to create your own custom `Cmd2ArgumentParser`
35
+ - [custom_types.py](https://github.com/python-cmd2/cmd2/blob/main/examples/custom_types.py)
36
+ - Some useful custom argument types
35
37
  - [default_categories.py](https://github.com/python-cmd2/cmd2/blob/main/examples/default_categories.py)
36
38
  - Demonstrates usage of `@with_default_category` decorator to group and categorize commands and
37
39
  `CommandSet` use
@@ -0,0 +1,165 @@
1
+ """Some useful argument types.
2
+
3
+ Note that these types can be used with other argparse-compatible libraries, including
4
+ "argparse" itself.
5
+
6
+ The 'type' parameter to ArgumentParser.add_argument() must be a callable object,
7
+ typically a function. That function is called to convert the string to the Python type available
8
+ in the 'namespace' passed to your "do_xyz" command function. Thus, "type=int" works because
9
+ int("53") returns the integer value 53. If that callable object / function raises an exception
10
+ due to invalid input, the name ("repr") of the object/function will be printed in the error message
11
+ to the user. Using lambda, functools.partial, or the like will generate a callable object with a
12
+ rather opaque repr so it can be useful to have a one-line function rather than relying on a lambda,
13
+ even for a short expression.
14
+
15
+ For "types" that have some context/state, using a class with a __call__ method, and overriding
16
+ the __repr__ method, allows you to produce an error message that provides that information
17
+ to the user.
18
+ """
19
+
20
+ from collections.abc import Iterable
21
+
22
+ import cmd2
23
+
24
+ _int_suffixes = {
25
+ # SI number suffixes (unit prefixes):
26
+ "K": 1_000,
27
+ "M": 1_000_000,
28
+ "G": 1_000_000_000,
29
+ "T": 1_000_000_000_000,
30
+ "P": 1_000_000_000_000_000,
31
+ # IEC number suffixes (unit prefixes):
32
+ "Ki": 1024,
33
+ "Mi": 1024 * 1024,
34
+ "Gi": 1024 * 1024 * 1024,
35
+ "Ti": 1024 * 1024 * 1024 * 1024,
36
+ "Pi": 1024 * 1024 * 1024 * 1024 * 1024,
37
+ }
38
+
39
+
40
+ def integer(value_str: str) -> int:
41
+ """Will accept any base, and optional suffix like '64K'."""
42
+ multiplier = 1
43
+ # If there is a matching suffix, use its multiplier:
44
+ for suffix, suffix_multiplier in _int_suffixes.items():
45
+ if value_str.endswith(suffix):
46
+ value_str = value_str.removesuffix(suffix)
47
+ multiplier = suffix_multiplier
48
+ break
49
+
50
+ return int(value_str, 0) * multiplier
51
+
52
+
53
+ def hexadecimal(value_str: str) -> int:
54
+ """Parse hexidecimal integer, with optional '0x' prefix."""
55
+ return int(value_str, base=16)
56
+
57
+
58
+ class Range:
59
+ """Useful as type for large ranges, when 'choices=range(maxval)' would be excessively large."""
60
+
61
+ def __init__(self, firstval: int, secondval: int | None = None) -> None:
62
+ """Construct a Range, with same syntax as 'range'.
63
+
64
+ :param firstval: either the top end of range (if 'secondval' is missing), or the bottom end
65
+ :param secondval: top end of range (one higher than maximum value)
66
+ """
67
+ if secondval is None:
68
+ self.bottom = 0
69
+ self.top = firstval
70
+ else:
71
+ self.bottom = firstval
72
+ self.top = secondval
73
+
74
+ self.range_str = f"[{self.bottom}..{self.top - 1}]"
75
+
76
+ def __repr__(self) -> str:
77
+ """Will be printed as the 'argument type' to user on syntax or range error."""
78
+ return f"Range{self.range_str}"
79
+
80
+ def __call__(self, arg: str) -> int:
81
+ """Parse the string argument and checks validity."""
82
+ val = integer(arg)
83
+ if self.bottom <= val < self.top:
84
+ return val
85
+ raise ValueError(f"Value '{val}' not within {self.range_str}")
86
+
87
+
88
+ class IntSet:
89
+ """Set of integers from a specified range.
90
+
91
+ e.g. '5', '1-3,8', 'all'
92
+ """
93
+
94
+ def __init__(self, firstval: int, secondval: int | None = None) -> None:
95
+ """Construct an IntSet, with same syntax as 'range'.
96
+
97
+ :param firstval: either the top end of range (if 'secondval' is missing), or the bottom end
98
+ :param secondval: top end of range (one higher than maximum value)
99
+ """
100
+ if secondval is None:
101
+ self.bottom = 0
102
+ self.top = firstval
103
+ else:
104
+ self.bottom = firstval
105
+ self.top = secondval
106
+
107
+ self.range_str = f"[{self.bottom}..{self.top - 1}]"
108
+
109
+ def __repr__(self) -> str:
110
+ """Will be printed as the 'argument type' to user on syntax or range error."""
111
+ return f"IntSet{self.range_str}"
112
+
113
+ def __call__(self, arg: str) -> Iterable[int]:
114
+ """Parse a string into an iterable returning ints."""
115
+ if arg == 'all':
116
+ return range(self.bottom, self.top)
117
+
118
+ out = []
119
+ for piece in arg.split(','):
120
+ if '-' in piece:
121
+ a, b = [int(x) for x in piece.split('-', 2)]
122
+ if a < self.bottom:
123
+ raise ValueError(f"Value '{a}' not within {self.range_str}")
124
+ if b >= self.top:
125
+ raise ValueError(f"Value '{b}' not within {self.range_str}")
126
+ out += list(range(a, b + 1))
127
+ else:
128
+ val = int(piece)
129
+ if not self.bottom <= val < self.top:
130
+ raise ValueError(f"Value '{val}' not within {self.range_str}")
131
+ out += [val]
132
+ return out
133
+
134
+
135
+ if __name__ == '__main__':
136
+ import argparse
137
+ import sys
138
+
139
+ class CustomTypesExample(cmd2.Cmd):
140
+ example_parser = cmd2.Cmd2ArgumentParser()
141
+ example_parser.add_argument(
142
+ '--value', '-v', type=integer, help='Integer value, with optional K/M/G/Ki/Mi/Gi/... suffix'
143
+ )
144
+ example_parser.add_argument('--memory-address', '-m', type=hexadecimal, help='Memory address in hex')
145
+ example_parser.add_argument('--year', type=Range(1900, 2000), help='Year between 1900-1999')
146
+ example_parser.add_argument(
147
+ '--index', dest='index_list', type=IntSet(100), help='One or more indexes 0-99. e.g. "1,3,5", "10,30-50", "all"'
148
+ )
149
+
150
+ @cmd2.with_argparser(example_parser)
151
+ def do_example(self, args: argparse.Namespace) -> None:
152
+ """The example command."""
153
+ if args.value is not None:
154
+ self.poutput(f"Value: {args.value}")
155
+ if args.memory_address is not None:
156
+ # print the value as hex, with leading "0x" + 16 hex digits + three '_' group separators:
157
+ self.poutput(f"Address: {args.memory_address:#021_x}")
158
+ if args.year is not None:
159
+ self.poutput(f"Year: {args.year}")
160
+ if args.index_list is not None:
161
+ for index in args.index_list:
162
+ self.poutput(f"Process index {index}")
163
+
164
+ app = CustomTypesExample()
165
+ sys.exit(app.cmdloop())
@@ -1,4 +1,5 @@
1
- """An example cmd2 plugin."""
1
+ #!/usr/bin/env python
2
+ """An example cmd2 mixin."""
2
3
 
3
4
  import functools
4
5
  from collections.abc import Callable
@@ -13,7 +14,7 @@ else:
13
14
 
14
15
 
15
16
  def empty_decorator(func: Callable) -> Callable:
16
- """An empty decorator for myplugin."""
17
+ """An empty decorator for use with your mixin."""
17
18
 
18
19
  @functools.wraps(func)
19
20
  def _empty_decorator(self, *args, **kwargs) -> None:
@@ -24,15 +25,15 @@ def empty_decorator(func: Callable) -> Callable:
24
25
  return _empty_decorator
25
26
 
26
27
 
27
- class MyPluginMixin(_Base):
28
+ class MyMixin(_Base):
28
29
  """A mixin class which adds a 'say' command to a cmd2 subclass.
29
30
 
30
31
  The order in which you add the mixin matters. Say you want to
31
32
  use this mixin in a class called MyApp.
32
33
 
33
- class MyApp(cmd2_myplugin.MyPlugin, cmd2.Cmd):
34
+ class MyApp(MyMixin, cmd2.Cmd):
34
35
  def __init__(self, *args, **kwargs):
35
- # gotta have this or neither the plugin or cmd2 will initialize
36
+ # gotta have this or neither the mixin or cmd2 will initialize
36
37
  super().__init__(*args, **kwargs)
37
38
  """
38
39
 
@@ -41,9 +42,9 @@ class MyPluginMixin(_Base):
41
42
  super().__init__(*args, **kwargs)
42
43
  # code placed here runs after cmd2 initializes
43
44
  # this is where you register any hook functions
44
- self.register_preloop_hook(self.cmd2_myplugin_preloop_hook)
45
- self.register_postloop_hook(self.cmd2_myplugin_postloop_hook)
46
- self.register_postparsing_hook(self.cmd2_myplugin_postparsing_hook)
45
+ self.register_preloop_hook(self.cmd2_mymixin_preloop_hook)
46
+ self.register_postloop_hook(self.cmd2_mymixin_postloop_hook)
47
+ self.register_postparsing_hook(self.cmd2_mymixin_postparsing_hook)
47
48
 
48
49
  def do_say(self, statement) -> None:
49
50
  """Simple say command."""
@@ -51,15 +52,32 @@ class MyPluginMixin(_Base):
51
52
 
52
53
  #
53
54
  # define hooks as functions, not methods
54
- def cmd2_myplugin_preloop_hook(self) -> None:
55
+ def cmd2_mymixin_preloop_hook(self) -> None:
55
56
  """Method to be called before the command loop begins."""
56
57
  self.poutput("preloop hook")
57
58
 
58
- def cmd2_myplugin_postloop_hook(self) -> None:
59
+ def cmd2_mymixin_postloop_hook(self) -> None:
59
60
  """Method to be called after the command loop finishes."""
60
61
  self.poutput("postloop hook")
61
62
 
62
- def cmd2_myplugin_postparsing_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
63
+ def cmd2_mymixin_postparsing_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
63
64
  """Method to be called after parsing user input, but before running the command."""
64
65
  self.poutput('in postparsing hook')
65
66
  return data
67
+
68
+
69
+ class Example(MyMixin, cmd2.Cmd):
70
+ """An class to show how to use a mixin."""
71
+
72
+ def __init__(self, *args, **kwargs) -> None:
73
+ # gotta have this or neither the mixin or cmd2 will initialize
74
+ super().__init__(*args, **kwargs)
75
+
76
+ @empty_decorator
77
+ def do_something(self, _arg) -> None:
78
+ self.poutput('this is the something command')
79
+
80
+
81
+ if __name__ == '__main__':
82
+ app = Example()
83
+ app.cmdloop()
@@ -193,9 +193,9 @@ nav:
193
193
  - examples/getting_started.md
194
194
  - examples/alternate_event_loops.md
195
195
  - examples/examples.md
196
- - Plugins:
197
- - plugins/index.md
198
- - plugins/plugin_template.md
196
+ - Mixins:
197
+ - mixins/index.md
198
+ - mixins/mixin_template.md
199
199
  - Testing:
200
200
  - testing.md
201
201
  - API Reference: