##// END OF EJS Templates
First cut at allowing the kernel to be restarted from the frontend.
epatters -
Show More
@@ -430,12 +430,6 b' class ConsoleWidget(QtGui.QWidget):'
430 """
430 """
431 raise NotImplementedError
431 raise NotImplementedError
432
432
433 def _execute_interrupt(self):
434 """ Attempts to stop execution. Returns whether this method has an
435 implementation.
436 """
437 return False
438
439 def _prompt_started_hook(self):
433 def _prompt_started_hook(self):
440 """ Called immediately after a new prompt is displayed.
434 """ Called immediately after a new prompt is displayed.
441 """
435 """
@@ -575,10 +569,7 b' class ConsoleWidget(QtGui.QWidget):'
575 intercepted = True
569 intercepted = True
576
570
577 elif ctrl_down:
571 elif ctrl_down:
578 if key == QtCore.Qt.Key_C:
572 if key == QtCore.Qt.Key_K:
579 intercepted = self._executing and self._execute_interrupt()
580
581 elif key == QtCore.Qt.Key_K:
582 if self._in_buffer(position):
573 if self._in_buffer(position):
583 cursor.movePosition(QtGui.QTextCursor.EndOfLine,
574 cursor.movePosition(QtGui.QTextCursor.EndOfLine,
584 QtGui.QTextCursor.KeepAnchor)
575 QtGui.QTextCursor.KeepAnchor)
@@ -72,12 +72,22 b' class FrontendHighlighter(PygmentsHighlighter):'
72 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
72 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
73 """ A Qt frontend for a generic Python kernel.
73 """ A Qt frontend for a generic Python kernel.
74 """
74 """
75
76 # An option and corresponding signal for overriding the default kernel
77 # interrupt behavior.
78 custom_interrupt = False
79 custom_interrupt_requested = QtCore.pyqtSignal()
80
81 # An option and corresponding signal for overriding the default kernel
82 # restart behavior.
83 custom_restart = False
84 custom_restart_requested = QtCore.pyqtSignal()
75
85
76 # Emitted when an 'execute_reply' has been received from the kernel and
86 # Emitted when an 'execute_reply' has been received from the kernel and
77 # processed by the FrontendWidget.
87 # processed by the FrontendWidget.
78 executed = QtCore.pyqtSignal(object)
88 executed = QtCore.pyqtSignal(object)
79
89
80 # Protected class attributes.
90 # Protected class variables.
81 _highlighter_class = FrontendHighlighter
91 _highlighter_class = FrontendHighlighter
82 _input_splitter_class = InputSplitter
92 _input_splitter_class = InputSplitter
83
93
@@ -123,13 +133,6 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
123 """
133 """
124 self.kernel_manager.xreq_channel.execute(source, hidden)
134 self.kernel_manager.xreq_channel.execute(source, hidden)
125 self._hidden = hidden
135 self._hidden = hidden
126
127 def _execute_interrupt(self):
128 """ Attempts to stop execution. Returns whether this method has an
129 implementation.
130 """
131 self._interrupt_kernel()
132 return True
133
136
134 def _prompt_started_hook(self):
137 def _prompt_started_hook(self):
135 """ Called immediately after a new prompt is displayed.
138 """ Called immediately after a new prompt is displayed.
@@ -163,6 +166,19 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
163 # 'ConsoleWidget' protected interface
166 # 'ConsoleWidget' protected interface
164 #---------------------------------------------------------------------------
167 #---------------------------------------------------------------------------
165
168
169 def _event_filter_console_keypress(self, event):
170 """ Reimplemented to allow execution interruption.
171 """
172 key = event.key()
173 if self._executing and self._control_key_down(event.modifiers()):
174 if key == QtCore.Qt.Key_C:
175 self._kernel_interrupt()
176 return True
177 elif key == QtCore.Qt.Key_Period:
178 self._kernel_restart()
179 return True
180 return super(FrontendWidget, self)._event_filter_console_keypress(event)
181
166 def _show_continuation_prompt(self):
182 def _show_continuation_prompt(self):
167 """ Reimplemented for auto-indentation.
183 """ Reimplemented for auto-indentation.
168 """
184 """
@@ -324,15 +340,36 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
324 text = str(cursor.selection().toPlainText())
340 text = str(cursor.selection().toPlainText())
325 return self._completion_lexer.get_context(text)
341 return self._completion_lexer.get_context(text)
326
342
327 def _interrupt_kernel(self):
343 def _kernel_interrupt(self):
328 """ Attempts to the interrupt the kernel.
344 """ Attempts to interrupt the running kernel.
329 """
345 """
330 if self.kernel_manager.has_kernel:
346 if self.custom_interrupt:
347 self.custom_interrupt_requested.emit()
348 elif self.kernel_manager.has_kernel:
331 self.kernel_manager.signal_kernel(signal.SIGINT)
349 self.kernel_manager.signal_kernel(signal.SIGINT)
332 else:
350 else:
333 self._append_plain_text('Kernel process is either remote or '
351 self._append_plain_text('Kernel process is either remote or '
334 'unspecified. Cannot interrupt.\n')
352 'unspecified. Cannot interrupt.\n')
335
353
354 def _kernel_restart(self):
355 """ Attempts to restart the running kernel.
356 """
357 if self.custom_restart:
358 self.custom_restart_requested.emit()
359 elif self.kernel_manager.has_kernel:
360 try:
361 self.kernel_manager.restart_kernel()
362 except RuntimeError:
363 message = 'Kernel started externally. Cannot restart.\n'
364 self._append_plain_text(message)
365 else:
366 self._stopped_channels()
367 self._append_plain_text('Kernel restarting...\n')
368 self._show_interpreter_prompt()
369 else:
370 self._append_plain_text('Kernel process is either remote or '
371 'unspecified. Cannot restart.\n')
372
336 def _process_execute_abort(self, msg):
373 def _process_execute_abort(self, msg):
337 """ Process a reply for an aborted execution request.
374 """ Process a reply for an aborted execution request.
338 """
375 """
@@ -1,5 +1,3 b''
1 import os
2
3 # System library imports
1 # System library imports
4 from PyQt4 import QtCore, QtGui
2 from PyQt4 import QtCore, QtGui
5
3
@@ -482,6 +482,7 b' class KernelManager(HasTraits):'
482 rep_channel_class = Type(RepSocketChannel)
482 rep_channel_class = Type(RepSocketChannel)
483
483
484 # Protected traits.
484 # Protected traits.
485 _launch_args = Any
485 _xreq_channel = Any
486 _xreq_channel = Any
486 _sub_channel = Any
487 _sub_channel = Any
487 _rep_channel = Any
488 _rep_channel = Any
@@ -523,7 +524,7 b' class KernelManager(HasTraits):'
523 # Kernel process management methods:
524 # Kernel process management methods:
524 #--------------------------------------------------------------------------
525 #--------------------------------------------------------------------------
525
526
526 def start_kernel(self, ipython=True, **kw):
527 def start_kernel(self, **kw):
527 """Starts a kernel process and configures the manager to use it.
528 """Starts a kernel process and configures the manager to use it.
528
529
529 If random ports (port=0) are being used, this method must be called
530 If random ports (port=0) are being used, this method must be called
@@ -540,7 +541,8 b' class KernelManager(HasTraits):'
540 "Make sure that the '*_address' attributes are "
541 "Make sure that the '*_address' attributes are "
541 "configured properly.")
542 "configured properly.")
542
543
543 if ipython:
544 self._launch_args = kw.copy()
545 if kw.pop('ipython', True):
544 from ipkernel import launch_kernel as launch
546 from ipkernel import launch_kernel as launch
545 else:
547 else:
546 from pykernel import launch_kernel as launch
548 from pykernel import launch_kernel as launch
@@ -550,6 +552,19 b' class KernelManager(HasTraits):'
550 self.sub_address = (LOCALHOST, pub)
552 self.sub_address = (LOCALHOST, pub)
551 self.rep_address = (LOCALHOST, req)
553 self.rep_address = (LOCALHOST, req)
552
554
555 def restart_kernel(self):
556 """Restarts a kernel with the same arguments that were used to launch
557 it. If the old kernel was launched with random ports, the same ports
558 will be used for the new kernel.
559 """
560 if self._launch_args is None:
561 raise RuntimeError("Cannot restart the kernel. "
562 "No previous call to 'start_kernel'.")
563 else:
564 if self.has_kernel:
565 self.kill_kernel()
566 self.start_kernel(*self._launch_args)
567
553 @property
568 @property
554 def has_kernel(self):
569 def has_kernel(self):
555 """Returns whether a kernel process has been specified for the kernel
570 """Returns whether a kernel process has been specified for the kernel
General Comments 0
You need to be logged in to leave comments. Login now