client.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. """A client for in-process kernels."""
  2. #-----------------------------------------------------------------------------
  3. # Copyright (C) 2012 The IPython Development Team
  4. #
  5. # Distributed under the terms of the BSD License. The full license is in
  6. # the file COPYING, distributed as part of this software.
  7. #-----------------------------------------------------------------------------
  8. #-----------------------------------------------------------------------------
  9. # Imports
  10. #-----------------------------------------------------------------------------
  11. # IPython imports
  12. from ipykernel.inprocess.socket import DummySocket
  13. from traitlets import Type, Instance, default
  14. from jupyter_client.clientabc import KernelClientABC
  15. from jupyter_client.client import KernelClient
  16. # Local imports
  17. from .channels import (
  18. InProcessChannel,
  19. InProcessHBChannel,
  20. )
  21. #-----------------------------------------------------------------------------
  22. # Main kernel Client class
  23. #-----------------------------------------------------------------------------
  24. class InProcessKernelClient(KernelClient):
  25. """A client for an in-process kernel.
  26. This class implements the interface of
  27. `jupyter_client.clientabc.KernelClientABC` and allows
  28. (asynchronous) frontends to be used seamlessly with an in-process kernel.
  29. See `jupyter_client.client.KernelClient` for docstrings.
  30. """
  31. # The classes to use for the various channels.
  32. shell_channel_class = Type(InProcessChannel)
  33. iopub_channel_class = Type(InProcessChannel)
  34. stdin_channel_class = Type(InProcessChannel)
  35. hb_channel_class = Type(InProcessHBChannel)
  36. kernel = Instance('ipykernel.inprocess.ipkernel.InProcessKernel',
  37. allow_none=True)
  38. #--------------------------------------------------------------------------
  39. # Channel management methods
  40. #--------------------------------------------------------------------------
  41. @default('blocking_class')
  42. def _default_blocking_class(self):
  43. from .blocking import BlockingInProcessKernelClient
  44. return BlockingInProcessKernelClient
  45. def get_connection_info(self):
  46. d = super(InProcessKernelClient, self).get_connection_info()
  47. d['kernel'] = self.kernel
  48. return d
  49. def start_channels(self, *args, **kwargs):
  50. super(InProcessKernelClient, self).start_channels()
  51. self.kernel.frontends.append(self)
  52. @property
  53. def shell_channel(self):
  54. if self._shell_channel is None:
  55. self._shell_channel = self.shell_channel_class(self)
  56. return self._shell_channel
  57. @property
  58. def iopub_channel(self):
  59. if self._iopub_channel is None:
  60. self._iopub_channel = self.iopub_channel_class(self)
  61. return self._iopub_channel
  62. @property
  63. def stdin_channel(self):
  64. if self._stdin_channel is None:
  65. self._stdin_channel = self.stdin_channel_class(self)
  66. return self._stdin_channel
  67. @property
  68. def hb_channel(self):
  69. if self._hb_channel is None:
  70. self._hb_channel = self.hb_channel_class(self)
  71. return self._hb_channel
  72. # Methods for sending specific messages
  73. # -------------------------------------
  74. def execute(self, code, silent=False, store_history=True,
  75. user_expressions={}, allow_stdin=None):
  76. if allow_stdin is None:
  77. allow_stdin = self.allow_stdin
  78. content = dict(code=code, silent=silent, store_history=store_history,
  79. user_expressions=user_expressions,
  80. allow_stdin=allow_stdin)
  81. msg = self.session.msg('execute_request', content)
  82. self._dispatch_to_kernel(msg)
  83. return msg['header']['msg_id']
  84. def complete(self, code, cursor_pos=None):
  85. if cursor_pos is None:
  86. cursor_pos = len(code)
  87. content = dict(code=code, cursor_pos=cursor_pos)
  88. msg = self.session.msg('complete_request', content)
  89. self._dispatch_to_kernel(msg)
  90. return msg['header']['msg_id']
  91. def inspect(self, code, cursor_pos=None, detail_level=0):
  92. if cursor_pos is None:
  93. cursor_pos = len(code)
  94. content = dict(code=code, cursor_pos=cursor_pos,
  95. detail_level=detail_level,
  96. )
  97. msg = self.session.msg('inspect_request', content)
  98. self._dispatch_to_kernel(msg)
  99. return msg['header']['msg_id']
  100. def history(self, raw=True, output=False, hist_access_type='range', **kwds):
  101. content = dict(raw=raw, output=output,
  102. hist_access_type=hist_access_type, **kwds)
  103. msg = self.session.msg('history_request', content)
  104. self._dispatch_to_kernel(msg)
  105. return msg['header']['msg_id']
  106. def shutdown(self, restart=False):
  107. # FIXME: What to do here?
  108. raise NotImplementedError('Cannot shutdown in-process kernel')
  109. def kernel_info(self):
  110. """Request kernel info."""
  111. msg = self.session.msg('kernel_info_request')
  112. self._dispatch_to_kernel(msg)
  113. return msg['header']['msg_id']
  114. def comm_info(self, target_name=None):
  115. """Request a dictionary of valid comms and their targets."""
  116. if target_name is None:
  117. content = {}
  118. else:
  119. content = dict(target_name=target_name)
  120. msg = self.session.msg('comm_info_request', content)
  121. self._dispatch_to_kernel(msg)
  122. return msg['header']['msg_id']
  123. def input(self, string):
  124. if self.kernel is None:
  125. raise RuntimeError('Cannot send input reply. No kernel exists.')
  126. self.kernel.raw_input_str = string
  127. def is_complete(self, code):
  128. msg = self.session.msg('is_complete_request', {'code': code})
  129. self._dispatch_to_kernel(msg)
  130. return msg['header']['msg_id']
  131. def _dispatch_to_kernel(self, msg):
  132. """ Send a message to the kernel and handle a reply.
  133. """
  134. kernel = self.kernel
  135. if kernel is None:
  136. raise RuntimeError('Cannot send request. No kernel exists.')
  137. stream = DummySocket()
  138. self.session.send(stream, msg)
  139. msg_parts = stream.recv_multipart()
  140. kernel.dispatch_shell(stream, msg_parts)
  141. idents, reply_msg = self.session.recv(stream, copy=False)
  142. self.shell_channel.call_handlers_later(reply_msg)
  143. #-----------------------------------------------------------------------------
  144. # ABC Registration
  145. #-----------------------------------------------------------------------------
  146. KernelClientABC.register(InProcessKernelClient)