diff options
-rw-r--r-- | cmd2/cmd2.py | 6 | ||||
-rw-r--r-- | cmd2/plugin.py | 21 | ||||
-rw-r--r-- | docs/hooks.rst | 14 | ||||
-rw-r--r-- | tests/test_plugin.py | 5 |
4 files changed, 40 insertions, 6 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 63ad1ea2..69d6224e 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -45,6 +45,7 @@ import pyperclip from . import constants from . import utils +from . import plugin from .parsing import StatementParser, Statement # Set up readline @@ -1704,7 +1705,10 @@ class Cmd(cmd.Cmd): # precommand hooks for func in self._precmd_hooks: - statement = func(statement) + data = plugin.PrecommandData(statement) + result = func(data) + statement = result.statement + # call precmd() for compatibility with cmd.Cmd statement = self.precmd(statement) # go run the command function diff --git a/cmd2/plugin.py b/cmd2/plugin.py new file mode 100644 index 00000000..47f4a514 --- /dev/null +++ b/cmd2/plugin.py @@ -0,0 +1,21 @@ +# +# coding=utf-8 +"""Classes for the cmd2 plugin system""" +import attr + +@attr.s +class PostparsingData(): + stop = attr.ib() + statement = attr.ib() + +@attr.s +class PrecommandData(): + statement = attr.ib() + +@attr.s +class PostcommandData(): + stop = attr.ib(default=False) + +@attr.s +class CommandFinalizationData(): + stop = attr.ib(default=False) diff --git a/docs/hooks.rst b/docs/hooks.rst index ed1d9070..47909abf 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -204,8 +204,7 @@ Here's how to define a register a postcommand hook:: super().__init__(*args, **kwargs) self.register_postcmd_hook(self.myhookmethod) - def myhookmethod(self, statement): - stop = False + def myhookmethod(self, stop, statement): return stop Your hook will be passed the statement object, which describes the command which @@ -224,6 +223,15 @@ subsequent postcommand hooks will still be called, as will the command finalization hooks, but once those hooks have all been called, the application will terminate. +Any postcommand hook can change the value of the ``stop`` parameter before +returning it, and the modified value will be passed to the next postcommand +hook. The value returned by the final postcommand hook will be passed to the +command finalization hooks, which may further modify the value. If your hook +blindly returns ``False``, a prior hook's requst to exit the application will +not be honored. It's best to return the value you were passed unless you have a +compelling reason to do otherwise. + + Command Finalization Hooks ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +252,7 @@ terminate, the value of the ``stop`` parameter passed to the first command finalization hook will be ``True``. Any command finalization hook can change the value of the ``stop`` parameter before returning it, and the modified value will be passed to the next command finalization hook. The value returned by the final -command finalization hook will determin whether the application terminates or +command finalization hook will determine whether the application terminates or not. This approach to command finalization hooks can be powerful, but it can also diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 2bebd4af..133284a0 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -11,6 +11,7 @@ from typing import Tuple import pytest import cmd2 +from cmd2 import plugin from .conftest import StdOut @@ -57,10 +58,10 @@ class Plugin: self.called_precmd += 1 return statement - def precmd_hook(self, statement: cmd2.Statement) -> cmd2.Statement: + def precmd_hook(self, data: plugin.PrecommandData) -> plugin.PrecommandData: "A precommand hook" self.called_precmd += 1 - return statement + return data def precmd_hook_emptystatement(self, statement: cmd2.Statement) -> cmd2.Statement: "A precommand hook which raises an EmptyStatement exception" |