##// END OF EJS Templates
Collapse Qt in-process channel classes together
Thomas Kluyver -
Show More
@@ -1,196 +1,111 b''
1 1 """A kernel client for in-process kernels."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from IPython.kernel.channelsabc import (
7 7 ShellChannelABC, IOPubChannelABC,
8 8 HBChannelABC, StdInChannelABC,
9 9 )
10 10
11 11 from .socket import DummySocket
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Channel classes
15 15 #-----------------------------------------------------------------------------
16 16
17 17 class InProcessChannel(object):
18 18 """Base class for in-process channels."""
19 19 proxy_methods = []
20 20
21 21 def __init__(self, client=None):
22 22 super(InProcessChannel, self).__init__()
23 23 self.client = client
24 24 self._is_alive = False
25 25
26 26 #--------------------------------------------------------------------------
27 27 # Channel interface
28 28 #--------------------------------------------------------------------------
29 29
30 30 def is_alive(self):
31 31 return self._is_alive
32 32
33 33 def start(self):
34 34 self._is_alive = True
35 35
36 36 def stop(self):
37 37 self._is_alive = False
38 38
39 39 def call_handlers(self, msg):
40 40 """ This method is called in the main thread when a message arrives.
41 41
42 42 Subclasses should override this method to handle incoming messages.
43 43 """
44 44 raise NotImplementedError('call_handlers must be defined in a subclass.')
45 45
46 def flush(self, timeout=1.0):
47 pass
48
46 49 #--------------------------------------------------------------------------
47 50 # InProcessChannel interface
48 51 #--------------------------------------------------------------------------
49 52
50 53 def call_handlers_later(self, *args, **kwds):
51 54 """ Call the message handlers later.
52 55
53 56 The default implementation just calls the handlers immediately, but this
54 57 method exists so that GUI toolkits can defer calling the handlers until
55 58 after the event loop has run, as expected by GUI frontends.
56 59 """
57 60 self.call_handlers(*args, **kwds)
58 61
59 62 def process_events(self):
60 63 """ Process any pending GUI events.
61 64
62 65 This method will be never be called from a frontend without an event
63 66 loop (e.g., a terminal frontend).
64 67 """
65 68 raise NotImplementedError
66 69
67 70
68 71 class InProcessShellChannel(InProcessChannel):
69 72 """See `IPython.kernel.channels.ShellChannel` for docstrings."""
70 73
71 74 # flag for whether execute requests should be allowed to call raw_input
72 75 allow_stdin = True
73 proxy_methods = [
74 'execute',
75 'complete',
76 'inspect',
77 'history',
78 'shutdown',
79 'kernel_info',
80 ]
81
82 #--------------------------------------------------------------------------
83 # ShellChannel interface
84 #--------------------------------------------------------------------------
85
86 def execute(self, code, silent=False, store_history=True,
87 user_expressions={}, allow_stdin=None):
88 if allow_stdin is None:
89 allow_stdin = self.allow_stdin
90 content = dict(code=code, silent=silent, store_history=store_history,
91 user_expressions=user_expressions,
92 allow_stdin=allow_stdin)
93 msg = self.client.session.msg('execute_request', content)
94 self._dispatch_to_kernel(msg)
95 return msg['header']['msg_id']
96
97 def complete(self, code, cursor_pos=None):
98 if cursor_pos is None:
99 cursor_pos = len(code)
100 content = dict(code=code, cursor_pos=cursor_pos)
101 msg = self.client.session.msg('complete_request', content)
102 self._dispatch_to_kernel(msg)
103 return msg['header']['msg_id']
104
105 def inspect(self, code, cursor_pos=None, detail_level=0):
106 if cursor_pos is None:
107 cursor_pos = len(code)
108 content = dict(code=code, cursor_pos=cursor_pos,
109 detail_level=detail_level,
110 )
111 msg = self.client.session.msg('inspect_request', content)
112 self._dispatch_to_kernel(msg)
113 return msg['header']['msg_id']
114
115 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
116 content = dict(raw=raw, output=output,
117 hist_access_type=hist_access_type, **kwds)
118 msg = self.client.session.msg('history_request', content)
119 self._dispatch_to_kernel(msg)
120 return msg['header']['msg_id']
121
122 def shutdown(self, restart=False):
123 # FIXME: What to do here?
124 raise NotImplementedError('Cannot shutdown in-process kernel')
125
126 def kernel_info(self):
127 """Request kernel info."""
128 msg = self.client.session.msg('kernel_info_request')
129 self._dispatch_to_kernel(msg)
130 return msg['header']['msg_id']
131
132 #--------------------------------------------------------------------------
133 # Protected interface
134 #--------------------------------------------------------------------------
135
136 def _dispatch_to_kernel(self, msg):
137 """ Send a message to the kernel and handle a reply.
138 """
139 kernel = self.client.kernel
140 if kernel is None:
141 raise RuntimeError('Cannot send request. No kernel exists.')
142
143 stream = DummySocket()
144 self.client.session.send(stream, msg)
145 msg_parts = stream.recv_multipart()
146 kernel.dispatch_shell(stream, msg_parts)
147
148 idents, reply_msg = self.client.session.recv(stream, copy=False)
149 self.call_handlers_later(reply_msg)
150
151 76
152 77 class InProcessIOPubChannel(InProcessChannel):
153 78 """See `IPython.kernel.channels.IOPubChannel` for docstrings."""
154 79
155 def flush(self, timeout=1.0):
156 pass
157
158 80
159 81 class InProcessStdInChannel(InProcessChannel):
160 82 """See `IPython.kernel.channels.StdInChannel` for docstrings."""
161 83
162 proxy_methods = ['input']
163
164 def input(self, string):
165 kernel = self.client.kernel
166 if kernel is None:
167 raise RuntimeError('Cannot send input reply. No kernel exists.')
168 kernel.raw_input_str = string
169 84
170 85
171 86 class InProcessHBChannel(InProcessChannel):
172 87 """See `IPython.kernel.channels.HBChannel` for docstrings."""
173 88
174 89 time_to_dead = 3.0
175 90
176 91 def __init__(self, *args, **kwds):
177 92 super(InProcessHBChannel, self).__init__(*args, **kwds)
178 93 self._pause = True
179 94
180 95 def pause(self):
181 96 self._pause = True
182 97
183 98 def unpause(self):
184 99 self._pause = False
185 100
186 101 def is_beating(self):
187 102 return not self._pause
188 103
189 104 #-----------------------------------------------------------------------------
190 105 # ABC Registration
191 106 #-----------------------------------------------------------------------------
192 107
193 108 ShellChannelABC.register(InProcessShellChannel)
194 109 IOPubChannelABC.register(InProcessIOPubChannel)
195 110 HBChannelABC.register(InProcessHBChannel)
196 111 StdInChannelABC.register(InProcessStdInChannel)
@@ -1,87 +1,158 b''
1 1 """A client for in-process kernels."""
2 2
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (C) 2012 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13
14 14 # IPython imports
15 from IPython.kernel.inprocess.socket import DummySocket
15 16 from IPython.utils.traitlets import Type, Instance
16 17 from IPython.kernel.clientabc import KernelClientABC
17 18 from IPython.kernel.client import KernelClient
18 19
19 20 # Local imports
20 21 from .channels import (
21 22 InProcessShellChannel,
22 23 InProcessIOPubChannel,
23 24 InProcessHBChannel,
24 25 InProcessStdInChannel,
25 26
26 27 )
27 28
28 29 #-----------------------------------------------------------------------------
29 30 # Main kernel Client class
30 31 #-----------------------------------------------------------------------------
31 32
32 33 class InProcessKernelClient(KernelClient):
33 34 """A client for an in-process kernel.
34 35
35 36 This class implements the interface of
36 37 `IPython.kernel.clientabc.KernelClientABC` and allows
37 38 (asynchronous) frontends to be used seamlessly with an in-process kernel.
38 39
39 40 See `IPython.kernel.client.KernelClient` for docstrings.
40 41 """
41 42
42 43 # The classes to use for the various channels.
43 44 shell_channel_class = Type(InProcessShellChannel)
44 45 iopub_channel_class = Type(InProcessIOPubChannel)
45 46 stdin_channel_class = Type(InProcessStdInChannel)
46 47 hb_channel_class = Type(InProcessHBChannel)
47 48
48 49 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel')
49 50
50 51 #--------------------------------------------------------------------------
51 52 # Channel management methods
52 53 #--------------------------------------------------------------------------
53 54
54 55 def start_channels(self, *args, **kwargs):
55 56 super(InProcessKernelClient, self).start_channels(self)
56 57 self.kernel.frontends.append(self)
57 58
58 59 @property
59 60 def shell_channel(self):
60 61 if self._shell_channel is None:
61 62 self._shell_channel = self.shell_channel_class(self)
62 63 return self._shell_channel
63 64
64 65 @property
65 66 def iopub_channel(self):
66 67 if self._iopub_channel is None:
67 68 self._iopub_channel = self.iopub_channel_class(self)
68 69 return self._iopub_channel
69 70
70 71 @property
71 72 def stdin_channel(self):
72 73 if self._stdin_channel is None:
73 74 self._stdin_channel = self.stdin_channel_class(self)
74 75 return self._stdin_channel
75 76
76 77 @property
77 78 def hb_channel(self):
78 79 if self._hb_channel is None:
79 80 self._hb_channel = self.hb_channel_class(self)
80 81 return self._hb_channel
81 82
83 # Methods for sending specific messages
84 # -------------------------------------
85
86 def execute(self, code, silent=False, store_history=True,
87 user_expressions={}, allow_stdin=None):
88 if allow_stdin is None:
89 allow_stdin = self.allow_stdin
90 content = dict(code=code, silent=silent, store_history=store_history,
91 user_expressions=user_expressions,
92 allow_stdin=allow_stdin)
93 msg = self.session.msg('execute_request', content)
94 self._dispatch_to_kernel(msg)
95 return msg['header']['msg_id']
96
97 def complete(self, code, cursor_pos=None):
98 if cursor_pos is None:
99 cursor_pos = len(code)
100 content = dict(code=code, cursor_pos=cursor_pos)
101 msg = self.session.msg('complete_request', content)
102 self._dispatch_to_kernel(msg)
103 return msg['header']['msg_id']
104
105 def inspect(self, code, cursor_pos=None, detail_level=0):
106 if cursor_pos is None:
107 cursor_pos = len(code)
108 content = dict(code=code, cursor_pos=cursor_pos,
109 detail_level=detail_level,
110 )
111 msg = self.session.msg('inspect_request', content)
112 self._dispatch_to_kernel(msg)
113 return msg['header']['msg_id']
114
115 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
116 content = dict(raw=raw, output=output,
117 hist_access_type=hist_access_type, **kwds)
118 msg = self.session.msg('history_request', content)
119 self._dispatch_to_kernel(msg)
120 return msg['header']['msg_id']
121
122 def shutdown(self, restart=False):
123 # FIXME: What to do here?
124 raise NotImplementedError('Cannot shutdown in-process kernel')
125
126 def kernel_info(self):
127 """Request kernel info."""
128 msg = self.session.msg('kernel_info_request')
129 self._dispatch_to_kernel(msg)
130 return msg['header']['msg_id']
131
132 def input(self, string):
133 if self.kernel is None:
134 raise RuntimeError('Cannot send input reply. No kernel exists.')
135 self.kernel.raw_input_str = string
136
137
138 def _dispatch_to_kernel(self, msg):
139 """ Send a message to the kernel and handle a reply.
140 """
141 kernel = self.kernel
142 if kernel is None:
143 raise RuntimeError('Cannot send request. No kernel exists.')
144
145 stream = DummySocket()
146 self.session.send(stream, msg)
147 msg_parts = stream.recv_multipart()
148 kernel.dispatch_shell(stream, msg_parts)
149
150 idents, reply_msg = self.session.recv(stream, copy=False)
151 self.shell_channel.call_handlers_later(reply_msg)
152
82 153
83 154 #-----------------------------------------------------------------------------
84 155 # ABC Registration
85 156 #-----------------------------------------------------------------------------
86 157
87 158 KernelClientABC.register(InProcessKernelClient)
@@ -1,115 +1,33 b''
1 1 """ Defines an in-process KernelManager with signals and slots.
2 2 """
3 3
4 4 # Local imports.
5 5 from IPython.external.qt import QtCore
6 6 from IPython.kernel.inprocess import (
7 InProcessShellChannel, InProcessIOPubChannel, InProcessStdInChannel,
8 7 InProcessHBChannel, InProcessKernelClient, InProcessKernelManager,
9 8 )
9 from IPython.kernel.inprocess.channels import InProcessChannel
10 10
11 11 from IPython.utils.traitlets import Type
12 12 from .kernel_mixins import ( ChannelQObject,
13 13 QtHBChannelMixin, QtKernelClientMixin,
14 14 QtKernelManagerMixin,
15 15 )
16 16
17
18 class QtInProcessShellChannel(ChannelQObject, InProcessShellChannel):
19 # Emitted when a reply has been received for the corresponding request type.
20 execute_reply = QtCore.Signal(object)
21 complete_reply = QtCore.Signal(object)
22 inspect_reply = QtCore.Signal(object)
23 history_reply = QtCore.Signal(object)
24 kernel_info_reply = QtCore.Signal(object)
25
26 def call_handlers(self, msg):
27 """ Reimplemented to emit signals instead of making callbacks.
28 """
29 # Emit the generic signal.
30 self.message_received.emit(msg)
31
32 # Emit signals for specialized message types.
33 msg_type = msg['header']['msg_type']
34 if msg_type == 'kernel_info_reply':
35 self._handle_kernel_info_reply(msg)
36
37 signal = getattr(self, msg_type, None)
38 if signal:
39 signal.emit(msg)
40
41 class QtInProcessIOPubChannel(ChannelQObject, InProcessIOPubChannel):
42 # Emitted when a message of type 'stream' is received.
43 stream_received = QtCore.Signal(object)
44
45 # Emitted when a message of type 'execute_input' is received.
46 execute_input_received = QtCore.Signal(object)
47
48 # Emitted when a message of type 'execute_result' is received.
49 execute_result_received = QtCore.Signal(object)
50
51 # Emitted when a message of type 'error' is received.
52 error_received = QtCore.Signal(object)
53
54 # Emitted when a message of type 'display_data' is received
55 display_data_received = QtCore.Signal(object)
56
57 # Emitted when a crash report message is received from the kernel's
58 # last-resort sys.excepthook.
59 crash_received = QtCore.Signal(object)
60
61 # Emitted when a shutdown is noticed.
62 shutdown_reply_received = QtCore.Signal(object)
63
64 #---------------------------------------------------------------------------
65 # 'IOPubChannel' interface
66 #---------------------------------------------------------------------------
67
68 def call_handlers(self, msg):
69 """ Reimplemented to emit signals instead of making callbacks.
70 """
71 # Emit the generic signal.
72 self.message_received.emit(msg)
73 # Emit signals for specialized message types.
74 msg_type = msg['header']['msg_type']
75 signal = getattr(self, msg_type + '_received', None)
76 if signal:
77 signal.emit(msg)
78 elif msg_type in ('stdout', 'stderr'):
79 self.stream_received.emit(msg)
80
81 def flush(self):
82 """ Reimplemented to ensure that signals are dispatched immediately.
83 """
84 super(QtInProcessIOPubChannel, self).flush()
85 QtCore.QCoreApplication.instance().processEvents()
86
87 class QtInProcessStdInChannel(ChannelQObject, InProcessStdInChannel):
88 # Emitted when an input request is received.
89 input_requested = QtCore.Signal(object)
90
91 def call_handlers(self, msg):
92 """ Reimplemented to emit signals instead of making callbacks.
93 """
94 # Emit the generic signal.
95 self.message_received.emit(msg)
96
97 # Emit signals for specialized message types.
98 msg_type = msg['header']['msg_type']
99 if msg_type == 'input_request':
100 self.input_requested.emit(msg)
17 class QtInProcessChannel(ChannelQObject, InProcessChannel):
18 pass
101 19
102 20 class QtInProcessHBChannel(QtHBChannelMixin, InProcessHBChannel):
103 21 pass
104 22
105 23 class QtInProcessKernelClient(QtKernelClientMixin, InProcessKernelClient):
106 24 """ An in-process KernelManager with signals and slots.
107 25 """
108 26
109 iopub_channel_class = Type(QtInProcessIOPubChannel)
110 shell_channel_class = Type(QtInProcessShellChannel)
111 stdin_channel_class = Type(QtInProcessStdInChannel)
27 iopub_channel_class = Type(QtInProcessChannel)
28 shell_channel_class = Type(QtInProcessChannel)
29 stdin_channel_class = Type(QtInProcessChannel)
112 30 hb_channel_class = Type(QtInProcessHBChannel)
113 31
114 32 class QtInProcessKernelManager(QtKernelManagerMixin, InProcessKernelManager):
115 33 client_class = __module__ + '.QtInProcessKernelClient'
@@ -1,104 +1,105 b''
1 1 """Defines a KernelManager that provides signals and slots."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from IPython.external.qt import QtCore
7 7
8 8 from IPython.utils.traitlets import HasTraits, Type
9 9 from .util import MetaQObjectHasTraits, SuperQObject
10 10
11 11
12 12 class ChannelQObject(SuperQObject):
13 13
14 14 # Emitted when the channel is started.
15 15 started = QtCore.Signal()
16 16
17 17 # Emitted when the channel is stopped.
18 18 stopped = QtCore.Signal()
19 19
20 20 # Emitted when any message is received.
21 21 message_received = QtCore.Signal(object)
22 22
23 #---------------------------------------------------------------------------
24 # Channel interface
25 #---------------------------------------------------------------------------
26
27 23 def start(self):
28 24 """ Reimplemented to emit signal.
29 25 """
30 26 super(ChannelQObject, self).start()
31 27 self.started.emit()
32 28
33 29 def stop(self):
34 30 """ Reimplemented to emit signal.
35 31 """
36 32 super(ChannelQObject, self).stop()
37 33 self.stopped.emit()
38 34
39 #---------------------------------------------------------------------------
40 # InProcessChannel interface
41 #---------------------------------------------------------------------------
42
43 35 def call_handlers_later(self, *args, **kwds):
44 36 """ Call the message handlers later.
45 37 """
46 38 do_later = lambda: self.call_handlers(*args, **kwds)
47 39 QtCore.QTimer.singleShot(0, do_later)
48 40
41 def call_handlers(self, msg):
42 self.message_received.emit(msg)
43
49 44 def process_events(self):
50 45 """ Process any pending GUI events.
51 46 """
52 47 QtCore.QCoreApplication.instance().processEvents()
53 48
49 def flush(self):
50 """ Reimplemented to ensure that signals are dispatched immediately.
51 """
52 super(ChannelQObject, self).flush()
53 self.process_events()
54
54 55
55 56 class QtHBChannelMixin(ChannelQObject):
56 57
57 58 # Emitted when the kernel has died.
58 59 kernel_died = QtCore.Signal(object)
59 60
60 61 def call_handlers(self, since_last_heartbeat):
61 62 """ Reimplemented to emit signals instead of making callbacks.
62 63 """
63 64 self.kernel_died.emit(since_last_heartbeat)
64 65
65 66
66 67 class QtKernelRestarterMixin(MetaQObjectHasTraits('NewBase', (HasTraits, SuperQObject), {})):
67 68
68 69 _timer = None
69 70
70 71
71 72 class QtKernelManagerMixin(MetaQObjectHasTraits('NewBase', (HasTraits, SuperQObject), {})):
72 73 """ A KernelClient that provides signals and slots.
73 74 """
74 75
75 76 kernel_restarted = QtCore.Signal()
76 77
77 78
78 79 class QtKernelClientMixin(MetaQObjectHasTraits('NewBase', (HasTraits, SuperQObject), {})):
79 80 """ A KernelClient that provides signals and slots.
80 81 """
81 82
82 83 # Emitted when the kernel client has started listening.
83 84 started_channels = QtCore.Signal()
84 85
85 86 # Emitted when the kernel client has stopped listening.
86 87 stopped_channels = QtCore.Signal()
87 88
88 89 #---------------------------------------------------------------------------
89 90 # 'KernelClient' interface
90 91 #---------------------------------------------------------------------------
91 92
92 93 #------ Channel management -------------------------------------------------
93 94
94 95 def start_channels(self, *args, **kw):
95 96 """ Reimplemented to emit signal.
96 97 """
97 98 super(QtKernelClientMixin, self).start_channels(*args, **kw)
98 99 self.started_channels.emit()
99 100
100 101 def stop_channels(self):
101 102 """ Reimplemented to emit signal.
102 103 """
103 104 super(QtKernelClientMixin, self).stop_channels()
104 105 self.stopped_channels.emit()
General Comments 0
You need to be logged in to leave comments. Login now