From 9a0989a438ccaa2fee66e869645fb6b4432c13ea 2011-12-06 01:41:00 From: MinRK Date: 2011-12-06 01:41:00 Subject: [PATCH] Adjustment to console signal-handling Do not explicitly interrupt the kernel, because the subprocess already gets the interrupt. Once we properly prevent this, then the interrupt can be restored. Also, the KeyboardInterrupt is still raised if not executing, in order to restore the prompt. In ipkernel, the interrupt is ignored during poll, and restored after the loop exits, to prevent it being swallowed in future code that expects normal sigint behavior. --- diff --git a/IPython/frontend/terminal/console/app.py b/IPython/frontend/terminal/console/app.py index dc54707..adbf0b3 100644 --- a/IPython/frontend/terminal/console/app.py +++ b/IPython/frontend/terminal/console/app.py @@ -22,6 +22,8 @@ from IPython.frontend.terminal.ipapp import TerminalIPythonApp, frontend_flags a from IPython.utils.traitlets import ( Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any ) +from IPython.utils.warn import warn,error + from IPython.zmq.ipkernel import IPKernelApp from IPython.zmq.session import Session, default_secure from IPython.zmq.zmqshell import ZMQInteractiveShell @@ -114,12 +116,22 @@ class ZMQTerminalIPythonApp(TerminalIPythonApp, IPythonMixinConsoleApp): ipython_dir=self.ipython_dir, kernel_manager=self.kernel_manager) def handle_sigint(self, *args): - self.shell.write('KeyboardInterrupt\n') - if self.kernel_manager.has_kernel: - self.kernel_manager.interrupt_kernel() + if self.shell._executing: + if self.kernel_manager.has_kernel: + # interrupt already gets passed to subprocess by signal handler. + # Only if we prevent that should we need to explicitly call + # interrupt_kernel, until which time, this would result in a + # double-interrupt: + # self.kernel_manager.interrupt_kernel() + pass + else: + self.shell.write_err('\n') + error("Cannot interrupt kernels we didn't start.\n") else: - print 'Kernel process is either remote or unspecified.', - print 'Cannot interrupt.' + # raise the KeyboardInterrupt if we aren't waiting for execution, + # so that the interact loop advances, and prompt is redrawn, etc. + raise KeyboardInterrupt + def init_code(self): # no-op in the frontend, code gets run in the backend diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index a23f8e3..a7994bf 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -198,6 +198,9 @@ class Kernel(Configurable): except KeyboardInterrupt: # Ctrl-C shouldn't crash the kernel io.raw_print("KeyboardInterrupt caught in kernel") + # stop ignoring sigint, now that we are out of our own loop, + # we don't want to prevent future code from handling it + signal(SIGINT, default_int_handler) if self.eventloop is not None: try: self.eventloop(self)