##// END OF EJS Templates
Merge branch 'keepkernel' of https://github.com/minrk/ipython into minrk-keepkernel...
Fernando Perez -
r3106:f16f5ccc merge
parent child Browse files
Show More
@@ -3,6 +3,7 b' from __future__ import print_function'
3 # Standard library imports
3 # Standard library imports
4 from collections import namedtuple
4 from collections import namedtuple
5 import sys
5 import sys
6 import time
6
7
7 # System library imports
8 # System library imports
8 from pygments.lexers import PythonLexer
9 from pygments.lexers import PythonLexer
@@ -361,6 +362,19 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
361 self._append_plain_text(text)
362 self._append_plain_text(text)
362 self._control.moveCursor(QtGui.QTextCursor.End)
363 self._control.moveCursor(QtGui.QTextCursor.End)
363
364
365 def _handle_shutdown_reply(self, msg):
366 """ Handle shutdown signal, only if from other console.
367 """
368 if not self._hidden and not self._is_from_this_session(msg):
369 if not msg['content']['restart']:
370 sys.exit(0)
371 else:
372 # we just got notified of a restart!
373 time.sleep(0.25) # wait 1/4 sec to reset
374 # lest the request for a new prompt
375 # goes to the old kernel
376 self.reset()
377
364 def _started_channels(self):
378 def _started_channels(self):
365 """ Called when the KernelManager channels have started listening or
379 """ Called when the KernelManager channels have started listening or
366 when the frontend is assigned an already listening KernelManager.
380 when the frontend is assigned an already listening KernelManager.
@@ -31,11 +31,18 b' class MainWindow(QtGui.QMainWindow):'
31 # 'object' interface
31 # 'object' interface
32 #---------------------------------------------------------------------------
32 #---------------------------------------------------------------------------
33
33
34 def __init__(self, frontend):
34 def __init__(self, app, frontend, existing=False):
35 """ Create a MainWindow for the specified FrontendWidget.
35 """ Create a MainWindow for the specified FrontendWidget.
36
37 The app is passed as an argument to allow for different
38 closing behavior depending on whether we are the Kernel's parent.
39
40 If existing is True, then this Window does not own the Kernel.
36 """
41 """
37 super(MainWindow, self).__init__()
42 super(MainWindow, self).__init__()
43 self._app = app
38 self._frontend = frontend
44 self._frontend = frontend
45 self._existing = existing
39 self._frontend.exit_requested.connect(self.close)
46 self._frontend.exit_requested.connect(self.close)
40 self.setCentralWidget(frontend)
47 self.setCentralWidget(frontend)
41
48
@@ -50,11 +57,18 b' class MainWindow(QtGui.QMainWindow):'
50 if kernel_manager and kernel_manager.channels_running:
57 if kernel_manager and kernel_manager.channels_running:
51 title = self.window().windowTitle()
58 title = self.window().windowTitle()
52 reply = QtGui.QMessageBox.question(self, title,
59 reply = QtGui.QMessageBox.question(self, title,
53 'Close console?', QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
60 "Close just this console, or shutdown the kernel and close "+
54 if reply == QtGui.QMessageBox.Yes:
61 "all windows attached to it?",
62 'Cancel', 'Close Console', 'Close All')
63 if reply == 2: # close All
55 kernel_manager.shutdown_kernel()
64 kernel_manager.shutdown_kernel()
56 #kernel_manager.stop_channels()
65 #kernel_manager.stop_channels()
57 event.accept()
66 event.accept()
67 elif reply == 1: # close Console
68 if not self._existing:
69 # I have the kernel: don't quit, just close the window
70 self._app.setQuitOnLastWindowClosed(False)
71 event.accept()
58 else:
72 else:
59 event.ignore()
73 event.ignore()
60
74
@@ -132,7 +146,7 b' def main():'
132 widget.kernel_manager = kernel_manager
146 widget.kernel_manager = kernel_manager
133
147
134 # Create the main window.
148 # Create the main window.
135 window = MainWindow(widget)
149 window = MainWindow(app, widget, args.existing)
136 window.setWindowTitle('Python' if args.pure else 'IPython')
150 window.setWindowTitle('Python' if args.pure else 'IPython')
137 window.show()
151 window.show()
138
152
@@ -105,6 +105,9 b' class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):'
105 # last-resort sys.excepthook.
105 # last-resort sys.excepthook.
106 crash_received = QtCore.pyqtSignal(object)
106 crash_received = QtCore.pyqtSignal(object)
107
107
108 # Emitted when a shutdown is noticed.
109 shutdown_reply_received = QtCore.pyqtSignal(object)
110
108 #---------------------------------------------------------------------------
111 #---------------------------------------------------------------------------
109 # 'SubSocketChannel' interface
112 # 'SubSocketChannel' interface
110 #---------------------------------------------------------------------------
113 #---------------------------------------------------------------------------
@@ -330,7 +330,7 b' class Kernel(Configurable):'
330
330
331 def shutdown_request(self, ident, parent):
331 def shutdown_request(self, ident, parent):
332 self.shell.exit_now = True
332 self.shell.exit_now = True
333 self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
333 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
334 sys.exit(0)
334 sys.exit(0)
335
335
336 #---------------------------------------------------------------------------
336 #---------------------------------------------------------------------------
@@ -428,6 +428,7 b' class Kernel(Configurable):'
428 # io.rprint("Kernel at_shutdown") # dbg
428 # io.rprint("Kernel at_shutdown") # dbg
429 if self._shutdown_message is not None:
429 if self._shutdown_message is not None:
430 self.reply_socket.send_json(self._shutdown_message)
430 self.reply_socket.send_json(self._shutdown_message)
431 self.pub_socket.send_json(self._shutdown_message)
431 io.raw_print(self._shutdown_message)
432 io.raw_print(self._shutdown_message)
432 # A very short sleep to give zmq time to flush its message buffers
433 # A very short sleep to give zmq time to flush its message buffers
433 # before Python truly shuts down.
434 # before Python truly shuts down.
@@ -305,7 +305,7 b' class XReqSocketChannel(ZmqSocketChannel):'
305 self._queue_request(msg)
305 self._queue_request(msg)
306 return msg['header']['msg_id']
306 return msg['header']['msg_id']
307
307
308 def shutdown(self):
308 def shutdown(self, restart=False):
309 """Request an immediate kernel shutdown.
309 """Request an immediate kernel shutdown.
310
310
311 Upon receipt of the (empty) reply, client code can safely assume that
311 Upon receipt of the (empty) reply, client code can safely assume that
@@ -318,7 +318,7 b' class XReqSocketChannel(ZmqSocketChannel):'
318 """
318 """
319 # Send quit message to kernel. Once we implement kernel-side setattr,
319 # Send quit message to kernel. Once we implement kernel-side setattr,
320 # this should probably be done that way, but for now this will do.
320 # this should probably be done that way, but for now this will do.
321 msg = self.session.msg('shutdown_request', {})
321 msg = self.session.msg('shutdown_request', {'restart':restart})
322 self._queue_request(msg)
322 self._queue_request(msg)
323 return msg['header']['msg_id']
323 return msg['header']['msg_id']
324
324
@@ -743,7 +743,7 b' class KernelManager(HasTraits):'
743 self.rep_address = (LOCALHOST, req)
743 self.rep_address = (LOCALHOST, req)
744 self.hb_address = (LOCALHOST, hb)
744 self.hb_address = (LOCALHOST, hb)
745
745
746 def shutdown_kernel(self):
746 def shutdown_kernel(self, restart=False):
747 """ Attempts to the stop the kernel process cleanly. If the kernel
747 """ Attempts to the stop the kernel process cleanly. If the kernel
748 cannot be stopped, it is killed, if possible.
748 cannot be stopped, it is killed, if possible.
749 """
749 """
@@ -759,7 +759,7 b' class KernelManager(HasTraits):'
759 # Don't send any additional kernel kill messages immediately, to give
759 # Don't send any additional kernel kill messages immediately, to give
760 # the kernel a chance to properly execute shutdown actions. Wait for at
760 # the kernel a chance to properly execute shutdown actions. Wait for at
761 # most 1s, checking every 0.1s.
761 # most 1s, checking every 0.1s.
762 self.xreq_channel.shutdown()
762 self.xreq_channel.shutdown(restart=restart)
763 for i in range(10):
763 for i in range(10):
764 if self.is_alive:
764 if self.is_alive:
765 time.sleep(0.1)
765 time.sleep(0.1)
@@ -793,7 +793,7 b' class KernelManager(HasTraits):'
793 if now:
793 if now:
794 self.kill_kernel()
794 self.kill_kernel()
795 else:
795 else:
796 self.shutdown_kernel()
796 self.shutdown_kernel(restart=True)
797 self.start_kernel(**self._launch_args)
797 self.start_kernel(**self._launch_args)
798
798
799 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
799 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
@@ -60,7 +60,7 b' class Kernel(HasTraits):'
60
60
61 # Build dict of handlers for message types
61 # Build dict of handlers for message types
62 msg_types = [ 'execute_request', 'complete_request',
62 msg_types = [ 'execute_request', 'complete_request',
63 'object_info_request' ]
63 'object_info_request', 'shutdown_request' ]
64 self.handlers = {}
64 self.handlers = {}
65 for msg_type in msg_types:
65 for msg_type in msg_types:
66 self.handlers[msg_type] = getattr(self, msg_type)
66 self.handlers[msg_type] = getattr(self, msg_type)
@@ -163,6 +163,16 b' class Kernel(HasTraits):'
163 object_info, parent, ident)
163 object_info, parent, ident)
164 print >> sys.__stdout__, msg
164 print >> sys.__stdout__, msg
165
165
166 def shutdown_request(self, ident, parent):
167 content = dict(parent['content'])
168 msg = self.session.send(self.reply_socket, 'shutdown_reply',
169 content, parent, ident)
170 msg = self.session.send(self.pub_socket, 'shutdown_reply',
171 content, parent, ident)
172 print >> sys.__stdout__, msg
173 time.sleep(0.1)
174 sys.exit(0)
175
166 #---------------------------------------------------------------------------
176 #---------------------------------------------------------------------------
167 # Protected interface
177 # Protected interface
168 #---------------------------------------------------------------------------
178 #---------------------------------------------------------------------------
@@ -663,11 +663,13 b' be sent, so the content dict is empty.'
663 Message type: ``shutdown_request``::
663 Message type: ``shutdown_request``::
664
664
665 content = {
665 content = {
666 'restart' : bool # whether the shutdown is final, or precedes a restart
666 }
667 }
667
668
668 Message type: ``shutdown_reply``::
669 Message type: ``shutdown_reply``::
669
670
670 content = {
671 content = {
672 'restart' : bool # whether the shutdown is final, or precedes a restart
671 }
673 }
672
674
673 .. Note::
675 .. Note::
General Comments 0
You need to be logged in to leave comments. Login now