summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/cmd2.py6
-rw-r--r--cmd2/plugin.py21
-rw-r--r--docs/hooks.rst14
-rw-r--r--tests/test_plugin.py5
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"