Show More
@@ -445,18 +445,30 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
445 | self._reading = False |
|
445 | self._reading = False | |
446 | self._readline(msg['content']['prompt'], callback=callback) |
|
446 | self._readline(msg['content']['prompt'], callback=callback) | |
447 |
|
447 | |||
|
448 | def _kernel_restarted_message(self, died=True): | |||
|
449 | msg = "Kernel died, restarting" if died else "Kernel restarting" | |||
|
450 | self._append_html("<br>%s<hr><br>" % msg, | |||
|
451 | before_prompt=False | |||
|
452 | ) | |||
|
453 | ||||
448 | def _handle_kernel_died(self, since_last_heartbeat): |
|
454 | def _handle_kernel_died(self, since_last_heartbeat): | |
449 |
""" |
|
455 | """Handle the kernel's death (if we do not own the kernel). | |
450 | """ |
|
456 | """ | |
451 |
self.log. |
|
457 | self.log.warn("kernel died: %s", since_last_heartbeat) | |
452 | if self.custom_restart: |
|
458 | if self.custom_restart: | |
453 | self.custom_restart_kernel_died.emit(since_last_heartbeat) |
|
459 | self.custom_restart_kernel_died.emit(since_last_heartbeat) | |
454 | else: |
|
460 | else: | |
455 | message = 'The kernel heartbeat has been inactive for %.2f ' \ |
|
461 | self._kernel_restarted_message(died=True) | |
456 | 'seconds. Do you want to restart the kernel? You may ' \ |
|
462 | self.reset() | |
457 | 'first want to check the network connection.' % \ |
|
463 | ||
458 | since_last_heartbeat |
|
464 | def _handle_kernel_restarted(self, died=True): | |
459 | self.restart_kernel(message, now=True) |
|
465 | """Notice that the autorestarter restarted the kernel. | |
|
466 | ||||
|
467 | There's nothing to do but show a message. | |||
|
468 | """ | |||
|
469 | self.log.warn("kernel restarted") | |||
|
470 | self._kernel_restarted_message(died=died) | |||
|
471 | self.reset() | |||
460 |
|
472 | |||
461 | def _handle_object_info_reply(self, rep): |
|
473 | def _handle_object_info_reply(self, rep): | |
462 | """ Handle replies for call tips. |
|
474 | """ Handle replies for call tips. | |
@@ -506,37 +518,28 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
506 | def _handle_shutdown_reply(self, msg): |
|
518 | def _handle_shutdown_reply(self, msg): | |
507 | """ Handle shutdown signal, only if from other console. |
|
519 | """ Handle shutdown signal, only if from other console. | |
508 | """ |
|
520 | """ | |
509 |
self.log. |
|
521 | self.log.warn("shutdown: %s", msg.get('content', '')) | |
|
522 | restart = msg.get('content', {}).get('restart', False) | |||
510 | if not self._hidden and not self._is_from_this_session(msg): |
|
523 | if not self._hidden and not self._is_from_this_session(msg): | |
511 | if self._local_kernel: |
|
524 | # got shutdown reply, request came from session other than ours | |
512 |
|
|
525 | if restart: | |
|
526 | # someone restarted the kernel, handle it | |||
|
527 | self._handle_kernel_restarted(died=False) | |||
|
528 | else: | |||
|
529 | # kernel was shutdown permanently | |||
|
530 | # this triggers exit_requested if the kernel was local, | |||
|
531 | # and a dialog if the kernel was remote, | |||
|
532 | # so we don't suddenly clear the qtconsole without asking. | |||
|
533 | if self._local_kernel: | |||
513 | self.exit_requested.emit(self) |
|
534 | self.exit_requested.emit(self) | |
514 | else: |
|
535 | else: | |
515 | # we just got notified of a restart! |
|
536 | title = self.window().windowTitle() | |
516 | time.sleep(0.25) # wait 1/4 sec to reset |
|
|||
517 | # lest the request for a new prompt |
|
|||
518 | # goes to the old kernel |
|
|||
519 | self.reset() |
|
|||
520 | else: # remote kernel, prompt on Kernel shutdown/reset |
|
|||
521 | title = self.window().windowTitle() |
|
|||
522 | if not msg['content']['restart']: |
|
|||
523 | reply = QtGui.QMessageBox.question(self, title, |
|
537 | reply = QtGui.QMessageBox.question(self, title, | |
524 | "Kernel has been shutdown permanently. " |
|
538 | "Kernel has been shutdown permanently. " | |
525 | "Close the Console?", |
|
539 | "Close the Console?", | |
526 | QtGui.QMessageBox.Yes,QtGui.QMessageBox.No) |
|
540 | QtGui.QMessageBox.Yes,QtGui.QMessageBox.No) | |
527 | if reply == QtGui.QMessageBox.Yes: |
|
541 | if reply == QtGui.QMessageBox.Yes: | |
528 | self.exit_requested.emit(self) |
|
542 | self.exit_requested.emit(self) | |
529 | else: |
|
|||
530 | # XXX: remove message box in favor of using the |
|
|||
531 | # clear_on_kernel_restart setting? |
|
|||
532 | reply = QtGui.QMessageBox.question(self, title, |
|
|||
533 | "Kernel has been reset. Clear the Console?", |
|
|||
534 | QtGui.QMessageBox.Yes,QtGui.QMessageBox.No) |
|
|||
535 | if reply == QtGui.QMessageBox.Yes: |
|
|||
536 | time.sleep(0.25) # wait 1/4 sec to reset |
|
|||
537 | # lest the request for a new prompt |
|
|||
538 | # goes to the old kernel |
|
|||
539 | self.reset() |
|
|||
540 |
|
543 | |||
541 | def _started_channels(self): |
|
544 | def _started_channels(self): | |
542 | """ Called when the KernelManager channels have started listening or |
|
545 | """ Called when the KernelManager channels have started listening or | |
@@ -573,12 +576,11 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
573 | self._reading = False |
|
576 | self._reading = False | |
574 | self.kernel_manager.interrupt_kernel() |
|
577 | self.kernel_manager.interrupt_kernel() | |
575 | else: |
|
578 | else: | |
576 |
self._append_plain_text(' |
|
579 | self._append_plain_text('Cannot interrupt a kernel I did not start.\n') | |
577 | 'unspecified. Cannot interrupt.\n') |
|
|||
578 |
|
580 | |||
579 | def reset(self, clear=False): |
|
581 | def reset(self, clear=False): | |
580 |
""" Resets the widget to its initial state if ``clear`` parameter |
|
582 | """ Resets the widget to its initial state if ``clear`` parameter | |
581 | ``clear_on_kernel_restart`` configuration setting is True, otherwise |
|
583 | is True, otherwise | |
582 | prints a visual indication of the fact that the kernel restarted, but |
|
584 | prints a visual indication of the fact that the kernel restarted, but | |
583 | does not clear the traces from previous usage of the kernel before it |
|
585 | does not clear the traces from previous usage of the kernel before it | |
584 | was restarted. With ``clear=True``, it is similar to ``%clear``, but |
|
586 | was restarted. With ``clear=True``, it is similar to ``%clear``, but | |
@@ -590,15 +592,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
590 | self._reading = False |
|
592 | self._reading = False | |
591 | self._highlighter.highlighting_on = False |
|
593 | self._highlighter.highlighting_on = False | |
592 |
|
594 | |||
593 | if self.clear_on_kernel_restart or clear: |
|
595 | if clear: | |
594 | self._control.clear() |
|
596 | self._control.clear() | |
595 | self._append_plain_text(self.banner) |
|
597 | self._append_plain_text(self.banner) | |
596 | else: |
|
|||
597 | self._append_plain_text("# restarting kernel...") |
|
|||
598 | self._append_html("<hr><br>") |
|
|||
599 | # XXX: Reprinting the full banner may be too much, but once #1680 is |
|
|||
600 | # addressed, that will mitigate it. |
|
|||
601 | #self._append_plain_text(self.banner) |
|
|||
602 | # update output marker for stdout/stderr, so that startup |
|
598 | # update output marker for stdout/stderr, so that startup | |
603 | # messages appear after banner: |
|
599 | # messages appear after banner: | |
604 | self._append_before_prompt_pos = self._get_cursor().position() |
|
600 | self._append_before_prompt_pos = self._get_cursor().position() | |
@@ -615,8 +611,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
615 |
|
611 | |||
616 | if self.custom_restart: |
|
612 | if self.custom_restart: | |
617 | self.custom_restart_requested.emit() |
|
613 | self.custom_restart_requested.emit() | |
|
614 | return | |||
618 |
|
615 | |||
619 |
|
|
616 | if self.kernel_manager: | |
620 | # Pause the heart beat channel to prevent further warnings. |
|
617 | # Pause the heart beat channel to prevent further warnings. | |
621 | self.kernel_client.hb_channel.pause() |
|
618 | self.kernel_client.hb_channel.pause() | |
622 |
|
619 | |||
@@ -635,21 +632,23 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
635 | if do_restart: |
|
632 | if do_restart: | |
636 | try: |
|
633 | try: | |
637 | self.kernel_manager.restart_kernel(now=now) |
|
634 | self.kernel_manager.restart_kernel(now=now) | |
638 | except RuntimeError: |
|
635 | except RuntimeError as e: | |
639 |
self._append_plain_text( |
|
636 | self._append_plain_text( | |
640 |
|
|
637 | 'Error restarting kernel: %s\n' % e, | |
641 |
|
|
638 | before_prompt=True | |
642 |
|
|
639 | ) | |
643 | else: |
|
640 | else: | |
644 | self.reset() |
|
641 | self._append_html("<br>Restarting kernel...\n<hr><br>", | |
|
642 | before_prompt=True, | |||
|
643 | ) | |||
645 | else: |
|
644 | else: | |
646 | self.kernel_client.hb_channel.unpause() |
|
645 | self.kernel_client.hb_channel.unpause() | |
647 |
|
646 | |||
648 | else: |
|
647 | else: | |
649 |
self._append_plain_text( |
|
648 | self._append_plain_text( | |
650 | 'unspecified. Cannot restart.\n', |
|
649 | 'Cannot restart a Kernel I did not start\n', | |
651 |
|
|
650 | before_prompt=True | |
652 | ) |
|
651 | ) | |
653 |
|
652 | |||
654 | #--------------------------------------------------------------------------- |
|
653 | #--------------------------------------------------------------------------- | |
655 | # 'FrontendWidget' protected interface |
|
654 | # 'FrontendWidget' protected interface |
@@ -62,6 +62,7 b' from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget' | |||||
62 | from IPython.frontend.qt.console import styles |
|
62 | from IPython.frontend.qt.console import styles | |
63 | from IPython.frontend.qt.console.mainwindow import MainWindow |
|
63 | from IPython.frontend.qt.console.mainwindow import MainWindow | |
64 | from IPython.frontend.qt.client import QtKernelClient |
|
64 | from IPython.frontend.qt.client import QtKernelClient | |
|
65 | from IPython.frontend.qt.manager import QtKernelManager | |||
65 | from IPython.kernel import tunnel_to_kernel, find_connection_file |
|
66 | from IPython.kernel import tunnel_to_kernel, find_connection_file | |
66 | from IPython.utils.traitlets import ( |
|
67 | from IPython.utils.traitlets import ( | |
67 | Dict, List, Unicode, CBool, Any |
|
68 | Dict, List, Unicode, CBool, Any | |
@@ -160,6 +161,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
160 | frontend_flags = Any(qt_flags) |
|
161 | frontend_flags = Any(qt_flags) | |
161 | frontend_aliases = Any(qt_aliases) |
|
162 | frontend_aliases = Any(qt_aliases) | |
162 | kernel_client_class = QtKernelClient |
|
163 | kernel_client_class = QtKernelClient | |
|
164 | kernel_manager_class = QtKernelManager | |||
163 |
|
165 | |||
164 | stylesheet = Unicode('', config=True, |
|
166 | stylesheet = Unicode('', config=True, | |
165 | help="path to a custom CSS stylesheet") |
|
167 | help="path to a custom CSS stylesheet") | |
@@ -189,19 +191,15 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
189 | kernel_manager = self.kernel_manager_class( |
|
191 | kernel_manager = self.kernel_manager_class( | |
190 | connection_file=self._new_connection_file(), |
|
192 | connection_file=self._new_connection_file(), | |
191 | config=self.config, |
|
193 | config=self.config, | |
|
194 | autorestart=True, | |||
192 | ) |
|
195 | ) | |
193 | # start the kernel |
|
196 | # start the kernel | |
194 | kwargs = dict() |
|
197 | kwargs = dict() | |
195 | kwargs['extra_arguments'] = self.kernel_argv |
|
198 | kwargs['extra_arguments'] = self.kernel_argv | |
196 | kernel_manager.start_kernel(**kwargs) |
|
199 | kernel_manager.start_kernel(**kwargs) | |
197 |
|
200 | kernel_manager.client_factory = self.kernel_client_class | ||
198 | # connect to the kernel |
|
201 | kernel_client = kernel_manager.client() | |
199 | kernel_client = self.kernel_client_class( |
|
202 | kernel_client.start_channels(shell=True, iopub=True) | |
200 | connection_file=kernel_manager.connection_file, |
|
|||
201 | config=self.config, |
|
|||
202 | ) |
|
|||
203 | kernel_client.load_connection_file() |
|
|||
204 | kernel_client.start_channels() |
|
|||
205 | widget = self.widget_factory(config=self.config, |
|
203 | widget = self.widget_factory(config=self.config, | |
206 | local_kernel=True) |
|
204 | local_kernel=True) | |
207 | self.init_colors(widget) |
|
205 | self.init_colors(widget) | |
@@ -220,7 +218,6 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
220 | current_widget : IPythonWidget |
|
218 | current_widget : IPythonWidget | |
221 | The IPythonWidget whose kernel this frontend is to share |
|
219 | The IPythonWidget whose kernel this frontend is to share | |
222 | """ |
|
220 | """ | |
223 |
|
||||
224 | kernel_client = self.kernel_client_class( |
|
221 | kernel_client = self.kernel_client_class( | |
225 | connection_file=current_widget.kernel_client.connection_file, |
|
222 | connection_file=current_widget.kernel_client.connection_file, | |
226 | config = self.config, |
|
223 | config = self.config, | |
@@ -234,11 +231,15 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
234 | widget._may_close = False |
|
231 | widget._may_close = False | |
235 | widget._confirm_exit = False |
|
232 | widget._confirm_exit = False | |
236 | widget.kernel_client = kernel_client |
|
233 | widget.kernel_client = kernel_client | |
|
234 | widget.kernel_manager = current_widget.kernel_manager | |||
237 | return widget |
|
235 | return widget | |
238 |
|
236 | |||
|
237 | def init_qt_app(self): | |||
|
238 | # separate from qt_elements, because it must run first | |||
|
239 | self.app = QtGui.QApplication([]) | |||
|
240 | ||||
239 | def init_qt_elements(self): |
|
241 | def init_qt_elements(self): | |
240 | # Create the widget. |
|
242 | # Create the widget. | |
241 | self.app = QtGui.QApplication([]) |
|
|||
242 |
|
243 | |||
243 | base_path = os.path.abspath(os.path.dirname(__file__)) |
|
244 | base_path = os.path.abspath(os.path.dirname(__file__)) | |
244 | icon_path = os.path.join(base_path, 'resources', 'icon', 'IPythonConsole.svg') |
|
245 | icon_path = os.path.join(base_path, 'resources', 'icon', 'IPythonConsole.svg') | |
@@ -345,6 +346,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
345 |
|
346 | |||
346 | @catch_config_error |
|
347 | @catch_config_error | |
347 | def initialize(self, argv=None): |
|
348 | def initialize(self, argv=None): | |
|
349 | self.init_qt_app() | |||
348 | super(IPythonQtConsoleApp, self).initialize(argv) |
|
350 | super(IPythonQtConsoleApp, self).initialize(argv) | |
349 | IPythonConsoleApp.initialize(self,argv) |
|
351 | IPythonConsoleApp.initialize(self,argv) | |
350 | self.init_qt_elements() |
|
352 | self.init_qt_elements() |
General Comments 0
You need to be logged in to leave comments.
Login now