Permalink
Browse files

Merge branch 'keepkernel' of https://github.com/minrk/ipython into mi…

…nrk-keepkernel

Closes pull request gh-164.
  • Loading branch information...
fperez committed Oct 10, 2010
2 parents a55b74a + 2675471 commit f16f5ccccc03d34634271a090b37e00caebe0b10
@@ -3,6 +3,7 @@
# Standard library imports
from collections import namedtuple
import sys
+import time
# System library imports
from pygments.lexers import PythonLexer
@@ -361,6 +362,19 @@ def _handle_stream(self, msg):
self._append_plain_text(text)
self._control.moveCursor(QtGui.QTextCursor.End)
+ def _handle_shutdown_reply(self, msg):
+ """ Handle shutdown signal, only if from other console.
+ """
+ if not self._hidden and not self._is_from_this_session(msg):
+ if not msg['content']['restart']:
+ sys.exit(0)
+ else:
+ # we just got notified of a restart!
+ time.sleep(0.25) # wait 1/4 sec to reset
+ # lest the request for a new prompt
+ # goes to the old kernel
+ self.reset()
+
def _started_channels(self):
""" Called when the KernelManager channels have started listening or
when the frontend is assigned an already listening KernelManager.
@@ -31,11 +31,18 @@ class MainWindow(QtGui.QMainWindow):
# 'object' interface
#---------------------------------------------------------------------------
- def __init__(self, frontend):
+ def __init__(self, app, frontend, existing=False):
""" Create a MainWindow for the specified FrontendWidget.
+
+ The app is passed as an argument to allow for different
+ closing behavior depending on whether we are the Kernel's parent.
+
+ If existing is True, then this Window does not own the Kernel.
"""
super(MainWindow, self).__init__()
+ self._app = app
self._frontend = frontend
+ self._existing = existing
self._frontend.exit_requested.connect(self.close)
self.setCentralWidget(frontend)
@@ -50,11 +57,18 @@ def closeEvent(self, event):
if kernel_manager and kernel_manager.channels_running:
title = self.window().windowTitle()
reply = QtGui.QMessageBox.question(self, title,
- 'Close console?', QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
- if reply == QtGui.QMessageBox.Yes:
+ "Close just this console, or shutdown the kernel and close "+
+ "all windows attached to it?",
+ 'Cancel', 'Close Console', 'Close All')
+ if reply == 2: # close All
kernel_manager.shutdown_kernel()
#kernel_manager.stop_channels()
event.accept()
+ elif reply == 1: # close Console
+ if not self._existing:
+ # I have the kernel: don't quit, just close the window
+ self._app.setQuitOnLastWindowClosed(False)
+ event.accept()
else:
event.ignore()
@@ -132,7 +146,7 @@ def main():
widget.kernel_manager = kernel_manager
# Create the main window.
- window = MainWindow(widget)
+ window = MainWindow(app, widget, args.existing)
window.setWindowTitle('Python' if args.pure else 'IPython')
window.show()
@@ -105,6 +105,9 @@ class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
# last-resort sys.excepthook.
crash_received = QtCore.pyqtSignal(object)
+ # Emitted when a shutdown is noticed.
+ shutdown_reply_received = QtCore.pyqtSignal(object)
+
#---------------------------------------------------------------------------
# 'SubSocketChannel' interface
#---------------------------------------------------------------------------
View
@@ -330,7 +330,7 @@ def connect_request(self, ident, parent):
def shutdown_request(self, ident, parent):
self.shell.exit_now = True
- self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
+ self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
sys.exit(0)
#---------------------------------------------------------------------------
@@ -428,6 +428,7 @@ def _at_shutdown(self):
# io.rprint("Kernel at_shutdown") # dbg
if self._shutdown_message is not None:
self.reply_socket.send_json(self._shutdown_message)
+ self.pub_socket.send_json(self._shutdown_message)
io.raw_print(self._shutdown_message)
# A very short sleep to give zmq time to flush its message buffers
# before Python truly shuts down.
@@ -305,7 +305,7 @@ def history(self, index=None, raw=False, output=True):
self._queue_request(msg)
return msg['header']['msg_id']
- def shutdown(self):
+ def shutdown(self, restart=False):
"""Request an immediate kernel shutdown.
Upon receipt of the (empty) reply, client code can safely assume that
@@ -318,7 +318,7 @@ def shutdown(self):
"""
# Send quit message to kernel. Once we implement kernel-side setattr,
# this should probably be done that way, but for now this will do.
- msg = self.session.msg('shutdown_request', {})
+ msg = self.session.msg('shutdown_request', {'restart':restart})
self._queue_request(msg)
return msg['header']['msg_id']
@@ -743,7 +743,7 @@ def start_kernel(self, **kw):
self.rep_address = (LOCALHOST, req)
self.hb_address = (LOCALHOST, hb)
- def shutdown_kernel(self):
+ def shutdown_kernel(self, restart=False):
""" Attempts to the stop the kernel process cleanly. If the kernel
cannot be stopped, it is killed, if possible.
"""
@@ -759,7 +759,7 @@ def shutdown_kernel(self):
# Don't send any additional kernel kill messages immediately, to give
# the kernel a chance to properly execute shutdown actions. Wait for at
# most 1s, checking every 0.1s.
- self.xreq_channel.shutdown()
+ self.xreq_channel.shutdown(restart=restart)
for i in range(10):
if self.is_alive:
time.sleep(0.1)
@@ -793,7 +793,7 @@ def restart_kernel(self, now=False):
if now:
self.kill_kernel()
else:
- self.shutdown_kernel()
+ self.shutdown_kernel(restart=True)
self.start_kernel(**self._launch_args)
# FIXME: Messages get dropped in Windows due to probable ZMQ bug
View
@@ -60,7 +60,7 @@ def __init__(self, **kwargs):
# Build dict of handlers for message types
msg_types = [ 'execute_request', 'complete_request',
- 'object_info_request' ]
+ 'object_info_request', 'shutdown_request' ]
self.handlers = {}
for msg_type in msg_types:
self.handlers[msg_type] = getattr(self, msg_type)
@@ -163,6 +163,16 @@ def object_info_request(self, ident, parent):
object_info, parent, ident)
print >> sys.__stdout__, msg
+ def shutdown_request(self, ident, parent):
+ content = dict(parent['content'])
+ msg = self.session.send(self.reply_socket, 'shutdown_reply',
+ content, parent, ident)
+ msg = self.session.send(self.pub_socket, 'shutdown_reply',
+ content, parent, ident)
+ print >> sys.__stdout__, msg
+ time.sleep(0.1)
+ sys.exit(0)
+
#---------------------------------------------------------------------------
# Protected interface
#---------------------------------------------------------------------------
@@ -663,11 +663,13 @@ be sent, so the content dict is empty.
Message type: ``shutdown_request``::
content = {
+ 'restart' : bool # whether the shutdown is final, or precedes a restart
}
Message type: ``shutdown_reply``::
content = {
+ 'restart' : bool # whether the shutdown is final, or precedes a restart
}
.. Note::

0 comments on commit f16f5cc

Please sign in to comment.