Repository: python-cmd2/cmd2
Pull request #540 (2018-09-25 04:12:35)

Deleted the hook methods which were deprecated in the previous release
The following methods of cmd2.Cmd have been deleted:
- preparse
- postparsing_precmd
- postparsing_postcmd

The new application lifecycle hook framework allows for registering callbacks to be called at various points in the application lifecycle and is more powerful and flexible than the old system of fixed hook methods.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6bf3c961..c03a2323 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,11 @@
     for formatting help/description text
     * Aliases are now sorted alphabetically
     * The **set** command now tab-completes settable parameter names
+* Deletions
+    * The ``preparse``, ``postparsing_precmd``, and ``postparsing_postcmd`` methods *deprecated* in the previous release 
+    have been deleted
+        * The new application lifecycle hook system allows for registration of callbacks to be called at various points
+        in the lifecycle and is more powerful and flexible than the previous system
     
 ## 0.9.4 (August 21, 2018)
 * Bug Fixes
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 972a2be4..91b84f0d 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -1649,58 +1649,6 @@ class Cmd(cmd.Cmd):
         """
         return statement
 
-    # -----  Methods which are cmd2-specific lifecycle hooks which are not present in cmd -----
-
-    # noinspection PyMethodMayBeStatic
-    def preparse(self, raw: str) -> str:
-        """Hook method executed before user input is parsed.
-
-        WARNING: If it's a multiline command, `preparse()` may not get all the
-        user input. _complete_statement() really does two things: a) parse the
-        user input, and b) accept more input in case it's a multiline command
-        the passed string doesn't have a terminator. `preparse()` is currently
-        called before we know whether it's a multiline command, and before we
-        know whether the user input includes a termination character.
-
-        If you want a reliable pre parsing hook method, register a postparsing
-        hook, modify the user input, and then reparse it.
-
-        :param raw: raw command line input :return: potentially modified raw command line input
-        :return: a potentially modified version of the raw input string
-        """
-        return raw
-
-    # noinspection PyMethodMayBeStatic
-    def postparsing_precmd(self, statement: Statement) -> Tuple[bool, Statement]:
-        """This runs after parsing the command-line, but before anything else; even before adding cmd to history.
-
-        NOTE: This runs before precmd() and prior to any potential output redirection or piping.
-
-        If you wish to fatally fail this command and exit the application entirely, set stop = True.
-
-        If you wish to just fail this command you can do so by raising an exception:
-
-        - raise EmptyStatement - will silently fail and do nothing
-        - raise <AnyOtherException> - will fail and print an error message
-
-        :param statement: the parsed command-line statement as a Statement object
-        :return: (stop, statement) containing a potentially modified version of the statement object
-        """
-        stop = False
-        return stop, statement
-
-    # noinspection PyMethodMayBeStatic
-    def postparsing_postcmd(self, stop: bool) -> bool:
-        """This runs after everything else, including after postcmd().
-
-        It even runs when an empty line is entered.  Thus, if you need to do something like update the prompt due
-        to notifications from a background thread, then this is the method you want to override to do it.
-
-        :param stop: True implies the entire application should exit.
-        :return: True implies the entire application should exit.
-        """
-        return stop
-
     def parseline(self, line: str) -> Tuple[str, str, str]:
         """Parse the line into a command name and a string containing the arguments.
 
@@ -1740,9 +1688,6 @@ class Cmd(cmd.Cmd):
                 data = func(data)
                 if data.stop:
                     break
-            # postparsing_precmd is deprecated
-            if not data.stop:
-                (data.stop, data.statement) = self.postparsing_precmd(data.statement)
             # unpack the data object
             statement = data.statement
             stop = data.stop
@@ -1807,9 +1752,7 @@ class Cmd(cmd.Cmd):
                 data = func(data)
             # retrieve the final value of stop, ignoring any
             # modifications to the statement
-            stop = data.stop
-            # postparsing_postcmd is deprecated
-            return self.postparsing_postcmd(stop)
+            return data.stop
         except Exception as ex:
             self.perror(ex)
 
@@ -1863,9 +1806,6 @@ class Cmd(cmd.Cmd):
         pipe runs out. We can't refactor it because we need to retain
         backwards compatibility with the standard library version of cmd.
         """
-        # preparse() is deprecated, use self.register_postparsing_hook() instead
-        line = self.preparse(line)
-
         while True:
             try:
                 statement = self.statement_parser.parse(line)
diff --git a/docs/hooks.rst b/docs/hooks.rst
index 2a5d7b5f..1696d365 100644
--- a/docs/hooks.rst
+++ b/docs/hooks.rst
@@ -76,24 +76,21 @@ Command Processing Loop
 When you call `.cmdloop()`, the following sequence of events are repeated until
 the application exits:
 
-1. Output the prompt
-2. Accept user input
-3. Call `preparse()` - for backwards compatibility with prior releases of cmd2, now deprecated
-4. Parse user input into `Statement` object
-5. Call methods registered with `register_postparsing_hook()`
-6. Call `postparsing_precmd()` - for backwards compatibility with prior releases of cmd2, now deprecated
-7. Redirect output, if user asked for it and it's allowed
-8. Start timer
-9. Call methods registered with `register_precmd_hook()`
-10. Call `precmd()` - for backwards compatibility with ``cmd.Cmd``
-11. Add statement to history
-12. Call `do_command` method
-13. Call methods registered with `register_postcmd_hook()`
-14. Call `postcmd(stop, statement)` - for backwards compatibility with ``cmd.Cmd``
-15. Stop timer and display the elapsed time
-16. Stop redirecting output if it was redirected
-17. Call methods registered with `register_cmdfinalization_hook()`
-18. Call `postparsing_postcmd()` - for backwards compatibility - deprecated
+#. Output the prompt
+#. Accept user input
+#. Parse user input into `Statement` object
+#. Call methods registered with `register_postparsing_hook()`
+#. Redirect output, if user asked for it and it's allowed
+#. Start timer
+#. Call methods registered with `register_precmd_hook()`
+#. Call `precmd()` - for backwards compatibility with ``cmd.Cmd``
+#. Add statement to history
+#. Call `do_command` method
+#. Call methods registered with `register_postcmd_hook()`
+#. Call `postcmd(stop, statement)` - for backwards compatibility with ``cmd.Cmd``
+#. Stop timer and display the elapsed time
+#. Stop redirecting output if it was redirected
+#. Call methods registered with `register_cmdfinalization_hook()`
 
 By registering hook methods, steps 4, 8, 12, and 16 allow you to run code
 during, and control the flow of the command processing loop. Be aware that
@@ -305,21 +302,3 @@ If any command finalization hook raises an exception, no more command
 finalization hooks will be called. If the last hook to return a value returned
 ``True``, then the exception will be rendered, and the application will
 terminate.
-
-Deprecated Command Processing Hooks
------------------------------------
-
-Inside the main loop, every time the user hits <Enter> the line is processed by the ``onecmd_plus_hooks`` method.
-
-.. automethod:: cmd2.cmd2.Cmd.onecmd_plus_hooks
-
-As the ``onecmd_plus_hooks`` name implies, there are a number of *hook* methods that can be defined in order to inject
-application-specific behavior at various points during the processing of a line of text entered by the user.  ``cmd2``
-increases the 2 hooks provided by ``cmd`` (**precmd** and **postcmd**) to 6 for greater flexibility.  Here are
-the various hook methods, presented in chronological order starting with the ones called earliest in the process.
-
-.. automethod:: cmd2.cmd2.Cmd.preparse
-
-.. automethod:: cmd2.cmd2.Cmd.postparsing_precmd
-
-.. automethod:: cmd2.cmd2.Cmd.postparsing_postcmd
diff --git a/docs/integrating.rst b/docs/integrating.rst
index 8f605e06..a8377fdb 100644
--- a/docs/integrating.rst
+++ b/docs/integrating.rst
@@ -135,22 +135,19 @@ script file.
 The **onecmd_plus_hooks()** method will do the following to execute a single
 ``cmd2`` command in a normal fashion:
 
-1. Call `preparse()` - for backwards compatibility with prior releases of cmd2, now deprecated
-2. Parse user input into `Statement` object
-3. Call methods registered with `register_postparsing_hook()`
-4. Call `postparsing_precmd()` - for backwards compatibility with prior releases of cmd2, now deprecated
-5. Redirect output, if user asked for it and it's allowed
-6. Start timer
-7. Call methods registered with `register_precmd_hook()`
-8. Call `precmd()` - for backwards compatibility with ``cmd.Cmd``
-9. Add statement to history
-10. Call `do_command` method
-11. Call methods registered with `register_postcmd_hook()`
-12. Call `postcmd(stop, statement)` - for backwards compatibility with ``cmd.Cmd``
-13. Stop timer and display the elapsed time
-14. Stop redirecting output if it was redirected
-15. Call methods registered with `register_cmdfinalization_hook()`
-16. Call `postparsing_postcmd()` - for backwards compatibility - deprecated
+#. Parse user input into `Statement` object
+#. Call methods registered with `register_postparsing_hook()`
+#. Redirect output, if user asked for it and it's allowed
+#. Start timer
+#. Call methods registered with `register_precmd_hook()`
+#. Call `precmd()` - for backwards compatibility with ``cmd.Cmd``
+#. Add statement to history
+#. Call `do_command` method
+#. Call methods registered with `register_postcmd_hook()`
+#. Call `postcmd(stop, statement)` - for backwards compatibility with ``cmd.Cmd``
+#. Stop timer and display the elapsed time
+#. Stop redirecting output if it was redirected
+#. Call methods registered with `register_cmdfinalization_hook()`
 
 Running in this fashion enables the ability to integrate with an external event
 loop.  However, how to integrate with any specific event loop is beyond the


Test patch:
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 99c30af4..17c19f2a 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -993,10 +993,13 @@ def test_cmdloop_without_rawinput():
 class HookFailureApp(cmd2.Cmd):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
+        # register a postparsing hook method
+        self.register_postparsing_hook(self.postparsing_precmd)
 
-    def postparsing_precmd(self, statement):
+    def postparsing_precmd(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
         """Simulate precmd hook failure."""
-        return True, statement
+        data.stop = True
+        return data
 
 @pytest.fixture
 def hook_failure():
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index 20f2f32c..81dd7683 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -51,10 +51,10 @@ class Plugin:
     # preparse hook
     #
     ###
-    def preparse(self, line: str) -> str:
+    def preparse(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
         """Preparsing hook"""
         self.called_preparse += 1
-        return line
+        return data
 
     ###
     #
@@ -322,6 +322,7 @@ def test_postloop_hooks(capsys):
 ###
 def test_preparse(capsys):
     app = PluggedApp()
+    app.register_postparsing_hook(app.preparse)
     app.onecmd_plus_hooks('say hello')
     out, err = capsys.readouterr()
     assert out == 'hello\n'