##// END OF EJS Templates
Merge pull request #5764 from takluyver/parallel-kernel-shutdown...
Thomas Kluyver -
r16726:a26a2e70 merge
parent child Browse files
Show More
@@ -1,413 +1,420 b''
1 1 """Base class to manage a running kernel"""
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 __future__ import absolute_import
7 7
8 8 # Standard library imports
9 9 import os
10 10 import re
11 11 import signal
12 12 import sys
13 13 import time
14 14 import warnings
15 15
16 16 import zmq
17 17
18 18 # Local imports
19 19 from IPython.config.configurable import LoggingConfigurable
20 20 from IPython.utils.importstring import import_item
21 21 from IPython.utils.localinterfaces import is_local_ip, local_ips
22 22 from IPython.utils.path import get_ipython_dir
23 23 from IPython.utils.traitlets import (
24 24 Any, Instance, Unicode, List, Bool, Type, DottedObjectName
25 25 )
26 26 from IPython.kernel import (
27 27 make_ipkernel_cmd,
28 28 launch_kernel,
29 29 kernelspec,
30 30 )
31 31 from .connect import ConnectionFileMixin
32 32 from .zmq.session import Session
33 33 from .managerabc import (
34 34 KernelManagerABC
35 35 )
36 36
37 37
38 38 class KernelManager(LoggingConfigurable, ConnectionFileMixin):
39 39 """Manages a single kernel in a subprocess on this host.
40 40
41 41 This version starts kernels with Popen.
42 42 """
43 43
44 44 # The PyZMQ Context to use for communication with the kernel.
45 45 context = Instance(zmq.Context)
46 46 def _context_default(self):
47 47 return zmq.Context.instance()
48 48
49 49 # The Session to use for communication with the kernel.
50 50 session = Instance(Session)
51 51 def _session_default(self):
52 52 return Session(parent=self)
53 53
54 54 # the class to create with our `client` method
55 55 client_class = DottedObjectName('IPython.kernel.blocking.BlockingKernelClient')
56 56 client_factory = Type()
57 57 def _client_class_changed(self, name, old, new):
58 58 self.client_factory = import_item(str(new))
59 59
60 60 # The kernel process with which the KernelManager is communicating.
61 61 # generally a Popen instance
62 62 kernel = Any()
63 63
64 64 kernel_spec_manager = Instance(kernelspec.KernelSpecManager)
65 65
66 66 def _kernel_spec_manager_default(self):
67 67 return kernelspec.KernelSpecManager(ipython_dir=self.ipython_dir)
68 68
69 69 kernel_name = Unicode('python')
70 70
71 71 kernel_spec = Instance(kernelspec.KernelSpec)
72 72
73 73 def _kernel_spec_default(self):
74 74 return self.kernel_spec_manager.get_kernel_spec(self.kernel_name)
75 75
76 76 def _kernel_name_changed(self, name, old, new):
77 77 self.kernel_spec = self.kernel_spec_manager.get_kernel_spec(new)
78 78 self.ipython_kernel = new in {'python', 'python2', 'python3'}
79 79
80 80 kernel_cmd = List(Unicode, config=True,
81 81 help="""DEPRECATED: Use kernel_name instead.
82 82
83 83 The Popen Command to launch the kernel.
84 84 Override this if you have a custom kernel.
85 85 If kernel_cmd is specified in a configuration file,
86 86 IPython does not pass any arguments to the kernel,
87 87 because it cannot make any assumptions about the
88 88 arguments that the kernel understands. In particular,
89 89 this means that the kernel does not receive the
90 90 option --debug if it given on the IPython command line.
91 91 """
92 92 )
93 93
94 94 def _kernel_cmd_changed(self, name, old, new):
95 95 warnings.warn("Setting kernel_cmd is deprecated, use kernel_spec to "
96 96 "start different kernels.")
97 97 self.ipython_kernel = False
98 98
99 99 ipython_kernel = Bool(True)
100 100
101 101 ipython_dir = Unicode()
102 102 def _ipython_dir_default(self):
103 103 return get_ipython_dir()
104 104
105 105 # Protected traits
106 106 _launch_args = Any()
107 107 _control_socket = Any()
108 108
109 109 _restarter = Any()
110 110
111 111 autorestart = Bool(False, config=True,
112 112 help="""Should we autorestart the kernel if it dies."""
113 113 )
114 114
115 115 def __del__(self):
116 116 self._close_control_socket()
117 117 self.cleanup_connection_file()
118 118
119 119 #--------------------------------------------------------------------------
120 120 # Kernel restarter
121 121 #--------------------------------------------------------------------------
122 122
123 123 def start_restarter(self):
124 124 pass
125 125
126 126 def stop_restarter(self):
127 127 pass
128 128
129 129 def add_restart_callback(self, callback, event='restart'):
130 130 """register a callback to be called when a kernel is restarted"""
131 131 if self._restarter is None:
132 132 return
133 133 self._restarter.add_callback(callback, event)
134 134
135 135 def remove_restart_callback(self, callback, event='restart'):
136 136 """unregister a callback to be called when a kernel is restarted"""
137 137 if self._restarter is None:
138 138 return
139 139 self._restarter.remove_callback(callback, event)
140 140
141 141 #--------------------------------------------------------------------------
142 142 # create a Client connected to our Kernel
143 143 #--------------------------------------------------------------------------
144 144
145 145 def client(self, **kwargs):
146 146 """Create a client configured to connect to our kernel"""
147 147 if self.client_factory is None:
148 148 self.client_factory = import_item(self.client_class)
149 149
150 150 kw = {}
151 151 kw.update(self.get_connection_info())
152 152 kw.update(dict(
153 153 connection_file=self.connection_file,
154 154 session=self.session,
155 155 parent=self,
156 156 ))
157 157
158 158 # add kwargs last, for manual overrides
159 159 kw.update(kwargs)
160 160 return self.client_factory(**kw)
161 161
162 162 #--------------------------------------------------------------------------
163 163 # Kernel management
164 164 #--------------------------------------------------------------------------
165 165
166 166 def format_kernel_cmd(self, **kw):
167 167 """replace templated args (e.g. {connection_file})"""
168 168 if self.kernel_cmd:
169 169 cmd = self.kernel_cmd
170 170 elif self.kernel_name == 'python':
171 171 # The native kernel gets special handling
172 172 cmd = make_ipkernel_cmd(
173 173 'from IPython.kernel.zmq.kernelapp import main; main()',
174 174 **kw
175 175 )
176 176 else:
177 177 cmd = self.kernel_spec.argv
178 178
179 179 ns = dict(connection_file=self.connection_file)
180 180 ns.update(self._launch_args)
181 181
182 182 pat = re.compile(r'\{([A-Za-z0-9_]+)\}')
183 183 def from_ns(match):
184 184 """Get the key out of ns if it's there, otherwise no change."""
185 185 return ns.get(match.group(1), match.group())
186 186
187 187 return [ pat.sub(from_ns, arg) for arg in cmd ]
188 188
189 189 def _launch_kernel(self, kernel_cmd, **kw):
190 190 """actually launch the kernel
191 191
192 192 override in a subclass to launch kernel subprocesses differently
193 193 """
194 194 return launch_kernel(kernel_cmd, **kw)
195 195
196 196 # Control socket used for polite kernel shutdown
197 197
198 198 def _connect_control_socket(self):
199 199 if self._control_socket is None:
200 200 self._control_socket = self.connect_control()
201 201 self._control_socket.linger = 100
202 202
203 203 def _close_control_socket(self):
204 204 if self._control_socket is None:
205 205 return
206 206 self._control_socket.close()
207 207 self._control_socket = None
208 208
209 209 def start_kernel(self, **kw):
210 210 """Starts a kernel on this host in a separate process.
211 211
212 212 If random ports (port=0) are being used, this method must be called
213 213 before the channels are created.
214 214
215 215 Parameters
216 216 ----------
217 217 **kw : optional
218 218 keyword arguments that are passed down to build the kernel_cmd
219 219 and launching the kernel (e.g. Popen kwargs).
220 220 """
221 221 if self.transport == 'tcp' and not is_local_ip(self.ip):
222 222 raise RuntimeError("Can only launch a kernel on a local interface. "
223 223 "Make sure that the '*_address' attributes are "
224 224 "configured properly. "
225 225 "Currently valid addresses are: %s" % local_ips()
226 226 )
227 227
228 228 # write connection file / get default ports
229 229 self.write_connection_file()
230 230
231 231 # save kwargs for use in restart
232 232 self._launch_args = kw.copy()
233 233 # build the Popen cmd
234 234 kernel_cmd = self.format_kernel_cmd(**kw)
235 235 if self.kernel_cmd:
236 236 # If kernel_cmd has been set manually, don't refer to a kernel spec
237 237 env = os.environ
238 238 else:
239 239 # Environment variables from kernel spec are added to os.environ
240 240 env = os.environ.copy()
241 241 env.update(self.kernel_spec.env or {})
242 242 # launch the kernel subprocess
243 243 self.kernel = self._launch_kernel(kernel_cmd, env=env,
244 244 ipython_kernel=self.ipython_kernel,
245 245 **kw)
246 246 self.start_restarter()
247 247 self._connect_control_socket()
248 248
249 def _send_shutdown_request(self, restart=False):
250 """TODO: send a shutdown request via control channel"""
249 def request_shutdown(self, restart=False):
250 """Send a shutdown request via control channel
251
252 On Windows, this just kills kernels instead, because the shutdown
253 messages don't work.
254 """
251 255 content = dict(restart=restart)
252 256 msg = self.session.msg("shutdown_request", content=content)
253 257 self.session.send(self._control_socket, msg)
254 258
259 def finish_shutdown(self, waittime=1, pollinterval=0.1):
260 """Wait for kernel shutdown, then kill process if it doesn't shutdown.
261
262 This does not send shutdown requests - use :meth:`request_shutdown`
263 first.
264 """
265 for i in range(int(waittime/pollinterval)):
266 if self.is_alive():
267 time.sleep(pollinterval)
268 else:
269 break
270 else:
271 # OK, we've waited long enough.
272 if self.has_kernel:
273 self._kill_kernel()
274
275 def cleanup(self, connection_file=True):
276 """Clean up resources when the kernel is shut down"""
277 if connection_file:
278 self.cleanup_connection_file()
279
280 self.cleanup_ipc_files()
281 self._close_control_socket()
282
255 283 def shutdown_kernel(self, now=False, restart=False):
256 284 """Attempts to the stop the kernel process cleanly.
257 285
258 286 This attempts to shutdown the kernels cleanly by:
259 287
260 288 1. Sending it a shutdown message over the shell channel.
261 289 2. If that fails, the kernel is shutdown forcibly by sending it
262 290 a signal.
263 291
264 292 Parameters
265 293 ----------
266 294 now : bool
267 295 Should the kernel be forcible killed *now*. This skips the
268 296 first, nice shutdown attempt.
269 297 restart: bool
270 298 Will this kernel be restarted after it is shutdown. When this
271 299 is True, connection files will not be cleaned up.
272 300 """
273 301 # Stop monitoring for restarting while we shutdown.
274 302 self.stop_restarter()
275 303
276 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
277 if now or sys.platform == 'win32':
278 if self.has_kernel:
279 self._kill_kernel()
304 if now:
305 self._kill_kernel()
280 306 else:
307 self.request_shutdown(restart=restart)
281 308 # Don't send any additional kernel kill messages immediately, to give
282 309 # the kernel a chance to properly execute shutdown actions. Wait for at
283 310 # most 1s, checking every 0.1s.
284 self._send_shutdown_request(restart=restart)
285 for i in range(10):
286 if self.is_alive():
287 time.sleep(0.1)
288 else:
289 break
290 else:
291 # OK, we've waited long enough.
292 if self.has_kernel:
293 self._kill_kernel()
311 self.finish_shutdown()
294 312
295 if not restart:
296 self.cleanup_connection_file()
297 self.cleanup_ipc_files()
298 else:
299 self.cleanup_ipc_files()
300
301 self._close_control_socket()
313 self.cleanup(connection_file=not restart)
302 314
303 315 def restart_kernel(self, now=False, **kw):
304 316 """Restarts a kernel with the arguments that were used to launch it.
305 317
306 318 If the old kernel was launched with random ports, the same ports will be
307 319 used for the new kernel. The same connection file is used again.
308 320
309 321 Parameters
310 322 ----------
311 323 now : bool, optional
312 324 If True, the kernel is forcefully restarted *immediately*, without
313 325 having a chance to do any cleanup action. Otherwise the kernel is
314 326 given 1s to clean up before a forceful restart is issued.
315 327
316 328 In all cases the kernel is restarted, the only difference is whether
317 329 it is given a chance to perform a clean shutdown or not.
318 330
319 331 **kw : optional
320 332 Any options specified here will overwrite those used to launch the
321 333 kernel.
322 334 """
323 335 if self._launch_args is None:
324 336 raise RuntimeError("Cannot restart the kernel. "
325 337 "No previous call to 'start_kernel'.")
326 338 else:
327 339 # Stop currently running kernel.
328 340 self.shutdown_kernel(now=now, restart=True)
329 341
330 342 # Start new kernel.
331 343 self._launch_args.update(kw)
332 344 self.start_kernel(**self._launch_args)
333 345
334 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
335 # unless there is some delay here.
336 if sys.platform == 'win32':
337 time.sleep(0.2)
338
339 346 @property
340 347 def has_kernel(self):
341 348 """Has a kernel been started that we are managing."""
342 349 return self.kernel is not None
343 350
344 351 def _kill_kernel(self):
345 352 """Kill the running kernel.
346 353
347 354 This is a private method, callers should use shutdown_kernel(now=True).
348 355 """
349 356 if self.has_kernel:
350 357
351 358 # Signal the kernel to terminate (sends SIGKILL on Unix and calls
352 359 # TerminateProcess() on Win32).
353 360 try:
354 361 self.kernel.kill()
355 362 except OSError as e:
356 363 # In Windows, we will get an Access Denied error if the process
357 364 # has already terminated. Ignore it.
358 365 if sys.platform == 'win32':
359 366 if e.winerror != 5:
360 367 raise
361 368 # On Unix, we may get an ESRCH error if the process has already
362 369 # terminated. Ignore it.
363 370 else:
364 371 from errno import ESRCH
365 372 if e.errno != ESRCH:
366 373 raise
367 374
368 375 # Block until the kernel terminates.
369 376 self.kernel.wait()
370 377 self.kernel = None
371 378 else:
372 379 raise RuntimeError("Cannot kill kernel. No kernel is running!")
373 380
374 381 def interrupt_kernel(self):
375 382 """Interrupts the kernel by sending it a signal.
376 383
377 384 Unlike ``signal_kernel``, this operation is well supported on all
378 385 platforms.
379 386 """
380 387 if self.has_kernel:
381 388 if sys.platform == 'win32':
382 389 from .zmq.parentpoller import ParentPollerWindows as Poller
383 390 Poller.send_interrupt(self.kernel.win32_interrupt_event)
384 391 else:
385 392 self.kernel.send_signal(signal.SIGINT)
386 393 else:
387 394 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
388 395
389 396 def signal_kernel(self, signum):
390 397 """Sends a signal to the kernel.
391 398
392 399 Note that since only SIGTERM is supported on Windows, this function is
393 400 only useful on Unix systems.
394 401 """
395 402 if self.has_kernel:
396 403 self.kernel.send_signal(signum)
397 404 else:
398 405 raise RuntimeError("Cannot signal kernel. No kernel is running!")
399 406
400 407 def is_alive(self):
401 408 """Is the kernel process still running?"""
402 409 if self.has_kernel:
403 410 if self.kernel.poll() is None:
404 411 return True
405 412 else:
406 413 return False
407 414 else:
408 415 # we don't have a kernel
409 416 return False
410 417
411 418
412 419 KernelManagerABC.register(KernelManager)
413 420
@@ -1,302 +1,322 b''
1 1 """A kernel manager for multiple kernels
2 2
3 3 Authors:
4 4
5 5 * Brian Granger
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2013 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from __future__ import absolute_import
20 20
21 21 import os
22 22 import uuid
23 23
24 24 import zmq
25 25
26 26 from IPython.config.configurable import LoggingConfigurable
27 27 from IPython.utils.importstring import import_item
28 28 from IPython.utils.traitlets import (
29 29 Instance, Dict, Unicode, Any, DottedObjectName
30 30 )
31 31 from IPython.utils.py3compat import unicode_type
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Classes
35 35 #-----------------------------------------------------------------------------
36 36
37 37 class DuplicateKernelError(Exception):
38 38 pass
39 39
40 40
41 41
42 42 def kernel_method(f):
43 43 """decorator for proxying MKM.method(kernel_id) to individual KMs by ID"""
44 44 def wrapped(self, kernel_id, *args, **kwargs):
45 45 # get the kernel
46 46 km = self.get_kernel(kernel_id)
47 47 method = getattr(km, f.__name__)
48 48 # call the kernel's method
49 49 r = method(*args, **kwargs)
50 50 # last thing, call anything defined in the actual class method
51 51 # such as logging messages
52 52 f(self, kernel_id, *args, **kwargs)
53 53 # return the method result
54 54 return r
55 55 return wrapped
56 56
57 57
58 58 class MultiKernelManager(LoggingConfigurable):
59 59 """A class for managing multiple kernels."""
60 60
61 61 kernel_manager_class = DottedObjectName(
62 62 "IPython.kernel.ioloop.IOLoopKernelManager", config=True,
63 63 help="""The kernel manager class. This is configurable to allow
64 64 subclassing of the KernelManager for customized behavior.
65 65 """
66 66 )
67 67 def _kernel_manager_class_changed(self, name, old, new):
68 68 self.kernel_manager_factory = import_item(new)
69 69
70 70 kernel_manager_factory = Any(help="this is kernel_manager_class after import")
71 71 def _kernel_manager_factory_default(self):
72 72 return import_item(self.kernel_manager_class)
73 73
74 74 context = Instance('zmq.Context')
75 75 def _context_default(self):
76 76 return zmq.Context.instance()
77 77
78 78 connection_dir = Unicode('')
79 79
80 80 _kernels = Dict()
81 81
82 82 def list_kernel_ids(self):
83 83 """Return a list of the kernel ids of the active kernels."""
84 84 # Create a copy so we can iterate over kernels in operations
85 85 # that delete keys.
86 86 return list(self._kernels.keys())
87 87
88 88 def __len__(self):
89 89 """Return the number of running kernels."""
90 90 return len(self.list_kernel_ids())
91 91
92 92 def __contains__(self, kernel_id):
93 93 return kernel_id in self._kernels
94 94
95 95 def start_kernel(self, **kwargs):
96 96 """Start a new kernel.
97 97
98 98 The caller can pick a kernel_id by passing one in as a keyword arg,
99 99 otherwise one will be picked using a uuid.
100 100
101 101 To silence the kernel's stdout/stderr, call this using::
102 102
103 103 km.start_kernel(stdout=PIPE, stderr=PIPE)
104 104
105 105 """
106 106 kernel_id = kwargs.pop('kernel_id', unicode_type(uuid.uuid4()))
107 107 if kernel_id in self:
108 108 raise DuplicateKernelError('Kernel already exists: %s' % kernel_id)
109 109 # kernel_manager_factory is the constructor for the KernelManager
110 110 # subclass we are using. It can be configured as any Configurable,
111 111 # including things like its transport and ip.
112 112 km = self.kernel_manager_factory(connection_file=os.path.join(
113 113 self.connection_dir, "kernel-%s.json" % kernel_id),
114 114 parent=self, autorestart=True, log=self.log
115 115 )
116 116 km.start_kernel(**kwargs)
117 117 self._kernels[kernel_id] = km
118 118 return kernel_id
119 119
120 120 @kernel_method
121 def shutdown_kernel(self, kernel_id, now=False):
121 def shutdown_kernel(self, kernel_id, now=False, restart=False):
122 122 """Shutdown a kernel by its kernel uuid.
123 123
124 124 Parameters
125 125 ==========
126 126 kernel_id : uuid
127 127 The id of the kernel to shutdown.
128 128 now : bool
129 129 Should the kernel be shutdown forcibly using a signal.
130 restart : bool
131 Will the kernel be restarted?
130 132 """
131 133 self.log.info("Kernel shutdown: %s" % kernel_id)
132 134 self.remove_kernel(kernel_id)
133 135
136 @kernel_method
137 def request_shutdown(self, kernel_id, restart=False):
138 """Ask a kernel to shut down by its kernel uuid"""
139
140 @kernel_method
141 def finish_shutdown(self, kernel_id, waittime=1, pollinterval=0.1):
142 """Wait for a kernel to finish shutting down, and kill it if it doesn't
143 """
144 self.log.info("Kernel shutdown: %s" % kernel_id)
145
146 @kernel_method
147 def cleanup(self, kernel_id, connection_file=True):
148 """Clean up a kernel's resources"""
149
134 150 def remove_kernel(self, kernel_id):
135 151 """remove a kernel from our mapping.
136 152
137 153 Mainly so that a kernel can be removed if it is already dead,
138 154 without having to call shutdown_kernel.
139 155
140 156 The kernel object is returned.
141 157 """
142 158 return self._kernels.pop(kernel_id)
143 159
144 160 def shutdown_all(self, now=False):
145 161 """Shutdown all kernels."""
146 for kid in self.list_kernel_ids():
147 self.shutdown_kernel(kid, now=now)
162 kids = self.list_kernel_ids()
163 for kid in kids:
164 self.request_shutdown(kid)
165 for kid in kids:
166 self.finish_shutdown(kid)
167 self.cleanup(kid)
148 168
149 169 @kernel_method
150 170 def interrupt_kernel(self, kernel_id):
151 171 """Interrupt (SIGINT) the kernel by its uuid.
152 172
153 173 Parameters
154 174 ==========
155 175 kernel_id : uuid
156 176 The id of the kernel to interrupt.
157 177 """
158 178 self.log.info("Kernel interrupted: %s" % kernel_id)
159 179
160 180 @kernel_method
161 181 def signal_kernel(self, kernel_id, signum):
162 182 """Sends a signal to the kernel by its uuid.
163 183
164 184 Note that since only SIGTERM is supported on Windows, this function
165 185 is only useful on Unix systems.
166 186
167 187 Parameters
168 188 ==========
169 189 kernel_id : uuid
170 190 The id of the kernel to signal.
171 191 """
172 192 self.log.info("Signaled Kernel %s with %s" % (kernel_id, signum))
173 193
174 194 @kernel_method
175 195 def restart_kernel(self, kernel_id, now=False):
176 196 """Restart a kernel by its uuid, keeping the same ports.
177 197
178 198 Parameters
179 199 ==========
180 200 kernel_id : uuid
181 201 The id of the kernel to interrupt.
182 202 """
183 203 self.log.info("Kernel restarted: %s" % kernel_id)
184 204
185 205 @kernel_method
186 206 def is_alive(self, kernel_id):
187 207 """Is the kernel alive.
188 208
189 209 This calls KernelManager.is_alive() which calls Popen.poll on the
190 210 actual kernel subprocess.
191 211
192 212 Parameters
193 213 ==========
194 214 kernel_id : uuid
195 215 The id of the kernel.
196 216 """
197 217
198 218 def _check_kernel_id(self, kernel_id):
199 219 """check that a kernel id is valid"""
200 220 if kernel_id not in self:
201 221 raise KeyError("Kernel with id not found: %s" % kernel_id)
202 222
203 223 def get_kernel(self, kernel_id):
204 224 """Get the single KernelManager object for a kernel by its uuid.
205 225
206 226 Parameters
207 227 ==========
208 228 kernel_id : uuid
209 229 The id of the kernel.
210 230 """
211 231 self._check_kernel_id(kernel_id)
212 232 return self._kernels[kernel_id]
213 233
214 234 @kernel_method
215 235 def add_restart_callback(self, kernel_id, callback, event='restart'):
216 236 """add a callback for the KernelRestarter"""
217 237
218 238 @kernel_method
219 239 def remove_restart_callback(self, kernel_id, callback, event='restart'):
220 240 """remove a callback for the KernelRestarter"""
221 241
222 242 @kernel_method
223 243 def get_connection_info(self, kernel_id):
224 244 """Return a dictionary of connection data for a kernel.
225 245
226 246 Parameters
227 247 ==========
228 248 kernel_id : uuid
229 249 The id of the kernel.
230 250
231 251 Returns
232 252 =======
233 253 connection_dict : dict
234 254 A dict of the information needed to connect to a kernel.
235 255 This includes the ip address and the integer port
236 256 numbers of the different channels (stdin_port, iopub_port,
237 257 shell_port, hb_port).
238 258 """
239 259
240 260 @kernel_method
241 261 def connect_iopub(self, kernel_id, identity=None):
242 262 """Return a zmq Socket connected to the iopub channel.
243 263
244 264 Parameters
245 265 ==========
246 266 kernel_id : uuid
247 267 The id of the kernel
248 268 identity : bytes (optional)
249 269 The zmq identity of the socket
250 270
251 271 Returns
252 272 =======
253 273 stream : zmq Socket or ZMQStream
254 274 """
255 275
256 276 @kernel_method
257 277 def connect_shell(self, kernel_id, identity=None):
258 278 """Return a zmq Socket connected to the shell channel.
259 279
260 280 Parameters
261 281 ==========
262 282 kernel_id : uuid
263 283 The id of the kernel
264 284 identity : bytes (optional)
265 285 The zmq identity of the socket
266 286
267 287 Returns
268 288 =======
269 289 stream : zmq Socket or ZMQStream
270 290 """
271 291
272 292 @kernel_method
273 293 def connect_stdin(self, kernel_id, identity=None):
274 294 """Return a zmq Socket connected to the stdin channel.
275 295
276 296 Parameters
277 297 ==========
278 298 kernel_id : uuid
279 299 The id of the kernel
280 300 identity : bytes (optional)
281 301 The zmq identity of the socket
282 302
283 303 Returns
284 304 =======
285 305 stream : zmq Socket or ZMQStream
286 306 """
287 307
288 308 @kernel_method
289 309 def connect_hb(self, kernel_id, identity=None):
290 310 """Return a zmq Socket connected to the hb channel.
291 311
292 312 Parameters
293 313 ==========
294 314 kernel_id : uuid
295 315 The id of the kernel
296 316 identity : bytes (optional)
297 317 The zmq identity of the socket
298 318
299 319 Returns
300 320 =======
301 321 stream : zmq Socket or ZMQStream
302 322 """
General Comments 0
You need to be logged in to leave comments. Login now