codecov[bot]: # [Codecov](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=h1) Report
> Merging [#984](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=desc) into [master](https://codecov.io/gh/python-cmd2/cmd2/commit/a540cfc5373cee2272de6c81be8b6fa8a78c6462?el=desc) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/python-cmd2/cmd2/pull/984/graphs/tree.svg?width=650&height=150&src=pr&token=eks2PUwa6A)](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master     #984   +/-   ##
=======================================
  Coverage   97.83%   97.83%           
=======================================
  Files          22       22           
  Lines        4522     4523    +1     
=======================================
+ Hits         4424     4425    +1     
  Misses         98       98           
```


| [Impacted Files](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [cmd2/cmd2.py](https://codecov.io/gh/python-cmd2/cmd2/pull/984/diff?src=pr&el=tree#diff-Y21kMi9jbWQyLnB5) | `97.21% <100.00%> (+<0.01%)` | :arrow_up: |
| [cmd2/constants.py](https://codecov.io/gh/python-cmd2/cmd2/pull/984/diff?src=pr&el=tree#diff-Y21kMi9jb25zdGFudHMucHk=) | `100.00% <100.00%> (ø)` | |
| [cmd2/decorators.py](https://codecov.io/gh/python-cmd2/cmd2/pull/984/diff?src=pr&el=tree#diff-Y21kMi9kZWNvcmF0b3JzLnB5) | `97.19% <100.00%> (-0.03%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=footer). Last update [a540cfc...ac1639e](https://codecov.io/gh/python-cmd2/cmd2/pull/984?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 161a058d..f2ba2710 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.3.5 (TBD)
+* Bug Fixes
+    * Fixed `RecursionError` when printing an `argparse.Namespace` caused by custom attribute cmd2 was adding
+* Enhancements
+    * Added `get_statement()` function to `argparse.Namespace` which returns `__statement__` attribute
+
 ## 1.3.4 (August 20, 2020)
 * Bug Fixes
     * Fixed `AttributeError` when `CommandSet` that uses `as_subcommand_to` decorator is loaded during
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index da576805..bc6691f6 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -663,7 +663,9 @@ class Cmd(cmd.Cmd):
                 raise CommandSetRegistrationError('Could not find argparser for command "{}" needed by subcommand: {}'
                                                   .format(command_name, str(method)))
 
-            subcmd_parser.set_defaults(cmd2_handler=method)
+            # Set the subcommand handler function
+            defaults = {constants.NS_ATTR_SUBCMD_HANDLER: method}
+            subcmd_parser.set_defaults(**defaults)
 
             def find_subcommand(action: argparse.ArgumentParser, subcmd_names: List[str]) -> argparse.ArgumentParser:
                 if not subcmd_names:
diff --git a/cmd2/constants.py b/cmd2/constants.py
index 9eaa9957..037a7cab 100644
--- a/cmd2/constants.py
+++ b/cmd2/constants.py
@@ -37,10 +37,6 @@ HELP_FUNC_PREFIX = 'help_'
 # All command completer functions start with this
 COMPLETER_FUNC_PREFIX = 'complete_'
 
-##############################################################################
-# The following are optional attributes added to do_* command functions
-##############################################################################
-
 # The custom help category a command belongs to
 CMD_ATTR_HELP_CATEGORY = 'help_category'
 
@@ -50,9 +46,6 @@ CMD_ATTR_ARGPARSER = 'argparser'
 # Whether or not tokens are unquoted before sending to argparse
 CMD_ATTR_PRESERVE_QUOTES = 'preserve_quotes'
 
-# optional attribute
-SUBCMD_HANDLER = 'cmd2_handler'
-
 # subcommand attributes for the base command name and the subcommand name
 SUBCMD_ATTR_COMMAND = 'parent_command'
 SUBCMD_ATTR_NAME = 'subcommand_name'
@@ -60,3 +53,7 @@ SUBCMD_ATTR_ADD_PARSER_KWARGS = 'subcommand_add_parser_kwargs'
 
 # arpparse attribute linking to command set instance
 PARSER_ATTR_COMMANDSET = 'command_set'
+
+# custom attributes added to argparse Namespaces
+NS_ATTR_SUBCMD_HANDLER = '__subcmd_handler__'
+NS_ATTR_STATEMENT = '__statement__'
diff --git a/cmd2/decorators.py b/cmd2/decorators.py
index 689f29c5..ccbbd832 100644
--- a/cmd2/decorators.py
+++ b/cmd2/decorators.py
@@ -1,7 +1,6 @@
 # coding=utf-8
 """Decorators for ``cmd2`` commands"""
 import argparse
-import types
 from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
 
 from . import constants
@@ -190,6 +189,7 @@ def with_argparser_and_unknown_args(parser: argparse.ArgumentParser, *,
              of unknown argument strings. A member called ``__statement__`` is added to the
              ``Namespace`` to provide command functions access to the :class:`cmd2.Statement`
              object. This can be useful if the command function needs to know the command line.
+             ``__statement__`` can also be retrieved by calling ``get_statement()`` on the ``Namespace``.
 
     :Example:
 
@@ -228,6 +228,7 @@ def with_argparser(parser: argparse.ArgumentParser, *,
     :return: function that gets passed the argparse-parsed args in a Namespace
              A member called __statement__ is added to the Namespace to provide command functions access to the
              Statement object. This can be useful if the command function needs to know the command line.
+             ``__statement__`` can also be retrieved by calling ``get_statement()`` on the ``Namespace``.
 
     :Example:
 
@@ -297,12 +298,13 @@ def with_argparser(parser: argparse.ArgumentParser, *,
             except SystemExit:
                 raise Cmd2ArgparseError
             else:
-                setattr(ns, '__statement__', statement)
+                # Add statement to Namespace and a getter function for it
+                setattr(ns, constants.NS_ATTR_STATEMENT, statement)
+                setattr(ns, 'get_statement', lambda: statement)
 
-                def get_handler(ns_self: argparse.Namespace) -> Optional[Callable]:
-                    return getattr(ns_self, constants.SUBCMD_HANDLER, None)
-
-                setattr(ns, 'get_handler', types.MethodType(get_handler, ns))
+                # Add getter function for subcmd handler, which can be None
+                subcmd_handler = getattr(ns, constants.NS_ATTR_SUBCMD_HANDLER, None)
+                setattr(ns, 'get_handler', lambda: subcmd_handler)
 
                 args_list = _arg_swap(args, statement, *new_args)
                 return func(*args_list, **kwargs)
diff --git a/docs/features/argument_processing.rst b/docs/features/argument_processing.rst
index 9e65742e..16170239 100644
--- a/docs/features/argument_processing.rst
+++ b/docs/features/argument_processing.rst
@@ -14,7 +14,8 @@ handles the following for you:
 3. Passes the resulting ``argparse.Namespace`` object to your command function.
    The ``Namespace`` includes the ``Statement`` object that was created when
    parsing the command line. It is stored in the ``__statement__`` attribute of
-   the ``Namespace``.
+   the ``Namespace`` and can also be retrieved by calling ``get_statement()``
+   on the ``Namespace``.
 
 4. Adds the usage message from the argument parser to your command.
 
diff --git a/examples/decorator_example.py b/examples/decorator_example.py
index 0f5374ce..5b721da6 100755
--- a/examples/decorator_example.py
+++ b/examples/decorator_example.py
@@ -67,7 +67,7 @@ class CmdLineApp(cmd2.Cmd):
     def do_tag(self, args: argparse.Namespace):
         """create an html tag"""
         # The Namespace always includes the Statement object created when parsing the command line
-        statement = args.__statement__
+        statement = args.get_statement()
 
         self.poutput("The command line you ran was: {}".format(statement.command_and_args))
         self.poutput("It generated this tag:")

RecursionError when printing argparse Namespace
If I call `print(args)` in a do_* command function, I get the following stack trace.

> Traceback (most recent call last):
>   File "/home/user/PycharmProjects/cmd2/cmd2/cmd2.py", line 2021, in onecmd_plus_hooks
>     stop = self.onecmd(statement, add_to_history=add_to_history)
>   File "/home/user/PycharmProjects/cmd2/cmd2/cmd2.py", line 2451, in onecmd
>     stop = func(statement)
>   File "/home/user/PycharmProjects/cmd2/cmd2/decorators.py", line 309, in cmd_wrapper
>     return func(*args_list, **kwargs)
>   File "/home/user/PycharmProjects/cmd2/cmd2/cmd2.py", line 2686, in do_alias
>     print(args)
>   File "/home/user/miniconda3/envs/cmd2/lib/python3.7/argparse.py", line 122, in __repr__
>     arg_strings.append('%s=%r' % (name, value))
>   File "/home/user/miniconda3/envs/cmd2/lib/python3.7/argparse.py", line 122, in __repr__
>     arg_strings.append('%s=%r' % (name, value))
>   File "/home/user/miniconda3/envs/cmd2/lib/python3.7/argparse.py", line 122, in __repr__
>     arg_strings.append('%s=%r' % (name, value))
>   [Previous line repeated 993 more times]
>   File "/home/user/miniconda3/envs/cmd2/lib/python3.7/argparse.py", line 120, in __repr__
>     for name, value in self._get_kwargs():
>   File "/home/user/miniconda3/envs/cmd2/lib/python3.7/argparse.py", line 130, in _get_kwargs
>     return sorted(self.__dict__.items())
> RecursionError: maximum recursion depth exceeded while calling a Python object
> EXCEPTION of type 'RecursionError' occurred with message: 'maximum recursion depth exceeded while calling a Python object'

I've narrowed down the cause to this line in [decorators.py](https://github.com/python-cmd2/cmd2/blob/master/cmd2/decorators.py)
```Python
setattr(ns, 'get_handler', types.MethodType(get_handler, ns))
```
This change fixes it
```Python
setattr(ns, 'get_handler', functools.partial(get_handler, ns))
```
diff --git a/tests/test_argparse.py b/tests/test_argparse.py
index 0d46b15a..9806c9b5 100644
--- a/tests/test_argparse.py
+++ b/tests/test_argparse.py
@@ -290,6 +290,24 @@ class SubcommandApp(cmd2.Cmd):
         func(self, args)
 
 
+    # Add a subcommand using as_subcommand_to decorator
+    has_subcmd_parser = cmd2.Cmd2ArgumentParser(description="Tests as_subcmd_to decorator")
+    has_subcmd_subparsers = has_subcmd_parser.add_subparsers(dest='subcommand', metavar='SUBCOMMAND')
+    has_subcmd_subparsers.required = True
+
+    @cmd2.with_argparser(has_subcmd_parser)
+    def do_test_subcmd_decorator(self, args: argparse.Namespace):
+        handler = args.get_handler()
+        handler(args)
+
+    subcmd_parser = cmd2.Cmd2ArgumentParser(add_help=False, description="The subcommand")
+
+    @cmd2.as_subcommand_to('test_subcmd_decorator', 'subcmd', subcmd_parser, help='the subcommand')
+    def subcmd_func(self, args: argparse.Namespace):
+        # Make sure printing the Namespace works. The way we originally added get_hander()
+        # to it resulted in a RecursionError when printing.
+        print(args)
+
 @pytest.fixture
 def subcommand_app():
     app = SubcommandApp()
@@ -373,6 +391,11 @@ def test_add_another_subcommand(subcommand_app):
     assert new_parser.prog == "base new_sub"
 
 
+def test_subcmd_decorator(subcommand_app):
+    out, err = run_cmd(subcommand_app, 'test_subcmd_decorator subcmd')
+    assert out[0].startswith('Namespace(')
+
+
 def test_unittest_mock():
     from unittest import mock
     from cmd2 import CommandSetRegistrationError
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index e49cbbfc..d40a9b61 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -279,7 +279,7 @@ class PluggedApp(Plugin, cmd2.Cmd):
     @with_argparser(parser)
     def do_argparse_cmd(self, namespace: argparse.Namespace):
         """Repeat back the arguments"""
-        self.poutput(namespace.__statement__)
+        self.poutput(namespace.get_statement())
 
 ###
 #

pip install -e .[dev]
parse_log_pytest
Pipfile
pytest
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
anyio==4.9.0
argcomplete==3.6.1
attrs==25.3.0
babel==2.17.0
backports.tarfile==1.2.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
click==8.1.8
-e git+https://github.com/python-cmd2/cmd2.git@a540cfc5373cee2272de6c81be8b6fa8a78c6462#egg=cmd2
codecov==2.1.13
colorama==0.4.6
colorlog==6.9.0
coverage==7.8.0
cryptography==44.0.2
dependency-groups==1.3.0
distlib==0.3.9
doc8==1.1.2
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
flake8==7.2.0
h11==0.14.0
id==1.5.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
invoke==2.2.0
jaraco.classes==3.4.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jeepney==0.9.0
Jinja2==3.1.6
keyring==25.6.0
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mccabe==0.7.0
mdurl==0.1.2
more-itertools==10.6.0
nh3==0.2.21
nox==2025.2.9
packaging==24.2
pbr==6.1.1
pipfile==0.0.2
platformdirs==4.3.7
pluggy==1.5.0
pycodestyle==2.13.0
pycparser==2.22
pyflakes==3.3.1
Pygments==2.19.1
pyperclip==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
pytest-mock==3.14.0
readme_renderer==44.0
requests==2.32.3
requests-toolbelt==1.0.0
restructuredtext_lint==1.4.0
rfc3986==2.0.0
rich==14.0.0
SecretStorage==3.3.3
sniffio==1.3.1
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-autobuild==2024.10.3
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
starlette==0.46.1
stevedore==5.4.1
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tomli==2.2.1
twine==6.1.0
typing_extensions==4.13.0
urllib3==2.3.0
uvicorn==0.34.0
virtualenv==20.29.3
watchfiles==1.0.4
wcwidth==0.2.13
websockets==15.0.1
zipp==3.21.0

name: cmd2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - pipfile=0.0.2=py_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - anyio==4.9.0
      - argcomplete==3.6.1
      - attrs==25.3.0
      - babel==2.17.0
      - backports-tarfile==1.2.0
      - certifi==2025.1.31
      - cffi==1.17.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - codecov==2.1.13
      - colorama==0.4.6
      - colorlog==6.9.0
      - coverage==7.8.0
      - cryptography==44.0.2
      - dependency-groups==1.3.0
      - distlib==0.3.9
      - doc8==1.1.2
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - flake8==7.2.0
      - h11==0.14.0
      - id==1.5.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - invoke==2.2.0
      - jaraco-classes==3.4.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jeepney==0.9.0
      - jinja2==3.1.6
      - keyring==25.6.0
      - markdown-it-py==3.0.0
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - mdurl==0.1.2
      - more-itertools==10.6.0
      - nh3==0.2.21
      - nox==2025.2.9
      - packaging==24.2
      - pbr==6.1.1
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pycparser==2.22
      - pyflakes==3.3.1
      - pygments==2.19.1
      - pyperclip==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - readme-renderer==44.0
      - requests==2.32.3
      - requests-toolbelt==1.0.0
      - restructuredtext-lint==1.4.0
      - rfc3986==2.0.0
      - rich==14.0.0
      - secretstorage==3.3.3
      - sniffio==1.3.1
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-autobuild==2024.10.3
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - starlette==0.46.1
      - stevedore==5.4.1
      - tomli==2.2.1
      - twine==6.1.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - uvicorn==0.34.0
      - virtualenv==20.29.3
      - watchfiles==1.0.4
      - wcwidth==0.2.13
      - websockets==15.0.1
      - zipp==3.21.0
prefix: /opt/conda/envs/cmd2

tests/test_argparse.py::test_subcmd_decorator tests/test_plugin.py::test_cmd2_argparse_exception
tests/test_argparse.py::test_invalid_syntax tests/test_argparse.py::test_argparse_basic_command tests/test_argparse.py::test_argparse_remove_quotes tests/test_argparse.py::test_argparser_kwargs tests/test_argparse.py::test_argparse_preserve_quotes tests/test_argparse.py::test_argparse_custom_namespace tests/test_argparse.py::test_argparse_with_list tests/test_argparse.py::test_argparse_with_list_remove_quotes tests/test_argparse.py::test_argparse_with_list_preserve_quotes tests/test_argparse.py::test_argparse_with_list_custom_namespace tests/test_argparse.py::test_argparse_with_list_and_empty_doc tests/test_argparse.py::test_argparser_correct_args_with_quotes_and_midline_options tests/test_argparse.py::test_argparser_and_unknown_args_kwargs tests/test_argparse.py::test_argparse_quoted_arguments_multiple tests/test_argparse.py::test_argparse_help_docstring tests/test_argparse.py::test_argparse_help_description tests/test_argparse.py::test_argparse_prog tests/test_argparse.py::test_arglist tests/test_argparse.py::test_arglist_kwargs tests/test_argparse.py::test_preservelist tests/test_argparse.py::test_subcommand_foo tests/test_argparse.py::test_subcommand_bar tests/test_argparse.py::test_subcommand_invalid tests/test_argparse.py::test_subcommand_base_help tests/test_argparse.py::test_subcommand_help tests/test_argparse.py::test_subcommand_invalid_help tests/test_argparse.py::test_add_another_subcommand tests/test_argparse.py::test_unittest_mock tests/test_argparse.py::test_pytest_mock_invalid tests/test_argparse.py::test_pytest_mock_valid[spec_param0] tests/test_argparse.py::test_pytest_mock_valid[spec_param1] tests/test_argparse.py::test_pytest_mock_valid[spec_param2] tests/test_plugin.py::test_register_preloop_hook_too_many_parameters tests/test_plugin.py::test_register_preloop_hook_with_return_annotation tests/test_plugin.py::test_preloop_hook tests/test_plugin.py::test_preloop_hooks tests/test_plugin.py::test_register_postloop_hook_too_many_parameters tests/test_plugin.py::test_register_postloop_hook_with_wrong_return_annotation tests/test_plugin.py::test_postloop_hook tests/test_plugin.py::test_postloop_hooks tests/test_plugin.py::test_preparse tests/test_plugin.py::test_postparsing_hook_too_many_parameters tests/test_plugin.py::test_postparsing_hook_undeclared_parameter_annotation tests/test_plugin.py::test_postparsing_hook_wrong_parameter_annotation tests/test_plugin.py::test_postparsing_hook_undeclared_return_annotation tests/test_plugin.py::test_postparsing_hook_wrong_return_annotation tests/test_plugin.py::test_postparsing_hook tests/test_plugin.py::test_postparsing_hook_stop_first tests/test_plugin.py::test_postparsing_hook_stop_second tests/test_plugin.py::test_postparsing_hook_emptystatement_first tests/test_plugin.py::test_postparsing_hook_emptystatement_second tests/test_plugin.py::test_postparsing_hook_exception tests/test_plugin.py::test_register_precmd_hook_parameter_count tests/test_plugin.py::test_register_precmd_hook_no_parameter_annotation tests/test_plugin.py::test_register_precmd_hook_wrong_parameter_annotation tests/test_plugin.py::test_register_precmd_hook_no_return_annotation tests/test_plugin.py::test_register_precmd_hook_wrong_return_annotation tests/test_plugin.py::test_precmd_hook tests/test_plugin.py::test_precmd_hook_emptystatement_first tests/test_plugin.py::test_precmd_hook_emptystatement_second tests/test_plugin.py::test_register_postcmd_hook_parameter_count tests/test_plugin.py::test_register_postcmd_hook_no_parameter_annotation tests/test_plugin.py::test_register_postcmd_hook_wrong_parameter_annotation tests/test_plugin.py::test_register_postcmd_hook_no_return_annotation tests/test_plugin.py::test_register_postcmd_hook_wrong_return_annotation tests/test_plugin.py::test_postcmd tests/test_plugin.py::test_postcmd_exception_first tests/test_plugin.py::test_postcmd_exception_second tests/test_plugin.py::test_register_cmdfinalization_hook_parameter_count tests/test_plugin.py::test_register_cmdfinalization_hook_no_parameter_annotation tests/test_plugin.py::test_register_cmdfinalization_hook_wrong_parameter_annotation tests/test_plugin.py::test_register_cmdfinalization_hook_no_return_annotation tests/test_plugin.py::test_register_cmdfinalization_hook_wrong_return_annotation tests/test_plugin.py::test_cmdfinalization tests/test_plugin.py::test_cmdfinalization_stop_first tests/test_plugin.py::test_cmdfinalization_stop_second tests/test_plugin.py::test_cmdfinalization_hook_exception tests/test_plugin.py::test_cmdfinalization_hook_system_exit tests/test_plugin.py::test_cmdfinalization_hook_keyboard_interrupt tests/test_plugin.py::test_skip_postcmd_hooks
cmd2/cmd2.py cmd2/decorators.py CHANGELOG.md cmd2/constants.py examples/decorator_example.py docs/features/argument_processing.rst
cmd2/cmd2.py cmd2/decorators.py CHANGELOG.md cmd2/constants.py examples/decorator_example.py docs/features/argument_processing.rst