base_frontend_mixin.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. """Defines a convenient mix-in class for implementing Qt frontends."""
  2. class BaseFrontendMixin(object):
  3. """ A mix-in class for implementing Qt frontends.
  4. To handle messages of a particular type, frontends need only define an
  5. appropriate handler method. For example, to handle 'stream' messaged, define
  6. a '_handle_stream(msg)' method.
  7. """
  8. #---------------------------------------------------------------------------
  9. # 'BaseFrontendMixin' concrete interface
  10. #---------------------------------------------------------------------------
  11. _kernel_client = None
  12. _kernel_manager = None
  13. @property
  14. def kernel_client(self):
  15. """Returns the current kernel client."""
  16. return self._kernel_client
  17. @kernel_client.setter
  18. def kernel_client(self, kernel_client):
  19. """Disconnect from the current kernel client (if any) and set a new
  20. kernel client.
  21. """
  22. # Disconnect the old kernel client, if necessary.
  23. old_client = self._kernel_client
  24. if old_client is not None:
  25. old_client.started_channels.disconnect(self._started_channels)
  26. old_client.stopped_channels.disconnect(self._stopped_channels)
  27. # Disconnect the old kernel client's channels.
  28. old_client.iopub_channel.message_received.disconnect(self._dispatch)
  29. old_client.shell_channel.message_received.disconnect(self._dispatch)
  30. old_client.stdin_channel.message_received.disconnect(self._dispatch)
  31. old_client.hb_channel.kernel_died.disconnect(
  32. self._handle_kernel_died)
  33. # Handle the case where the old kernel client is still listening.
  34. if old_client.channels_running:
  35. self._stopped_channels()
  36. # Set the new kernel client.
  37. self._kernel_client = kernel_client
  38. if kernel_client is None:
  39. return
  40. # Connect the new kernel client.
  41. kernel_client.started_channels.connect(self._started_channels)
  42. kernel_client.stopped_channels.connect(self._stopped_channels)
  43. # Connect the new kernel client's channels.
  44. kernel_client.iopub_channel.message_received.connect(self._dispatch)
  45. kernel_client.shell_channel.message_received.connect(self._dispatch)
  46. kernel_client.stdin_channel.message_received.connect(self._dispatch)
  47. # hb_channel
  48. kernel_client.hb_channel.kernel_died.connect(self._handle_kernel_died)
  49. # Handle the case where the kernel client started channels before
  50. # we connected.
  51. if kernel_client.channels_running:
  52. self._started_channels()
  53. @property
  54. def kernel_manager(self):
  55. """The kernel manager, if any"""
  56. return self._kernel_manager
  57. @kernel_manager.setter
  58. def kernel_manager(self, kernel_manager):
  59. old_man = self._kernel_manager
  60. if old_man is not None:
  61. old_man.kernel_restarted.disconnect(self._handle_kernel_restarted)
  62. self._kernel_manager = kernel_manager
  63. if kernel_manager is None:
  64. return
  65. kernel_manager.kernel_restarted.connect(self._handle_kernel_restarted)
  66. #---------------------------------------------------------------------------
  67. # 'BaseFrontendMixin' abstract interface
  68. #---------------------------------------------------------------------------
  69. def _handle_kernel_died(self, since_last_heartbeat):
  70. """ This is called when the ``kernel_died`` signal is emitted.
  71. This method is called when the kernel heartbeat has not been
  72. active for a certain amount of time.
  73. This is a strictly passive notification -
  74. the kernel is likely being restarted by its KernelManager.
  75. Parameters
  76. ----------
  77. since_last_heartbeat : float
  78. The time since the heartbeat was last received.
  79. """
  80. def _handle_kernel_restarted(self):
  81. """ This is called when the ``kernel_restarted`` signal is emitted.
  82. This method is called when the kernel has been restarted by the
  83. autorestart mechanism.
  84. Parameters
  85. ----------
  86. since_last_heartbeat : float
  87. The time since the heartbeat was last received.
  88. """
  89. def _started_kernel(self):
  90. """Called when the KernelManager starts (or restarts) the kernel subprocess.
  91. Channels may or may not be running at this point.
  92. """
  93. def _started_channels(self):
  94. """ Called when the KernelManager channels have started listening or
  95. when the frontend is assigned an already listening KernelManager.
  96. """
  97. def _stopped_channels(self):
  98. """ Called when the KernelManager channels have stopped listening or
  99. when a listening KernelManager is removed from the frontend.
  100. """
  101. #---------------------------------------------------------------------------
  102. # 'BaseFrontendMixin' protected interface
  103. #---------------------------------------------------------------------------
  104. def _dispatch(self, msg):
  105. """ Calls the frontend handler associated with the message type of the
  106. given message.
  107. """
  108. msg_type = msg['header']['msg_type']
  109. handler = getattr(self, '_handle_' + msg_type, None)
  110. if handler:
  111. handler(msg)
  112. def from_here(self, msg):
  113. """Return whether a message is from this session"""
  114. session_id = self._kernel_client.session.session
  115. return msg['parent_header'].get("session", session_id) == session_id
  116. def include_output(self, msg):
  117. """Return whether we should include a given output message"""
  118. if self._hidden:
  119. return False
  120. from_here = self.from_here(msg)
  121. if msg['msg_type'] == 'execute_input':
  122. # only echo inputs not from here
  123. return self.include_other_output and not from_here
  124. if self.include_other_output:
  125. return True
  126. else:
  127. return from_here