##// END OF EJS Templates
add debug statements for kernel clients connecting to channels
MinRK -
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, self._make_url('shell')
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, self._make_url('iopub')
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, self._make_url('stdin')
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, self._make_url('hb')
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