diff options
author | Todd Leonhardt <todd.leonhardt@gmail.com> | 2018-03-20 16:13:50 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-20 16:13:50 -0400 |
commit | 328b408fa755a17268c33f0fae0301bb85d1f102 (patch) | |
tree | 2da9801764272b01f80c3b27f1d797ebd15c15a9 | |
parent | 627360cfc71995af939569b2aee9dbc8141544d0 (diff) | |
parent | 0075c6d6b324c934e7cbb694a99e5dc7ab5697a6 (diff) | |
download | cmd2-git-328b408fa755a17268c33f0fae0301bb85d1f102.tar.gz |
Merge pull request #323 from python-cmd2/sigint_handler
Added default sigint handler
-rwxr-xr-x | cmd2.py | 25 | ||||
-rwxr-xr-x | examples/subcommands.py | 6 | ||||
-rw-r--r-- | tests/test_cmd2.py | 2 |
3 files changed, 29 insertions, 4 deletions
@@ -36,6 +36,7 @@ import os import platform import re import shlex +import signal import six import sys import tempfile @@ -1051,7 +1052,7 @@ class Cmd(cmd.Cmd): allow_cli_args = True # Should arguments passed on the command-line be processed as commands? allow_redirection = True # Should output redirection and pipes be allowed default_to_shell = False # Attempt to run unrecognized commands as shell commands - quit_on_sigint = True # Quit the loop on interrupt instead of just resetting prompt + quit_on_sigint = False # Quit the loop on interrupt instead of just resetting prompt reserved_words = [] # Attributes which ARE dynamically settable at runtime @@ -1480,6 +1481,28 @@ class Cmd(cmd.Cmd): completions.sort() return completions + # noinspection PyUnusedLocal + def sigint_handler(self, signum, frame): + """Signal handler for SIGINTs which typically come from Ctrl-C events. + + If you need custom SIGINT behavior, then override this function. + + :param signum: int - signal number + :param frame + """ + # Save copy of pipe_proc since it could theoretically change while this is running + pipe_proc = self.pipe_proc + if pipe_proc is not None: + pipe_proc.terminate() + + # Re-raise a KeyboardInterrupt so other parts of the code can catch it + raise KeyboardInterrupt("Got a keyboard interrupt") + + def preloop(self): + """Hook method executed once when the cmdloop() method is called.""" + # Register a default SIGINT signal handler for Ctrl+C + signal.signal(signal.SIGINT, self.sigint_handler) + def precmd(self, statement): """Hook method executed just before the command is processed by ``onecmd()`` and after adding it to the history. diff --git a/examples/subcommands.py b/examples/subcommands.py index fa99f6b4..2a7e0afa 100755 --- a/examples/subcommands.py +++ b/examples/subcommands.py @@ -63,11 +63,11 @@ class SubcommandsExample(cmd2.Cmd): @with_argparser(base_parser) def do_base(self, args): """Base command help""" - try: + if args.func is not None: # Call whatever subcommand function was selected args.func(self, args) - except AttributeError: - # No subcommand was provided, so as called + else: + # No subcommand was provided, so call help self.do_help('base') # functools.partialmethod was added in Python 3.4 diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index d69bf343..20d477ba 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -915,6 +915,8 @@ def say_app(): return app def test_interrupt_quit(say_app): + say_app.quit_on_sigint = True + # Mock out the input call so we don't actually wait for a user's response on stdin m = mock.MagicMock(name='input') m.side_effect = ['say hello', KeyboardInterrupt(), 'say goodbye', 'eof'] |