Show More
@@ -1,198 +1,206 b'' | |||||
1 | """Base class to manage the interaction with a running kernel |
|
1 | """Base class to manage the interaction with a running kernel | |
2 | """ |
|
2 | """ | |
3 |
|
3 | |||
4 | #----------------------------------------------------------------------------- |
|
4 | #----------------------------------------------------------------------------- | |
5 | # Copyright (C) 2013 The IPython Development Team |
|
5 | # Copyright (C) 2013 The IPython Development Team | |
6 | # |
|
6 | # | |
7 | # Distributed under the terms of the BSD License. The full license is in |
|
7 | # Distributed under the terms of the BSD License. The full license is in | |
8 | # the file COPYING, distributed as part of this software. |
|
8 | # the file COPYING, distributed as part of this software. | |
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Imports |
|
12 | # Imports | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 |
|
14 | |||
15 | from __future__ import absolute_import |
|
15 | from __future__ import absolute_import | |
16 |
|
16 | |||
17 | import zmq |
|
17 | import zmq | |
18 |
|
18 | |||
19 | # Local imports |
|
19 | # Local imports | |
20 | from IPython.config.configurable import LoggingConfigurable |
|
20 | from IPython.config.configurable import LoggingConfigurable | |
21 | from IPython.utils.traitlets import ( |
|
21 | from IPython.utils.traitlets import ( | |
22 | Any, Instance, Type, |
|
22 | Any, Instance, Type, | |
23 | ) |
|
23 | ) | |
24 |
|
24 | |||
25 | from .zmq.session import Session |
|
25 | from .zmq.session import Session | |
26 | from .channels import ( |
|
26 | from .channels import ( | |
27 | ShellChannel, IOPubChannel, |
|
27 | ShellChannel, IOPubChannel, | |
28 | HBChannel, StdInChannel, |
|
28 | HBChannel, StdInChannel, | |
29 | ) |
|
29 | ) | |
30 | from .clientabc import KernelClientABC |
|
30 | from .clientabc import KernelClientABC | |
31 | from .connect import ConnectionFileMixin |
|
31 | from .connect import ConnectionFileMixin | |
32 |
|
32 | |||
33 |
|
33 | |||
34 | #----------------------------------------------------------------------------- |
|
34 | #----------------------------------------------------------------------------- | |
35 | # Main kernel client class |
|
35 | # Main kernel client class | |
36 | #----------------------------------------------------------------------------- |
|
36 | #----------------------------------------------------------------------------- | |
37 |
|
37 | |||
38 | class KernelClient(LoggingConfigurable, ConnectionFileMixin): |
|
38 | class KernelClient(LoggingConfigurable, ConnectionFileMixin): | |
39 | """Communicates with a single kernel on any host via zmq channels. |
|
39 | """Communicates with a single kernel on any host via zmq channels. | |
40 |
|
40 | |||
41 | There are four channels associated with each kernel: |
|
41 | There are four channels associated with each kernel: | |
42 |
|
42 | |||
43 | * shell: for request/reply calls to the kernel. |
|
43 | * shell: for request/reply calls to the kernel. | |
44 | * iopub: for the kernel to publish results to frontends. |
|
44 | * iopub: for the kernel to publish results to frontends. | |
45 | * hb: for monitoring the kernel's heartbeat. |
|
45 | * hb: for monitoring the kernel's heartbeat. | |
46 | * stdin: for frontends to reply to raw_input calls in the kernel. |
|
46 | * stdin: for frontends to reply to raw_input calls in the kernel. | |
47 |
|
47 | |||
48 | The methods of the channels are exposed as methods of the client itself |
|
48 | The methods of the channels are exposed as methods of the client itself | |
49 | (KernelClient.execute, complete, history, etc.). |
|
49 | (KernelClient.execute, complete, history, etc.). | |
50 | See the channels themselves for documentation of these methods. |
|
50 | See the channels themselves for documentation of these methods. | |
51 |
|
51 | |||
52 | """ |
|
52 | """ | |
53 |
|
53 | |||
54 | # The PyZMQ Context to use for communication with the kernel. |
|
54 | # The PyZMQ Context to use for communication with the kernel. | |
55 | context = Instance(zmq.Context) |
|
55 | context = Instance(zmq.Context) | |
56 | def _context_default(self): |
|
56 | def _context_default(self): | |
57 | return zmq.Context.instance() |
|
57 | return zmq.Context.instance() | |
58 |
|
58 | |||
59 | # The Session to use for communication with the kernel. |
|
59 | # The Session to use for communication with the kernel. | |
60 | session = Instance(Session) |
|
60 | session = Instance(Session) | |
61 | def _session_default(self): |
|
61 | def _session_default(self): | |
62 | return Session(parent=self) |
|
62 | return Session(parent=self) | |
63 |
|
63 | |||
64 | # The classes to use for the various channels |
|
64 | # The classes to use for the various channels | |
65 | shell_channel_class = Type(ShellChannel) |
|
65 | shell_channel_class = Type(ShellChannel) | |
66 | iopub_channel_class = Type(IOPubChannel) |
|
66 | iopub_channel_class = Type(IOPubChannel) | |
67 | stdin_channel_class = Type(StdInChannel) |
|
67 | stdin_channel_class = Type(StdInChannel) | |
68 | hb_channel_class = Type(HBChannel) |
|
68 | hb_channel_class = Type(HBChannel) | |
69 |
|
69 | |||
70 | # Protected traits |
|
70 | # Protected traits | |
71 | _shell_channel = Any |
|
71 | _shell_channel = Any | |
72 | _iopub_channel = Any |
|
72 | _iopub_channel = Any | |
73 | _stdin_channel = Any |
|
73 | _stdin_channel = Any | |
74 | _hb_channel = Any |
|
74 | _hb_channel = Any | |
75 |
|
75 | |||
76 | #-------------------------------------------------------------------------- |
|
76 | #-------------------------------------------------------------------------- | |
77 | # Channel proxy methods |
|
77 | # Channel proxy methods | |
78 | #-------------------------------------------------------------------------- |
|
78 | #-------------------------------------------------------------------------- | |
79 |
|
79 | |||
80 | def _get_msg(channel, *args, **kwargs): |
|
80 | def _get_msg(channel, *args, **kwargs): | |
81 | return channel.get_msg(*args, **kwargs) |
|
81 | return channel.get_msg(*args, **kwargs) | |
82 |
|
82 | |||
83 | def get_shell_msg(self, *args, **kwargs): |
|
83 | def get_shell_msg(self, *args, **kwargs): | |
84 | """Get a message from the shell channel""" |
|
84 | """Get a message from the shell channel""" | |
85 | return self.shell_channel.get_msg(*args, **kwargs) |
|
85 | return self.shell_channel.get_msg(*args, **kwargs) | |
86 |
|
86 | |||
87 | def get_iopub_msg(self, *args, **kwargs): |
|
87 | def get_iopub_msg(self, *args, **kwargs): | |
88 | """Get a message from the iopub channel""" |
|
88 | """Get a message from the iopub channel""" | |
89 | return self.iopub_channel.get_msg(*args, **kwargs) |
|
89 | return self.iopub_channel.get_msg(*args, **kwargs) | |
90 |
|
90 | |||
91 | def get_stdin_msg(self, *args, **kwargs): |
|
91 | def get_stdin_msg(self, *args, **kwargs): | |
92 | """Get a message from the stdin channel""" |
|
92 | """Get a message from the stdin channel""" | |
93 | return self.stdin_channel.get_msg(*args, **kwargs) |
|
93 | return self.stdin_channel.get_msg(*args, **kwargs) | |
94 |
|
94 | |||
95 | #-------------------------------------------------------------------------- |
|
95 | #-------------------------------------------------------------------------- | |
96 | # Channel management methods |
|
96 | # Channel management methods | |
97 | #-------------------------------------------------------------------------- |
|
97 | #-------------------------------------------------------------------------- | |
98 |
|
98 | |||
99 | def start_channels(self, shell=True, iopub=True, stdin=True, hb=True): |
|
99 | def start_channels(self, shell=True, iopub=True, stdin=True, hb=True): | |
100 | """Starts the channels for this kernel. |
|
100 | """Starts the channels for this kernel. | |
101 |
|
101 | |||
102 | This will create the channels if they do not exist and then start |
|
102 | This will create the channels if they do not exist and then start | |
103 | them (their activity runs in a thread). If port numbers of 0 are |
|
103 | them (their activity runs in a thread). If port numbers of 0 are | |
104 | being used (random ports) then you must first call |
|
104 | being used (random ports) then you must first call | |
105 | :method:`start_kernel`. If the channels have been stopped and you |
|
105 | :method:`start_kernel`. If the channels have been stopped and you | |
106 | call this, :class:`RuntimeError` will be raised. |
|
106 | call this, :class:`RuntimeError` will be raised. | |
107 | """ |
|
107 | """ | |
108 | if shell: |
|
108 | if shell: | |
109 | self.shell_channel.start() |
|
109 | self.shell_channel.start() | |
110 | for method in self.shell_channel.proxy_methods: |
|
110 | for method in self.shell_channel.proxy_methods: | |
111 | setattr(self, method, getattr(self.shell_channel, method)) |
|
111 | setattr(self, method, getattr(self.shell_channel, method)) | |
112 | if iopub: |
|
112 | if iopub: | |
113 | self.iopub_channel.start() |
|
113 | self.iopub_channel.start() | |
114 | for method in self.iopub_channel.proxy_methods: |
|
114 | for method in self.iopub_channel.proxy_methods: | |
115 | setattr(self, method, getattr(self.iopub_channel, method)) |
|
115 | setattr(self, method, getattr(self.iopub_channel, method)) | |
116 | if stdin: |
|
116 | if stdin: | |
117 | self.stdin_channel.start() |
|
117 | self.stdin_channel.start() | |
118 | for method in self.stdin_channel.proxy_methods: |
|
118 | for method in self.stdin_channel.proxy_methods: | |
119 | setattr(self, method, getattr(self.stdin_channel, method)) |
|
119 | setattr(self, method, getattr(self.stdin_channel, method)) | |
120 | self.shell_channel.allow_stdin = True |
|
120 | self.shell_channel.allow_stdin = True | |
121 | else: |
|
121 | else: | |
122 | self.shell_channel.allow_stdin = False |
|
122 | self.shell_channel.allow_stdin = False | |
123 | if hb: |
|
123 | if hb: | |
124 | self.hb_channel.start() |
|
124 | self.hb_channel.start() | |
125 |
|
125 | |||
126 | def stop_channels(self): |
|
126 | def stop_channels(self): | |
127 | """Stops all the running channels for this kernel. |
|
127 | """Stops all the running channels for this kernel. | |
128 |
|
128 | |||
129 | This stops their event loops and joins their threads. |
|
129 | This stops their event loops and joins their threads. | |
130 | """ |
|
130 | """ | |
131 | if self.shell_channel.is_alive(): |
|
131 | if self.shell_channel.is_alive(): | |
132 | self.shell_channel.stop() |
|
132 | self.shell_channel.stop() | |
133 | if self.iopub_channel.is_alive(): |
|
133 | if self.iopub_channel.is_alive(): | |
134 | self.iopub_channel.stop() |
|
134 | self.iopub_channel.stop() | |
135 | if self.stdin_channel.is_alive(): |
|
135 | if self.stdin_channel.is_alive(): | |
136 | self.stdin_channel.stop() |
|
136 | self.stdin_channel.stop() | |
137 | if self.hb_channel.is_alive(): |
|
137 | if self.hb_channel.is_alive(): | |
138 | self.hb_channel.stop() |
|
138 | self.hb_channel.stop() | |
139 |
|
139 | |||
140 | @property |
|
140 | @property | |
141 | def channels_running(self): |
|
141 | def channels_running(self): | |
142 | """Are any of the channels created and running?""" |
|
142 | """Are any of the channels created and running?""" | |
143 | return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or |
|
143 | return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or | |
144 | self.stdin_channel.is_alive() or self.hb_channel.is_alive()) |
|
144 | self.stdin_channel.is_alive() or self.hb_channel.is_alive()) | |
145 |
|
145 | |||
146 | @property |
|
146 | @property | |
147 | def shell_channel(self): |
|
147 | def shell_channel(self): | |
148 | """Get the shell channel object for this kernel.""" |
|
148 | """Get the shell channel object for this kernel.""" | |
149 | if self._shell_channel is None: |
|
149 | if self._shell_channel is None: | |
|
150 | url = self._make_url('shell') | |||
|
151 | self.log.debug("connecting shell channel to %s", url) | |||
150 | self._shell_channel = self.shell_channel_class( |
|
152 | self._shell_channel = self.shell_channel_class( | |
151 |
self.context, self.session, |
|
153 | self.context, self.session, url | |
152 | ) |
|
154 | ) | |
153 | return self._shell_channel |
|
155 | return self._shell_channel | |
154 |
|
156 | |||
155 | @property |
|
157 | @property | |
156 | def iopub_channel(self): |
|
158 | def iopub_channel(self): | |
157 | """Get the iopub channel object for this kernel.""" |
|
159 | """Get the iopub channel object for this kernel.""" | |
158 | if self._iopub_channel is None: |
|
160 | if self._iopub_channel is None: | |
|
161 | url = self._make_url('iopub') | |||
|
162 | self.log.debug("connecting iopub channel to %s", url) | |||
159 | self._iopub_channel = self.iopub_channel_class( |
|
163 | self._iopub_channel = self.iopub_channel_class( | |
160 |
self.context, self.session, |
|
164 | self.context, self.session, url | |
161 | ) |
|
165 | ) | |
162 | return self._iopub_channel |
|
166 | return self._iopub_channel | |
163 |
|
167 | |||
164 | @property |
|
168 | @property | |
165 | def stdin_channel(self): |
|
169 | def stdin_channel(self): | |
166 | """Get the stdin channel object for this kernel.""" |
|
170 | """Get the stdin channel object for this kernel.""" | |
167 | if self._stdin_channel is None: |
|
171 | if self._stdin_channel is None: | |
|
172 | url = self._make_url('stdin') | |||
|
173 | self.log.debug("connecting stdin channel to %s", url) | |||
168 | self._stdin_channel = self.stdin_channel_class( |
|
174 | self._stdin_channel = self.stdin_channel_class( | |
169 |
self.context, self.session, |
|
175 | self.context, self.session, url | |
170 | ) |
|
176 | ) | |
171 | return self._stdin_channel |
|
177 | return self._stdin_channel | |
172 |
|
178 | |||
173 | @property |
|
179 | @property | |
174 | def hb_channel(self): |
|
180 | def hb_channel(self): | |
175 | """Get the hb channel object for this kernel.""" |
|
181 | """Get the hb channel object for this kernel.""" | |
176 | if self._hb_channel is None: |
|
182 | if self._hb_channel is None: | |
|
183 | url = self._make_url('hb') | |||
|
184 | self.log.debug("connecting heartbeat channel to %s", url) | |||
177 | self._hb_channel = self.hb_channel_class( |
|
185 | self._hb_channel = self.hb_channel_class( | |
178 |
self.context, self.session, |
|
186 | self.context, self.session, url | |
179 | ) |
|
187 | ) | |
180 | return self._hb_channel |
|
188 | return self._hb_channel | |
181 |
|
189 | |||
182 | def is_alive(self): |
|
190 | def is_alive(self): | |
183 | """Is the kernel process still running?""" |
|
191 | """Is the kernel process still running?""" | |
184 | if self._hb_channel is not None: |
|
192 | if self._hb_channel is not None: | |
185 | # We didn't start the kernel with this KernelManager so we |
|
193 | # We didn't start the kernel with this KernelManager so we | |
186 | # use the heartbeat. |
|
194 | # use the heartbeat. | |
187 | return self._hb_channel.is_beating() |
|
195 | return self._hb_channel.is_beating() | |
188 | else: |
|
196 | else: | |
189 | # no heartbeat and not local, we can't tell if it's running, |
|
197 | # no heartbeat and not local, we can't tell if it's running, | |
190 | # so naively return True |
|
198 | # so naively return True | |
191 | return True |
|
199 | return True | |
192 |
|
200 | |||
193 |
|
201 | |||
194 | #----------------------------------------------------------------------------- |
|
202 | #----------------------------------------------------------------------------- | |
195 | # ABC Registration |
|
203 | # ABC Registration | |
196 | #----------------------------------------------------------------------------- |
|
204 | #----------------------------------------------------------------------------- | |
197 |
|
205 | |||
198 | KernelClientABC.register(KernelClient) |
|
206 | KernelClientABC.register(KernelClient) |
General Comments 0
You need to be logged in to leave comments.
Login now