cmd2 2.6.0__tar.gz → 2.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (362) hide show
  1. {cmd2-2.6.0 → cmd2-2.6.1}/CHANGELOG.md +5 -0
  2. {cmd2-2.6.0 → cmd2-2.6.1}/PKG-INFO +1 -1
  3. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/cmd2.py +39 -33
  4. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/utils.py +30 -23
  5. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2.egg-info/PKG-INFO +1 -1
  6. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2.egg-info/SOURCES.txt +1 -0
  7. {cmd2-2.6.0 → cmd2-2.6.1}/pyproject.toml +15 -37
  8. cmd2-2.6.1/tests/test_future_annotations.py +22 -0
  9. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_utils.py +41 -0
  10. {cmd2-2.6.0 → cmd2-2.6.1}/.pre-commit-config.yaml +0 -0
  11. {cmd2-2.6.0 → cmd2-2.6.1}/.prettierignore +0 -0
  12. {cmd2-2.6.0 → cmd2-2.6.1}/.prettierrc +0 -0
  13. {cmd2-2.6.0 → cmd2-2.6.1}/.readthedocs.yaml +0 -0
  14. {cmd2-2.6.0 → cmd2-2.6.1}/LICENSE +0 -0
  15. {cmd2-2.6.0 → cmd2-2.6.1}/MANIFEST.in +0 -0
  16. {cmd2-2.6.0 → cmd2-2.6.1}/Makefile +0 -0
  17. {cmd2-2.6.0 → cmd2-2.6.1}/Pipfile +0 -0
  18. {cmd2-2.6.0 → cmd2-2.6.1}/README.md +0 -0
  19. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/__init__.py +0 -0
  20. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/ansi.py +0 -0
  21. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/argparse_completer.py +0 -0
  22. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/argparse_custom.py +0 -0
  23. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/clipboard.py +0 -0
  24. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/command_definition.py +0 -0
  25. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/constants.py +0 -0
  26. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/decorators.py +0 -0
  27. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/exceptions.py +0 -0
  28. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/history.py +0 -0
  29. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/parsing.py +0 -0
  30. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/plugin.py +0 -0
  31. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/py.typed +0 -0
  32. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/py_bridge.py +0 -0
  33. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/rl_utils.py +0 -0
  34. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/table_creator.py +0 -0
  35. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2/transcript.py +0 -0
  36. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2.egg-info/dependency_links.txt +0 -0
  37. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2.egg-info/requires.txt +0 -0
  38. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2.egg-info/top_level.txt +0 -0
  39. {cmd2-2.6.0 → cmd2-2.6.1}/cmd2.png +0 -0
  40. {cmd2-2.6.0 → cmd2-2.6.1}/codecov.yml +0 -0
  41. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/ansi.md +0 -0
  42. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/argparse_completer.md +0 -0
  43. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/argparse_custom.md +0 -0
  44. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/cmd.md +0 -0
  45. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/command_definition.md +0 -0
  46. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/constants.md +0 -0
  47. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/decorators.md +0 -0
  48. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/exceptions.md +0 -0
  49. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/history.md +0 -0
  50. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/index.md +0 -0
  51. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/parsing.md +0 -0
  52. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/plugin.md +0 -0
  53. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/py_bridge.md +0 -0
  54. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/table_creator.md +0 -0
  55. {cmd2-2.6.0 → cmd2-2.6.1}/docs/api/utils.md +0 -0
  56. {cmd2-2.6.0 → cmd2-2.6.1}/docs/doc_conventions.md +0 -0
  57. {cmd2-2.6.0 → cmd2-2.6.1}/docs/examples/alternate_event_loops.md +0 -0
  58. {cmd2-2.6.0 → cmd2-2.6.1}/docs/examples/examples.md +0 -0
  59. {cmd2-2.6.0 → cmd2-2.6.1}/docs/examples/first_app.md +0 -0
  60. {cmd2-2.6.0 → cmd2-2.6.1}/docs/examples/index.md +0 -0
  61. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/argument_processing.md +0 -0
  62. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/builtin_commands.md +0 -0
  63. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/clipboard.md +0 -0
  64. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/commands.md +0 -0
  65. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/completion.md +0 -0
  66. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/disable_commands.md +0 -0
  67. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/embedded_python_shells.md +0 -0
  68. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/generating_output.md +0 -0
  69. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/help.md +0 -0
  70. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/history.md +0 -0
  71. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/hooks.md +0 -0
  72. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/index.md +0 -0
  73. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/initialization.md +0 -0
  74. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/misc.md +0 -0
  75. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/modular_commands.md +0 -0
  76. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/multiline_commands.md +0 -0
  77. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/os.md +0 -0
  78. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/packaging.md +0 -0
  79. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/plugins.md +0 -0
  80. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/prompt.md +0 -0
  81. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/redirection.md +0 -0
  82. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/scripting.md +0 -0
  83. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/settings.md +0 -0
  84. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/shortcuts_aliases_macros.md +0 -0
  85. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/startup_commands.md +0 -0
  86. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/table_creation.md +0 -0
  87. {cmd2-2.6.0 → cmd2-2.6.1}/docs/features/transcripts.md +0 -0
  88. {cmd2-2.6.0 → cmd2-2.6.1}/docs/index.md +0 -0
  89. {cmd2-2.6.0 → cmd2-2.6.1}/docs/javascripts/readthedocs.js +0 -0
  90. {cmd2-2.6.0 → cmd2-2.6.1}/docs/migrating/incompatibilities.md +0 -0
  91. {cmd2-2.6.0 → cmd2-2.6.1}/docs/migrating/index.md +0 -0
  92. {cmd2-2.6.0 → cmd2-2.6.1}/docs/migrating/minimum.md +0 -0
  93. {cmd2-2.6.0 → cmd2-2.6.1}/docs/migrating/next_steps.md +0 -0
  94. {cmd2-2.6.0 → cmd2-2.6.1}/docs/migrating/why.md +0 -0
  95. {cmd2-2.6.0 → cmd2-2.6.1}/docs/overrides/main.html +0 -0
  96. {cmd2-2.6.0 → cmd2-2.6.1}/docs/overview/alternatives.md +0 -0
  97. {cmd2-2.6.0 → cmd2-2.6.1}/docs/overview/index.md +0 -0
  98. {cmd2-2.6.0 → cmd2-2.6.1}/docs/overview/installation.md +0 -0
  99. {cmd2-2.6.0 → cmd2-2.6.1}/docs/overview/integrating.md +0 -0
  100. {cmd2-2.6.0 → cmd2-2.6.1}/docs/overview/resources.md +0 -0
  101. {cmd2-2.6.0 → cmd2-2.6.1}/docs/plugins/external_test.md +0 -0
  102. {cmd2-2.6.0 → cmd2-2.6.1}/docs/plugins/index.md +0 -0
  103. {cmd2-2.6.0 → cmd2-2.6.1}/docs/requirements.txt +0 -0
  104. {cmd2-2.6.0 → cmd2-2.6.1}/docs/stylesheets/readthedocs.css +0 -0
  105. {cmd2-2.6.0 → cmd2-2.6.1}/docs/testing.md +0 -0
  106. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.cmd2rc +0 -0
  107. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/@plugins_snapshot.json +0 -0
  108. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_ast.data.json +0 -0
  109. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_ast.meta.json +0 -0
  110. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_codecs.data.json +0 -0
  111. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_codecs.meta.json +0 -0
  112. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_collections_abc.data.json +0 -0
  113. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_collections_abc.meta.json +0 -0
  114. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_typeshed/__init__.data.json +0 -0
  115. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_typeshed/__init__.meta.json +0 -0
  116. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_typeshed/importlib.data.json +0 -0
  117. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/_typeshed/importlib.meta.json +0 -0
  118. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/abc.data.json +0 -0
  119. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/abc.meta.json +0 -0
  120. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/argparse.data.json +0 -0
  121. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/argparse.meta.json +0 -0
  122. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/builtins.data.json +0 -0
  123. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/builtins.meta.json +0 -0
  124. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/codecs.data.json +0 -0
  125. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/codecs.meta.json +0 -0
  126. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/collections/__init__.data.json +0 -0
  127. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/collections/__init__.meta.json +0 -0
  128. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/collections/abc.data.json +0 -0
  129. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/collections/abc.meta.json +0 -0
  130. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/contextlib.data.json +0 -0
  131. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/contextlib.meta.json +0 -0
  132. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/dataclasses.data.json +0 -0
  133. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/dataclasses.meta.json +0 -0
  134. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/__init__.data.json +0 -0
  135. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/__init__.meta.json +0 -0
  136. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/_policybase.data.json +0 -0
  137. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/_policybase.meta.json +0 -0
  138. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/charset.data.json +0 -0
  139. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/charset.meta.json +0 -0
  140. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/contentmanager.data.json +0 -0
  141. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/contentmanager.meta.json +0 -0
  142. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/errors.data.json +0 -0
  143. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/errors.meta.json +0 -0
  144. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/header.data.json +0 -0
  145. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/header.meta.json +0 -0
  146. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/message.data.json +0 -0
  147. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/message.meta.json +0 -0
  148. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/policy.data.json +0 -0
  149. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/email/policy.meta.json +0 -0
  150. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/enum.data.json +0 -0
  151. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/enum.meta.json +0 -0
  152. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/genericpath.data.json +0 -0
  153. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/genericpath.meta.json +0 -0
  154. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/__init__.data.json +0 -0
  155. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/__init__.meta.json +0 -0
  156. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/_abc.data.json +0 -0
  157. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/_abc.meta.json +0 -0
  158. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/abc.data.json +0 -0
  159. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/abc.meta.json +0 -0
  160. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/machinery.data.json +0 -0
  161. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/machinery.meta.json +0 -0
  162. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/metadata/__init__.data.json +0 -0
  163. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/metadata/__init__.meta.json +0 -0
  164. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/metadata/_meta.data.json +0 -0
  165. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/metadata/_meta.meta.json +0 -0
  166. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/readers.data.json +0 -0
  167. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/readers.meta.json +0 -0
  168. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/resources/__init__.data.json +0 -0
  169. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/resources/__init__.meta.json +0 -0
  170. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/resources/abc.data.json +0 -0
  171. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/importlib/resources/abc.meta.json +0 -0
  172. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/io.data.json +0 -0
  173. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/io.meta.json +0 -0
  174. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/os/__init__.data.json +0 -0
  175. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/os/__init__.meta.json +0 -0
  176. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/os/path.data.json +0 -0
  177. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/os/path.meta.json +0 -0
  178. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/pathlib.data.json +0 -0
  179. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/pathlib.meta.json +0 -0
  180. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/posixpath.data.json +0 -0
  181. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/posixpath.meta.json +0 -0
  182. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/re.data.json +0 -0
  183. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/re.meta.json +0 -0
  184. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/resource.data.json +0 -0
  185. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/resource.meta.json +0 -0
  186. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sre_compile.data.json +0 -0
  187. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sre_compile.meta.json +0 -0
  188. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sre_constants.data.json +0 -0
  189. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sre_constants.meta.json +0 -0
  190. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sre_parse.data.json +0 -0
  191. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sre_parse.meta.json +0 -0
  192. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/subprocess.data.json +0 -0
  193. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/subprocess.meta.json +0 -0
  194. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sys/__init__.data.json +0 -0
  195. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sys/__init__.meta.json +0 -0
  196. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sys/_monitoring.data.json +0 -0
  197. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/sys/_monitoring.meta.json +0 -0
  198. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/types.data.json +0 -0
  199. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/types.meta.json +0 -0
  200. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/typing.data.json +0 -0
  201. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/typing.meta.json +0 -0
  202. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/typing_extensions.data.json +0 -0
  203. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/typing_extensions.meta.json +0 -0
  204. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/zipfile/__init__.data.json +0 -0
  205. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/zipfile/__init__.meta.json +0 -0
  206. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/zipfile/_path.data.json +0 -0
  207. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/3.12/zipfile/_path.meta.json +0 -0
  208. {cmd2-2.6.0 → cmd2-2.6.1}/examples/.mypy_cache/CACHEDIR.TAG +0 -0
  209. {cmd2-2.6.0 → cmd2-2.6.1}/examples/README.md +0 -0
  210. {cmd2-2.6.0 → cmd2-2.6.1}/examples/alias_startup.py +0 -0
  211. {cmd2-2.6.0 → cmd2-2.6.1}/examples/arg_decorators.py +0 -0
  212. {cmd2-2.6.0 → cmd2-2.6.1}/examples/arg_print.py +0 -0
  213. {cmd2-2.6.0 → cmd2-2.6.1}/examples/argparse_completion.py +0 -0
  214. {cmd2-2.6.0 → cmd2-2.6.1}/examples/async_printing.py +0 -0
  215. {cmd2-2.6.0 → cmd2-2.6.1}/examples/basic.py +0 -0
  216. {cmd2-2.6.0 → cmd2-2.6.1}/examples/basic_completion.py +0 -0
  217. {cmd2-2.6.0 → cmd2-2.6.1}/examples/cmd2_history.dat +0 -0
  218. {cmd2-2.6.0 → cmd2-2.6.1}/examples/cmd_as_argument.py +0 -0
  219. {cmd2-2.6.0 → cmd2-2.6.1}/examples/colors.py +0 -0
  220. {cmd2-2.6.0 → cmd2-2.6.1}/examples/custom_parser.py +0 -0
  221. {cmd2-2.6.0 → cmd2-2.6.1}/examples/decorator_example.py +0 -0
  222. {cmd2-2.6.0 → cmd2-2.6.1}/examples/default_categories.py +0 -0
  223. {cmd2-2.6.0 → cmd2-2.6.1}/examples/dynamic_commands.py +0 -0
  224. {cmd2-2.6.0 → cmd2-2.6.1}/examples/environment.py +0 -0
  225. {cmd2-2.6.0 → cmd2-2.6.1}/examples/event_loops.py +0 -0
  226. {cmd2-2.6.0 → cmd2-2.6.1}/examples/example.py +0 -0
  227. {cmd2-2.6.0 → cmd2-2.6.1}/examples/exit_code.py +0 -0
  228. {cmd2-2.6.0 → cmd2-2.6.1}/examples/first_app.py +0 -0
  229. {cmd2-2.6.0 → cmd2-2.6.1}/examples/hello_cmd2.py +0 -0
  230. {cmd2-2.6.0 → cmd2-2.6.1}/examples/help_categories.py +0 -0
  231. {cmd2-2.6.0 → cmd2-2.6.1}/examples/hooks.py +0 -0
  232. {cmd2-2.6.0 → cmd2-2.6.1}/examples/initialization.py +0 -0
  233. {cmd2-2.6.0 → cmd2-2.6.1}/examples/migrating.py +0 -0
  234. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands/__init__.py +0 -0
  235. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands/commandset_basic.py +0 -0
  236. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands/commandset_complex.py +0 -0
  237. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands/commandset_custominit.py +0 -0
  238. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands_basic.py +0 -0
  239. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands_dynamic.py +0 -0
  240. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_commands_main.py +0 -0
  241. {cmd2-2.6.0 → cmd2-2.6.1}/examples/modular_subcommands.py +0 -0
  242. {cmd2-2.6.0 → cmd2-2.6.1}/examples/override_parser.py +0 -0
  243. {cmd2-2.6.0 → cmd2-2.6.1}/examples/paged_output.py +0 -0
  244. {cmd2-2.6.0 → cmd2-2.6.1}/examples/persistent_history.py +0 -0
  245. {cmd2-2.6.0 → cmd2-2.6.1}/examples/pirate.py +0 -0
  246. {cmd2-2.6.0 → cmd2-2.6.1}/examples/pretty_print.py +0 -0
  247. {cmd2-2.6.0 → cmd2-2.6.1}/examples/python_scripting.py +0 -0
  248. {cmd2-2.6.0 → cmd2-2.6.1}/examples/read_input.py +0 -0
  249. {cmd2-2.6.0 → cmd2-2.6.1}/examples/remove_builtin_commands.py +0 -0
  250. {cmd2-2.6.0 → cmd2-2.6.1}/examples/remove_settable.py +0 -0
  251. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/arg_printer.py +0 -0
  252. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/conditional.py +0 -0
  253. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/nested.txt +0 -0
  254. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/quit.txt +0 -0
  255. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/save_help_text.py +0 -0
  256. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/script.py +0 -0
  257. {cmd2-2.6.0 → cmd2-2.6.1}/examples/scripts/script.txt +0 -0
  258. {cmd2-2.6.0 → cmd2-2.6.1}/examples/subcommands.py +0 -0
  259. {cmd2-2.6.0 → cmd2-2.6.1}/examples/table_creation.py +0 -0
  260. {cmd2-2.6.0 → cmd2-2.6.1}/examples/tmux_launch.sh +0 -0
  261. {cmd2-2.6.0 → cmd2-2.6.1}/examples/tmux_split.sh +0 -0
  262. {cmd2-2.6.0 → cmd2-2.6.1}/examples/transcripts/exampleSession.txt +0 -0
  263. {cmd2-2.6.0 → cmd2-2.6.1}/examples/transcripts/pirate.transcript +0 -0
  264. {cmd2-2.6.0 → cmd2-2.6.1}/examples/transcripts/quit.txt +0 -0
  265. {cmd2-2.6.0 → cmd2-2.6.1}/examples/transcripts/transcript_regex.txt +0 -0
  266. {cmd2-2.6.0 → cmd2-2.6.1}/examples/unicode_commands.py +0 -0
  267. {cmd2-2.6.0 → cmd2-2.6.1}/mkdocs.yml +0 -0
  268. {cmd2-2.6.0 → cmd2-2.6.1}/package.json +0 -0
  269. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/README.txt +0 -0
  270. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/CHANGELOG.md +0 -0
  271. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/README.md +0 -0
  272. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/build-pyenvs.sh +0 -0
  273. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/cmd2_ext_test/__init__.py +0 -0
  274. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/cmd2_ext_test/cmd2_ext_test.py +0 -0
  275. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/cmd2_ext_test/py.typed +0 -0
  276. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/cmd2_ext_test/pylintrc +0 -0
  277. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/examples/example.py +0 -0
  278. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/noxfile.py +0 -0
  279. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/pyproject.toml +0 -0
  280. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/setup.py +0 -0
  281. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/tasks.py +0 -0
  282. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/tests/__init__.py +0 -0
  283. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/tests/pylintrc +0 -0
  284. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/ext_test/tests/test_ext_test.py +0 -0
  285. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/tasks.py +0 -0
  286. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/CHANGELOG.md +0 -0
  287. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/LICENSE +0 -0
  288. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/README.md +0 -0
  289. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/build-pyenvs.sh +0 -0
  290. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/cmd2_myplugin/__init__.py +0 -0
  291. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/cmd2_myplugin/myplugin.py +0 -0
  292. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/cmd2_myplugin/pylintrc +0 -0
  293. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/examples/example.py +0 -0
  294. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/noxfile.py +0 -0
  295. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/setup.py +0 -0
  296. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/tasks.py +0 -0
  297. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/tests/__init__.py +0 -0
  298. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/tests/pylintrc +0 -0
  299. {cmd2-2.6.0 → cmd2-2.6.1}/plugins/template/tests/test_myplugin.py +0 -0
  300. {cmd2-2.6.0 → cmd2-2.6.1}/readme_files/shout_out.csv +0 -0
  301. {cmd2-2.6.0 → cmd2-2.6.1}/readme_files/shoutout.txt +0 -0
  302. {cmd2-2.6.0 → cmd2-2.6.1}/setup.cfg +0 -0
  303. {cmd2-2.6.0 → cmd2-2.6.1}/tasks.py +0 -0
  304. {cmd2-2.6.0 → cmd2-2.6.1}/tests/.cmd2rc +0 -0
  305. {cmd2-2.6.0 → cmd2-2.6.1}/tests/__init__.py +0 -0
  306. {cmd2-2.6.0 → cmd2-2.6.1}/tests/conftest.py +0 -0
  307. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/echo.py +0 -0
  308. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/environment.py +0 -0
  309. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/help.py +0 -0
  310. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/py_locals.py +0 -0
  311. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/pyscript_dir.py +0 -0
  312. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/raises_exception.py +0 -0
  313. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/recursive.py +0 -0
  314. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/self_in_py.py +0 -0
  315. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/stdout_capture.py +0 -0
  316. {cmd2-2.6.0 → cmd2-2.6.1}/tests/pyscript/stop.py +0 -0
  317. {cmd2-2.6.0 → cmd2-2.6.1}/tests/relative_multiple.txt +0 -0
  318. {cmd2-2.6.0 → cmd2-2.6.1}/tests/script.py +0 -0
  319. {cmd2-2.6.0 → cmd2-2.6.1}/tests/script.txt +0 -0
  320. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/binary.bin +0 -0
  321. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/empty.txt +0 -0
  322. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/help.txt +0 -0
  323. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/nested.txt +0 -0
  324. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/one_down.txt +0 -0
  325. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/postcmds.txt +0 -0
  326. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/precmds.txt +0 -0
  327. {cmd2-2.6.0 → cmd2-2.6.1}/tests/scripts/utf8.txt +0 -0
  328. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_ansi.py +0 -0
  329. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_argparse.py +0 -0
  330. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_argparse_completer.py +0 -0
  331. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_argparse_custom.py +0 -0
  332. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_cmd2.py +0 -0
  333. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_completion.py +0 -0
  334. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_history.py +0 -0
  335. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_parsing.py +0 -0
  336. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_plugin.py +0 -0
  337. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_run_pyscript.py +0 -0
  338. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_table_creator.py +0 -0
  339. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_transcript.py +0 -0
  340. {cmd2-2.6.0 → cmd2-2.6.1}/tests/test_utils_defining_class.py +0 -0
  341. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/bol_eol.txt +0 -0
  342. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/characterclass.txt +0 -0
  343. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/dotstar.txt +0 -0
  344. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/extension_notation.txt +0 -0
  345. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/failure.txt +0 -0
  346. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/from_cmdloop.txt +0 -0
  347. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/multiline_no_regex.txt +0 -0
  348. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/multiline_regex.txt +0 -0
  349. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/no_output.txt +0 -0
  350. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/no_output_last.txt +0 -0
  351. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/regex_set.txt +0 -0
  352. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/singleslash.txt +0 -0
  353. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/slashes_escaped.txt +0 -0
  354. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/slashslash.txt +0 -0
  355. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/spaces.txt +0 -0
  356. {cmd2-2.6.0 → cmd2-2.6.1}/tests/transcripts/word_boundaries.txt +0 -0
  357. {cmd2-2.6.0 → cmd2-2.6.1}/tests_isolated/__init__.py +0 -0
  358. {cmd2-2.6.0 → cmd2-2.6.1}/tests_isolated/test_commandset/__init__.py +0 -0
  359. {cmd2-2.6.0 → cmd2-2.6.1}/tests_isolated/test_commandset/conftest.py +0 -0
  360. {cmd2-2.6.0 → cmd2-2.6.1}/tests_isolated/test_commandset/test_argparse_subcommands.py +0 -0
  361. {cmd2-2.6.0 → cmd2-2.6.1}/tests_isolated/test_commandset/test_categories.py +0 -0
  362. {cmd2-2.6.0 → cmd2-2.6.1}/tests_isolated/test_commandset/test_commandset.py +0 -0
@@ -1,3 +1,8 @@
1
+ ## 2.6.1 (June 8, 2025)
2
+
3
+ - Bug Fixes
4
+ - Fixed bug that prevented `cmd2` from working with `from __future__ import annotations`
5
+
1
6
  ## 2.6.0 (May 31, 2025)
2
7
 
3
8
  - Breaking Change
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 2.6.0
3
+ Version: 2.6.1
4
4
  Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
5
5
  Author: cmd2 Contributors
6
6
  License: The MIT License (MIT)
@@ -144,6 +144,7 @@ from .table_creator import (
144
144
  from .utils import (
145
145
  Settable,
146
146
  get_defining_class,
147
+ get_types,
147
148
  strip_doc_annotations,
148
149
  suggest_similar,
149
150
  )
@@ -3597,8 +3598,8 @@ class Cmd(cmd.Cmd):
3597
3598
  max_arg_num = 0
3598
3599
  arg_nums = set()
3599
3600
 
3600
- while True:
3601
- try:
3601
+ try:
3602
+ while True:
3602
3603
  cur_match = normal_matches.__next__()
3603
3604
 
3604
3605
  # Get the number string between the braces
@@ -3612,9 +3613,8 @@ class Cmd(cmd.Cmd):
3612
3613
  max_arg_num = max(max_arg_num, cur_num)
3613
3614
 
3614
3615
  arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=False))
3615
-
3616
- except StopIteration:
3617
- break
3616
+ except StopIteration:
3617
+ pass
3618
3618
 
3619
3619
  # Make sure the argument numbers are continuous
3620
3620
  if len(arg_nums) != max_arg_num:
@@ -3624,16 +3624,16 @@ class Cmd(cmd.Cmd):
3624
3624
  # Find all escaped arguments
3625
3625
  escaped_matches = re.finditer(MacroArg.macro_escaped_arg_pattern, value)
3626
3626
 
3627
- while True:
3628
- try:
3627
+ try:
3628
+ while True:
3629
3629
  cur_match = escaped_matches.__next__()
3630
3630
 
3631
3631
  # Get the number string between the braces
3632
3632
  cur_num_str = re.findall(MacroArg.digit_pattern, cur_match.group())[0]
3633
3633
 
3634
3634
  arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=True))
3635
- except StopIteration:
3636
- break
3635
+ except StopIteration:
3636
+ pass
3637
3637
 
3638
3638
  # Set the macro
3639
3639
  result = "overwritten" if args.name in self.macros else "created"
@@ -5545,10 +5545,10 @@ class Cmd(cmd.Cmd):
5545
5545
  def _validate_prepostloop_callable(cls, func: Callable[[], None]) -> None:
5546
5546
  """Check parameter and return types for preloop and postloop hooks."""
5547
5547
  cls._validate_callable_param_count(func, 0)
5548
- # make sure there is no return notation
5549
- signature = inspect.signature(func)
5550
- if signature.return_annotation is not None:
5551
- raise TypeError(f"{func.__name__} must declare return a return type of 'None'")
5548
+ # make sure there is no return annotation or the return is specified as None
5549
+ _, ret_ann = get_types(func)
5550
+ if ret_ann is not None:
5551
+ raise TypeError(f"{func.__name__} must have a return type of 'None', got: {ret_ann}")
5552
5552
 
5553
5553
  def register_preloop_hook(self, func: Callable[[], None]) -> None:
5554
5554
  """Register a function to be called at the beginning of the command loop."""
@@ -5564,11 +5564,13 @@ class Cmd(cmd.Cmd):
5564
5564
  def _validate_postparsing_callable(cls, func: Callable[[plugin.PostparsingData], plugin.PostparsingData]) -> None:
5565
5565
  """Check parameter and return types for postparsing hooks."""
5566
5566
  cls._validate_callable_param_count(cast(Callable[..., Any], func), 1)
5567
- signature = inspect.signature(func)
5568
- _, param = next(iter(signature.parameters.items()))
5569
- if param.annotation != plugin.PostparsingData:
5567
+ type_hints, ret_ann = get_types(func)
5568
+ if not type_hints:
5569
+ raise TypeError(f"{func.__name__} parameter is missing a type hint, expected: 'cmd2.plugin.PostparsingData'")
5570
+ par_ann = next(iter(type_hints.values()))
5571
+ if par_ann != plugin.PostparsingData:
5570
5572
  raise TypeError(f"{func.__name__} must have one parameter declared with type 'cmd2.plugin.PostparsingData'")
5571
- if signature.return_annotation != plugin.PostparsingData:
5573
+ if ret_ann != plugin.PostparsingData:
5572
5574
  raise TypeError(f"{func.__name__} must declare return a return type of 'cmd2.plugin.PostparsingData'")
5573
5575
 
5574
5576
  def register_postparsing_hook(self, func: Callable[[plugin.PostparsingData], plugin.PostparsingData]) -> None:
@@ -5583,21 +5585,21 @@ class Cmd(cmd.Cmd):
5583
5585
  cls, func: Callable[[CommandDataType], CommandDataType], data_type: type[CommandDataType]
5584
5586
  ) -> None:
5585
5587
  """Check parameter and return types for pre and post command hooks."""
5586
- signature = inspect.signature(func)
5587
5588
  # validate that the callable has the right number of parameters
5588
5589
  cls._validate_callable_param_count(cast(Callable[..., Any], func), 1)
5590
+
5591
+ type_hints, ret_ann = get_types(func)
5592
+ if not type_hints:
5593
+ raise TypeError(f"{func.__name__} parameter is missing a type hint, expected: {data_type}")
5594
+ param_name, par_ann = next(iter(type_hints.items()))
5589
5595
  # validate the parameter has the right annotation
5590
- paramname = next(iter(signature.parameters.keys()))
5591
- param = signature.parameters[paramname]
5592
- if param.annotation != data_type:
5593
- raise TypeError(f'argument 1 of {func.__name__} has incompatible type {param.annotation}, expected {data_type}')
5596
+ if par_ann != data_type:
5597
+ raise TypeError(f'argument 1 of {func.__name__} has incompatible type {par_ann}, expected {data_type}')
5594
5598
  # validate the return value has the right annotation
5595
- if signature.return_annotation == signature.empty:
5599
+ if ret_ann is None:
5596
5600
  raise TypeError(f'{func.__name__} does not have a declared return type, expected {data_type}')
5597
- if signature.return_annotation != data_type:
5598
- raise TypeError(
5599
- f'{func.__name__} has incompatible return type {signature.return_annotation}, expected {data_type}'
5600
- )
5601
+ if ret_ann != data_type:
5602
+ raise TypeError(f'{func.__name__} has incompatible return type {ret_ann}, expected {data_type}')
5601
5603
 
5602
5604
  def register_precmd_hook(self, func: Callable[[plugin.PrecommandData], plugin.PrecommandData]) -> None:
5603
5605
  """Register a hook to be called before the command function."""
@@ -5615,12 +5617,16 @@ class Cmd(cmd.Cmd):
5615
5617
  ) -> None:
5616
5618
  """Check parameter and return types for command finalization hooks."""
5617
5619
  cls._validate_callable_param_count(func, 1)
5618
- signature = inspect.signature(func)
5619
- _, param = next(iter(signature.parameters.items()))
5620
- if param.annotation != plugin.CommandFinalizationData:
5621
- raise TypeError(f"{func.__name__} must have one parameter declared with type {plugin.CommandFinalizationData}")
5622
- if signature.return_annotation != plugin.CommandFinalizationData:
5623
- raise TypeError("{func.__name__} must declare return a return type of {plugin.CommandFinalizationData}")
5620
+ type_hints, ret_ann = get_types(func)
5621
+ if not type_hints:
5622
+ raise TypeError(f"{func.__name__} parameter is missing a type hint, expected: {plugin.CommandFinalizationData}")
5623
+ _, par_ann = next(iter(type_hints.items()))
5624
+ if par_ann != plugin.CommandFinalizationData:
5625
+ raise TypeError(
5626
+ f"{func.__name__} must have one parameter declared with type {plugin.CommandFinalizationData}, got: {par_ann}"
5627
+ )
5628
+ if ret_ann != plugin.CommandFinalizationData:
5629
+ raise TypeError(f"{func.__name__} must declare return a return type of {plugin.CommandFinalizationData}")
5624
5630
 
5625
5631
  def register_cmdfinalization_hook(
5626
5632
  self, func: Callable[[plugin.CommandFinalizationData], plugin.CommandFinalizationData]
@@ -14,29 +14,12 @@ import sys
14
14
  import threading
15
15
  import unicodedata
16
16
  from collections.abc import Callable, Iterable
17
- from difflib import (
18
- SequenceMatcher,
19
- )
20
- from enum import (
21
- Enum,
22
- )
23
- from typing import (
24
- TYPE_CHECKING,
25
- Any,
26
- Optional,
27
- TextIO,
28
- TypeVar,
29
- Union,
30
- cast,
31
- )
32
-
33
- from . import (
34
- constants,
35
- )
36
- from .argparse_custom import (
37
- ChoicesProviderFunc,
38
- CompleterFunc,
39
- )
17
+ from difflib import SequenceMatcher
18
+ from enum import Enum
19
+ from typing import TYPE_CHECKING, Any, Optional, TextIO, TypeVar, Union, cast, get_type_hints
20
+
21
+ from . import constants
22
+ from .argparse_custom import ChoicesProviderFunc, CompleterFunc
40
23
 
41
24
  if TYPE_CHECKING: # pragma: no cover
42
25
  import cmd2 # noqa: F401
@@ -1261,3 +1244,27 @@ def suggest_similar(
1261
1244
  best_simil = simil
1262
1245
  proposed_command = each
1263
1246
  return proposed_command
1247
+
1248
+
1249
+ def get_types(func_or_method: Callable[..., Any]) -> tuple[dict[str, Any], Any]:
1250
+ """Use typing.get_type_hints() to extract type hints for parameters and return value.
1251
+
1252
+ This exists because the inspect module doesn't have a safe way of doing this that works
1253
+ both with and without importing annotations from __future__ until Python 3.10.
1254
+
1255
+ TODO: Once cmd2 only supports Python 3.10+, change to use inspect.get_annotations(eval_str=True)
1256
+
1257
+ :param func_or_method: Function or method to return the type hints for
1258
+ :return tuple with first element being dictionary mapping param names to type hints
1259
+ and second element being return type hint, unspecified, returns None
1260
+ """
1261
+ try:
1262
+ type_hints = get_type_hints(func_or_method) # Get dictionary of type hints
1263
+ except TypeError as exc:
1264
+ raise ValueError("Argument passed to get_types should be a function or method") from exc
1265
+ ret_ann = type_hints.pop('return', None) # Pop off the return annotation if it exists
1266
+ if inspect.ismethod(func_or_method):
1267
+ type_hints.pop('self', None) # Pop off `self` hint for methods
1268
+ if ret_ann is type(None):
1269
+ ret_ann = None # Simplify logic to just return None instead of NoneType
1270
+ return type_hints, ret_ann
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmd2
3
- Version: 2.6.0
3
+ Version: 2.6.1
4
4
  Summary: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python
5
5
  Author: cmd2 Contributors
6
6
  License: The MIT License (MIT)
@@ -309,6 +309,7 @@ tests/test_argparse_completer.py
309
309
  tests/test_argparse_custom.py
310
310
  tests/test_cmd2.py
311
311
  tests/test_completion.py
312
+ tests/test_future_annotations.py
312
313
  tests/test_history.py
313
314
  tests/test_parsing.py
314
315
  tests/test_plugin.py
@@ -147,9 +147,7 @@ exclude = [
147
147
  # Same as Black.
148
148
  line-length = 127
149
149
  indent-width = 4
150
-
151
- # Assume Python 3.13
152
- target-version = "py313"
150
+ target-version = "py39" # Minimum supported version of Python
153
151
  output-format = "full"
154
152
 
155
153
  [tool.ruff.lint]
@@ -235,6 +233,7 @@ ignore = [
235
233
  "E111", # Conflicts with ruff format
236
234
  "E114", # Conflicts with ruff format
237
235
  "E117", # Conflicts with ruff format
236
+ "FA100", # Adding from __future__ import annotations screws up cmd2 because of how use inspect to validate type annotations at runtime
238
237
  "ISC002", # Conflicts with ruff format
239
238
  "Q000", # Conflicts with ruff format
240
239
  "Q001", # Conflicts with ruff format
@@ -258,36 +257,26 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
258
257
 
259
258
  mccabe.max-complexity = 49
260
259
 
261
- per-file-ignores."cmd2/__init__.py" = [
262
- "E402", # Module level import not at top of file
263
- "F401", # Unused import
264
- ]
260
+ [tool.ruff.lint.per-file-ignores]
261
+ # Module level import not at top of file and unused import
262
+ "cmd2/__init__.py" = ["E402", "F401"]
265
263
 
266
- per-file-ignores."cmd2/argparse_custom.py" = [
267
- "B010", # Do not call setattr with a constant attribute value
268
- ]
264
+ # Do not call setattr with constant attribute value
265
+ "cmd2/argparse_custom.py" = ["B010"]
269
266
 
270
- per-file-ignores."examples/*.py" = [
267
+ # Ignore various varnings in examples/ directory
268
+ "examples/*.py" = [
271
269
  "ANN", # Ignore all type annotation rules in examples folder
272
270
  "D", # Ignore all pydocstyle rules in examples folder
273
271
  "INP001", # Module is part of an implicit namespace
274
272
  "PLW2901", # loop variable overwritten inside loop
275
273
  "S", # Ignore all Security rules in examples folder
276
274
  ]
275
+ "examples/scripts/*.py" = ["F821"] # Undefined name `app`
276
+ "plugins/*.py" = ["INP001"] # Module is part of an implicit namespace
277
277
 
278
- per-file-ignores."examples/scripts/*.py" = [
279
- "F821", # Undefined name `app`
280
- ]
281
-
282
- per-file-ignores."plugins/*.py" = [
283
- "ANN", # Ignore all type annotation rules in test folders
284
- "D", # Ignore all pydocstyle rules in test folders
285
- "INP001", # Module is part of an implicit namespace
286
- "S", # Ignore all Security rules in test folders
287
- "SLF", # Ignore all warnings about private or protected member access in test folders
288
- ]
289
-
290
- per-file-ignores."tests/*.py" = [
278
+ # Ingore various rulesets in test and plugins directories
279
+ "{plugins,tests,tests_isolated}/*.py" = [
291
280
  "ANN", # Ignore all type annotation rules in test folders
292
281
  "ARG", # Ignore all unused argument warnings in test folders
293
282
  "D", # Ignore all pydocstyle rules in test folders
@@ -295,19 +284,8 @@ per-file-ignores."tests/*.py" = [
295
284
  "S", # Ignore all Security rules in test folders
296
285
  "SLF", # Ignore all warnings about private or protected member access in test folders
297
286
  ]
298
-
299
- per-file-ignores."tests/pyscript/*.py" = [
300
- "F821", # Undefined name `app`
301
- "INP001", # Module is part of an implicit namespace
302
- ]
303
-
304
- per-file-ignores."tests_isolated/*.py" = [
305
- "ANN", # Ignore all type annotation rules in test folders
306
- "ARG", # Ignore all unused argument warnings in test folders
307
- "D", # Ignore all pydocstyle rules in test folders
308
- "S", # Ignore all Security rules in test folders
309
- "SLF", # Ignore all warnings about private or protected member access in test folders
310
- ]
287
+ # Undefined name `app` and module is part of an implicit namespace
288
+ "tests/pyscript/*.py" = ["F821", "INP001"]
311
289
 
312
290
  [tool.ruff.format]
313
291
  # Like Black, use double quotes for strings.
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ import cmd2
4
+
5
+ from .conftest import normalize, run_cmd
6
+
7
+
8
+ def test_hooks_work_with_future_annotations() -> None:
9
+ class HookApp(cmd2.Cmd):
10
+ def __init__(self, *args, **kwargs) -> None:
11
+ super().__init__(*args, **kwargs)
12
+ self.register_cmdfinalization_hook(self.hook)
13
+
14
+ def hook(self: cmd2.Cmd, data: cmd2.plugin.CommandFinalizationData) -> cmd2.plugin.CommandFinalizationData:
15
+ if self.in_script():
16
+ self.poutput("WE ARE IN SCRIPT")
17
+ return data
18
+
19
+ hook_app = HookApp()
20
+ out, err = run_cmd(hook_app, '')
21
+ expected = normalize('')
22
+ assert out == expected
@@ -892,3 +892,44 @@ def test_similarity_overwrite_function() -> None:
892
892
 
893
893
  suggested_command = cu.suggest_similar("test", ["test"], similarity_function_to_use=custom_similarity_function)
894
894
  assert suggested_command is None
895
+
896
+
897
+ def test_get_types_invalid_input() -> None:
898
+ x = 1
899
+ with pytest.raises(ValueError, match="Argument passed to get_types should be a function or method"):
900
+ cu.get_types(x)
901
+
902
+
903
+ def test_get_types_empty() -> None:
904
+ def a(b):
905
+ print(b)
906
+
907
+ param_ann, ret_ann = cu.get_types(a)
908
+ assert ret_ann is None
909
+ assert param_ann == {}
910
+
911
+
912
+ def test_get_types_non_empty() -> None:
913
+ def foo(x: int) -> str:
914
+ return f"{x * x}"
915
+
916
+ param_ann, ret_ann = cu.get_types(foo)
917
+ assert ret_ann is str
918
+ param_name, param_value = next(iter(param_ann.items()))
919
+ assert param_name == 'x'
920
+ assert param_value is int
921
+
922
+
923
+ def test_get_types_method() -> None:
924
+ class Foo:
925
+ def bar(self, x: bool) -> None:
926
+ print(x)
927
+
928
+ f = Foo()
929
+
930
+ param_ann, ret_ann = cu.get_types(f.bar)
931
+ assert ret_ann is None
932
+ assert len(param_ann) == 1
933
+ param_name, param_value = next(iter(param_ann.items()))
934
+ assert param_name == 'x'
935
+ assert param_value is bool
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes