Show More
@@ -1,194 +1,198 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 | |||
|
49 | (KernelClient.execute, complete, history, etc.). | |||
|
50 | See the channels themselves for documentation of these methods. | |||
|
51 | ||||
48 | """ |
|
52 | """ | |
49 |
|
53 | |||
50 | # The PyZMQ Context to use for communication with the kernel. |
|
54 | # The PyZMQ Context to use for communication with the kernel. | |
51 | context = Instance(zmq.Context) |
|
55 | context = Instance(zmq.Context) | |
52 | def _context_default(self): |
|
56 | def _context_default(self): | |
53 | return zmq.Context.instance() |
|
57 | return zmq.Context.instance() | |
54 |
|
58 | |||
55 | # The Session to use for communication with the kernel. |
|
59 | # The Session to use for communication with the kernel. | |
56 | session = Instance(Session) |
|
60 | session = Instance(Session) | |
57 | def _session_default(self): |
|
61 | def _session_default(self): | |
58 | return Session(config=self.config) |
|
62 | return Session(config=self.config) | |
59 |
|
63 | |||
60 | # The classes to use for the various channels |
|
64 | # The classes to use for the various channels | |
61 | shell_channel_class = Type(ShellChannel) |
|
65 | shell_channel_class = Type(ShellChannel) | |
62 | iopub_channel_class = Type(IOPubChannel) |
|
66 | iopub_channel_class = Type(IOPubChannel) | |
63 | stdin_channel_class = Type(StdInChannel) |
|
67 | stdin_channel_class = Type(StdInChannel) | |
64 | hb_channel_class = Type(HBChannel) |
|
68 | hb_channel_class = Type(HBChannel) | |
65 |
|
69 | |||
66 | # Protected traits |
|
70 | # Protected traits | |
67 | _shell_channel = Any |
|
71 | _shell_channel = Any | |
68 | _iopub_channel = Any |
|
72 | _iopub_channel = Any | |
69 | _stdin_channel = Any |
|
73 | _stdin_channel = Any | |
70 | _hb_channel = Any |
|
74 | _hb_channel = Any | |
71 |
|
75 | |||
72 | #-------------------------------------------------------------------------- |
|
76 | #-------------------------------------------------------------------------- | |
73 | # Channel proxy methods |
|
77 | # Channel proxy methods | |
74 | #-------------------------------------------------------------------------- |
|
78 | #-------------------------------------------------------------------------- | |
75 |
|
79 | |||
76 | def _get_msg(channel, *args, **kwargs): |
|
80 | def _get_msg(channel, *args, **kwargs): | |
77 | return channel.get_msg(*args, **kwargs) |
|
81 | return channel.get_msg(*args, **kwargs) | |
78 |
|
82 | |||
79 | def get_shell_msg(self, *args, **kwargs): |
|
83 | def get_shell_msg(self, *args, **kwargs): | |
80 | """Get a message from the shell channel""" |
|
84 | """Get a message from the shell channel""" | |
81 | return self.shell_channel.get_msg(*args, **kwargs) |
|
85 | return self.shell_channel.get_msg(*args, **kwargs) | |
82 |
|
86 | |||
83 | def get_iopub_msg(self, *args, **kwargs): |
|
87 | def get_iopub_msg(self, *args, **kwargs): | |
84 | """Get a message from the iopub channel""" |
|
88 | """Get a message from the iopub channel""" | |
85 | return self.iopub_channel.get_msg(*args, **kwargs) |
|
89 | return self.iopub_channel.get_msg(*args, **kwargs) | |
86 |
|
90 | |||
87 | def get_stdin_msg(self, *args, **kwargs): |
|
91 | def get_stdin_msg(self, *args, **kwargs): | |
88 | """Get a message from the stdin channel""" |
|
92 | """Get a message from the stdin channel""" | |
89 | return self.stdin_channel.get_msg(*args, **kwargs) |
|
93 | return self.stdin_channel.get_msg(*args, **kwargs) | |
90 |
|
94 | |||
91 | #-------------------------------------------------------------------------- |
|
95 | #-------------------------------------------------------------------------- | |
92 | # Channel management methods |
|
96 | # Channel management methods | |
93 | #-------------------------------------------------------------------------- |
|
97 | #-------------------------------------------------------------------------- | |
94 |
|
98 | |||
95 | 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): | |
96 | """Starts the channels for this kernel. |
|
100 | """Starts the channels for this kernel. | |
97 |
|
101 | |||
98 | 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 | |
99 | 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 | |
100 | being used (random ports) then you must first call |
|
104 | being used (random ports) then you must first call | |
101 | :method:`start_kernel`. If the channels have been stopped and you |
|
105 | :method:`start_kernel`. If the channels have been stopped and you | |
102 | call this, :class:`RuntimeError` will be raised. |
|
106 | call this, :class:`RuntimeError` will be raised. | |
103 | """ |
|
107 | """ | |
104 | if shell: |
|
108 | if shell: | |
105 | self.shell_channel.start() |
|
109 | self.shell_channel.start() | |
106 | for method in self.shell_channel.proxy_methods: |
|
110 | for method in self.shell_channel.proxy_methods: | |
107 | setattr(self, method, getattr(self.shell_channel, method)) |
|
111 | setattr(self, method, getattr(self.shell_channel, method)) | |
108 | if iopub: |
|
112 | if iopub: | |
109 | self.iopub_channel.start() |
|
113 | self.iopub_channel.start() | |
110 | for method in self.iopub_channel.proxy_methods: |
|
114 | for method in self.iopub_channel.proxy_methods: | |
111 | setattr(self, method, getattr(self.iopub_channel, method)) |
|
115 | setattr(self, method, getattr(self.iopub_channel, method)) | |
112 | if stdin: |
|
116 | if stdin: | |
113 | self.stdin_channel.start() |
|
117 | self.stdin_channel.start() | |
114 | for method in self.stdin_channel.proxy_methods: |
|
118 | for method in self.stdin_channel.proxy_methods: | |
115 | setattr(self, method, getattr(self.stdin_channel, method)) |
|
119 | setattr(self, method, getattr(self.stdin_channel, method)) | |
116 | self.shell_channel.allow_stdin = True |
|
120 | self.shell_channel.allow_stdin = True | |
117 | else: |
|
121 | else: | |
118 | self.shell_channel.allow_stdin = False |
|
122 | self.shell_channel.allow_stdin = False | |
119 | if hb: |
|
123 | if hb: | |
120 | self.hb_channel.start() |
|
124 | self.hb_channel.start() | |
121 |
|
125 | |||
122 | def stop_channels(self): |
|
126 | def stop_channels(self): | |
123 | """Stops all the running channels for this kernel. |
|
127 | """Stops all the running channels for this kernel. | |
124 |
|
128 | |||
125 | This stops their event loops and joins their threads. |
|
129 | This stops their event loops and joins their threads. | |
126 | """ |
|
130 | """ | |
127 | if self.shell_channel.is_alive(): |
|
131 | if self.shell_channel.is_alive(): | |
128 | self.shell_channel.stop() |
|
132 | self.shell_channel.stop() | |
129 | if self.iopub_channel.is_alive(): |
|
133 | if self.iopub_channel.is_alive(): | |
130 | self.iopub_channel.stop() |
|
134 | self.iopub_channel.stop() | |
131 | if self.stdin_channel.is_alive(): |
|
135 | if self.stdin_channel.is_alive(): | |
132 | self.stdin_channel.stop() |
|
136 | self.stdin_channel.stop() | |
133 | if self.hb_channel.is_alive(): |
|
137 | if self.hb_channel.is_alive(): | |
134 | self.hb_channel.stop() |
|
138 | self.hb_channel.stop() | |
135 |
|
139 | |||
136 | @property |
|
140 | @property | |
137 | def channels_running(self): |
|
141 | def channels_running(self): | |
138 | """Are any of the channels created and running?""" |
|
142 | """Are any of the channels created and running?""" | |
139 | 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 | |
140 | self.stdin_channel.is_alive() or self.hb_channel.is_alive()) |
|
144 | self.stdin_channel.is_alive() or self.hb_channel.is_alive()) | |
141 |
|
145 | |||
142 | @property |
|
146 | @property | |
143 | def shell_channel(self): |
|
147 | def shell_channel(self): | |
144 | """Get the shell channel object for this kernel.""" |
|
148 | """Get the shell channel object for this kernel.""" | |
145 | if self._shell_channel is None: |
|
149 | if self._shell_channel is None: | |
146 | self._shell_channel = self.shell_channel_class( |
|
150 | self._shell_channel = self.shell_channel_class( | |
147 | self.context, self.session, self._make_url('shell') |
|
151 | self.context, self.session, self._make_url('shell') | |
148 | ) |
|
152 | ) | |
149 | return self._shell_channel |
|
153 | return self._shell_channel | |
150 |
|
154 | |||
151 | @property |
|
155 | @property | |
152 | def iopub_channel(self): |
|
156 | def iopub_channel(self): | |
153 | """Get the iopub channel object for this kernel.""" |
|
157 | """Get the iopub channel object for this kernel.""" | |
154 | if self._iopub_channel is None: |
|
158 | if self._iopub_channel is None: | |
155 | self._iopub_channel = self.iopub_channel_class( |
|
159 | self._iopub_channel = self.iopub_channel_class( | |
156 | self.context, self.session, self._make_url('iopub') |
|
160 | self.context, self.session, self._make_url('iopub') | |
157 | ) |
|
161 | ) | |
158 | return self._iopub_channel |
|
162 | return self._iopub_channel | |
159 |
|
163 | |||
160 | @property |
|
164 | @property | |
161 | def stdin_channel(self): |
|
165 | def stdin_channel(self): | |
162 | """Get the stdin channel object for this kernel.""" |
|
166 | """Get the stdin channel object for this kernel.""" | |
163 | if self._stdin_channel is None: |
|
167 | if self._stdin_channel is None: | |
164 | self._stdin_channel = self.stdin_channel_class( |
|
168 | self._stdin_channel = self.stdin_channel_class( | |
165 | self.context, self.session, self._make_url('stdin') |
|
169 | self.context, self.session, self._make_url('stdin') | |
166 | ) |
|
170 | ) | |
167 | return self._stdin_channel |
|
171 | return self._stdin_channel | |
168 |
|
172 | |||
169 | @property |
|
173 | @property | |
170 | def hb_channel(self): |
|
174 | def hb_channel(self): | |
171 | """Get the hb channel object for this kernel.""" |
|
175 | """Get the hb channel object for this kernel.""" | |
172 | if self._hb_channel is None: |
|
176 | if self._hb_channel is None: | |
173 | self._hb_channel = self.hb_channel_class( |
|
177 | self._hb_channel = self.hb_channel_class( | |
174 | self.context, self.session, self._make_url('hb') |
|
178 | self.context, self.session, self._make_url('hb') | |
175 | ) |
|
179 | ) | |
176 | return self._hb_channel |
|
180 | return self._hb_channel | |
177 |
|
181 | |||
178 | def is_alive(self): |
|
182 | def is_alive(self): | |
179 | """Is the kernel process still running?""" |
|
183 | """Is the kernel process still running?""" | |
180 | if self._hb_channel is not None: |
|
184 | if self._hb_channel is not None: | |
181 | # We didn't start the kernel with this KernelManager so we |
|
185 | # We didn't start the kernel with this KernelManager so we | |
182 | # use the heartbeat. |
|
186 | # use the heartbeat. | |
183 | return self._hb_channel.is_beating() |
|
187 | return self._hb_channel.is_beating() | |
184 | else: |
|
188 | else: | |
185 | # no heartbeat and not local, we can't tell if it's running, |
|
189 | # no heartbeat and not local, we can't tell if it's running, | |
186 | # so naively return True |
|
190 | # so naively return True | |
187 | return True |
|
191 | return True | |
188 |
|
192 | |||
189 |
|
193 | |||
190 | #----------------------------------------------------------------------------- |
|
194 | #----------------------------------------------------------------------------- | |
191 | # ABC Registration |
|
195 | # ABC Registration | |
192 | #----------------------------------------------------------------------------- |
|
196 | #----------------------------------------------------------------------------- | |
193 |
|
197 | |||
194 | KernelClientABC.register(KernelClient) |
|
198 | KernelClientABC.register(KernelClient) |
General Comments 0
You need to be logged in to leave comments.
Login now