diff options
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | cmd2/cmd2.py | 62 | ||||
-rw-r--r-- | docs/hooks.rst | 51 | ||||
-rw-r--r-- | docs/integrating.rst | 29 | ||||
-rw-r--r-- | tests/test_cmd2.py | 7 | ||||
-rw-r--r-- | tests/test_plugin.py | 5 |
6 files changed, 42 insertions, 117 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 25c31e68..b7dbde48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ * Never - output methods strip all ANSI escape sequences * Deprecations * Deprecated the builtin ``cmd2`` suport for colors including ``Cmd.colorize()`` and ``Cmd._colorcodes`` +* 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 82ffb29e..dcdde0f6 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1675,58 +1675,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. @@ -1766,9 +1714,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 @@ -1833,9 +1778,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) @@ -1889,9 +1832,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 diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 91fb8b39..92832e2f 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -989,10 +989,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' |