summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2018-03-20 16:13:50 -0400
committerGitHub <noreply@github.com>2018-03-20 16:13:50 -0400
commit328b408fa755a17268c33f0fae0301bb85d1f102 (patch)
tree2da9801764272b01f80c3b27f1d797ebd15c15a9
parent627360cfc71995af939569b2aee9dbc8141544d0 (diff)
parent0075c6d6b324c934e7cbb694a99e5dc7ab5697a6 (diff)
downloadcmd2-git-328b408fa755a17268c33f0fae0301bb85d1f102.tar.gz
Merge pull request #323 from python-cmd2/sigint_handler
Added default sigint handler
-rwxr-xr-xcmd2.py25
-rwxr-xr-xexamples/subcommands.py6
-rw-r--r--tests/test_cmd2.py2
3 files changed, 29 insertions, 4 deletions
diff --git a/cmd2.py b/cmd2.py
index 9b13ff92..9f026571 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -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']