##// END OF EJS Templates
relocate redundantly-named kernel files...
MinRK -
Show More
1 NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
@@ -1,90 +1,89 b''
1 1 """ Implements a fully blocking kernel manager.
2 2
3 3 Useful for test suites and blocking terminal interfaces.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2010-2012 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING.txt, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import Queue
17 17
18 18 from IPython.utils.traitlets import Type
19 19 from .kernelmanager import KernelManager, IOPubChannel, HBChannel, \
20 20 ShellChannel, StdInChannel
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Blocking kernel manager
24 24 #-----------------------------------------------------------------------------
25 25
26 26
27 27 class BlockingChannelMixin(object):
28
28
29 29 def __init__(self, *args, **kwds):
30 30 super(BlockingChannelMixin, self).__init__(*args, **kwds)
31 31 self._in_queue = Queue.Queue()
32
32
33 33 def call_handlers(self, msg):
34 34 self._in_queue.put(msg)
35
35
36 36 def get_msg(self, block=True, timeout=None):
37 37 """ Gets a message if there is one that is ready. """
38 38 if timeout is None:
39 39 # Queue.get(timeout=None) has stupid uninteruptible
40 40 # behavior, so wait for a week instead
41 41 timeout = 604800
42 42 return self._in_queue.get(block, timeout)
43
43
44 44 def get_msgs(self):
45 45 """ Get all messages that are currently ready. """
46 46 msgs = []
47 47 while True:
48 48 try:
49 49 msgs.append(self.get_msg(block=False))
50 50 except Queue.Empty:
51 51 break
52 52 return msgs
53
53
54 54 def msg_ready(self):
55 55 """ Is there a message that has been received? """
56 56 return not self._in_queue.empty()
57 57
58 58
59 59 class BlockingIOPubChannel(BlockingChannelMixin, IOPubChannel):
60 60 pass
61 61
62 62
63 63 class BlockingShellChannel(BlockingChannelMixin, ShellChannel):
64 64 pass
65 65
66 66
67 67 class BlockingStdInChannel(BlockingChannelMixin, StdInChannel):
68 68 pass
69 69
70 70
71 71 class BlockingHBChannel(HBChannel):
72
72
73 73 # This kernel needs quicker monitoring, shorten to 1 sec.
74 74 # less than 0.5s is unreliable, and will get occasional
75 75 # false reports of missed beats.
76 76 time_to_dead = 1.
77 77
78 78 def call_handlers(self, since_last_heartbeat):
79 79 """ Pause beating on missed heartbeat. """
80 80 pass
81 81
82 82
83 83 class BlockingKernelManager(KernelManager):
84 84
85 85 # The classes to use for the various channels.
86 86 shell_channel_class = Type(BlockingShellChannel)
87 87 iopub_channel_class = Type(BlockingIOPubChannel)
88 88 stdin_channel_class = Type(BlockingStdInChannel)
89 89 hb_channel_class = Type(BlockingHBChannel)
90
1 NO CONTENT: file renamed from IPython/kernel/ioloopkernelmanager.py to IPython/kernel/ioloop/manager.py
1 NO CONTENT: file renamed from IPython/kernel/ioloopkernelrestarter.py to IPython/kernel/ioloop/restarter.py
@@ -1,1147 +1,1146 b''
1 1 """Base classes to manage the interaction with a running kernel.
2 2
3 3 TODO
4 4 * Create logger to handle debugging and console messages.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import absolute_import
19 19
20 20 # Standard library imports
21 21 import atexit
22 22 import errno
23 23 import json
24 24 import os
25 25 import signal
26 26 import sys
27 27 from threading import Thread
28 28 import time
29 29
30 30 import zmq
31 31 # import ZMQError in top-level namespace, to avoid ugly attribute-error messages
32 32 # during garbage collection of threads at exit:
33 33 from zmq import ZMQError
34 34 from zmq.eventloop import ioloop, zmqstream
35 35
36 36 # Local imports
37 37 from IPython.config.configurable import Configurable
38 38 from IPython.utils.importstring import import_item
39 39 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
40 40 from IPython.utils.traitlets import (
41 41 Any, Instance, Type, Unicode, List, Integer, Bool,
42 42 CaselessStrEnum, DottedObjectName
43 43 )
44 44 from IPython.utils.py3compat import str_to_bytes
45 45 from IPython.kernel import (
46 46 write_connection_file,
47 47 make_ipkernel_cmd,
48 48 launch_kernel,
49 49 )
50 50 from .zmq.session import Session
51 51 from .kernelmanagerabc import (
52 52 ShellChannelABC, IOPubChannelABC,
53 53 HBChannelABC, StdInChannelABC,
54 54 KernelManagerABC
55 55 )
56 56
57 57 #-----------------------------------------------------------------------------
58 58 # Constants and exceptions
59 59 #-----------------------------------------------------------------------------
60 60
61 61 class InvalidPortNumber(Exception):
62 62 pass
63 63
64 64 #-----------------------------------------------------------------------------
65 65 # Utility functions
66 66 #-----------------------------------------------------------------------------
67 67
68 68 # some utilities to validate message structure, these might get moved elsewhere
69 69 # if they prove to have more generic utility
70 70
71 71 def validate_string_list(lst):
72 72 """Validate that the input is a list of strings.
73 73
74 74 Raises ValueError if not."""
75 75 if not isinstance(lst, list):
76 76 raise ValueError('input %r must be a list' % lst)
77 77 for x in lst:
78 78 if not isinstance(x, basestring):
79 79 raise ValueError('element %r in list must be a string' % x)
80 80
81 81
82 82 def validate_string_dict(dct):
83 83 """Validate that the input is a dict with string keys and values.
84 84
85 85 Raises ValueError if not."""
86 86 for k,v in dct.iteritems():
87 87 if not isinstance(k, basestring):
88 88 raise ValueError('key %r in dict must be a string' % k)
89 89 if not isinstance(v, basestring):
90 90 raise ValueError('value %r in dict must be a string' % v)
91 91
92 92
93 93 #-----------------------------------------------------------------------------
94 94 # ZMQ Socket Channel classes
95 95 #-----------------------------------------------------------------------------
96 96
97 97 class ZMQSocketChannel(Thread):
98 98 """The base class for the channels that use ZMQ sockets."""
99 99 context = None
100 100 session = None
101 101 socket = None
102 102 ioloop = None
103 103 stream = None
104 104 _address = None
105 105 _exiting = False
106 106
107 107 def __init__(self, context, session, address):
108 108 """Create a channel.
109 109
110 110 Parameters
111 111 ----------
112 112 context : :class:`zmq.Context`
113 113 The ZMQ context to use.
114 114 session : :class:`session.Session`
115 115 The session to use.
116 116 address : zmq url
117 117 Standard (ip, port) tuple that the kernel is listening on.
118 118 """
119 119 super(ZMQSocketChannel, self).__init__()
120 120 self.daemon = True
121 121
122 122 self.context = context
123 123 self.session = session
124 124 if isinstance(address, tuple):
125 125 if address[1] == 0:
126 126 message = 'The port number for a channel cannot be 0.'
127 127 raise InvalidPortNumber(message)
128 128 address = "tcp://%s:%i" % address
129 129 self._address = address
130 130 atexit.register(self._notice_exit)
131
131
132 132 def _notice_exit(self):
133 133 self._exiting = True
134 134
135 135 def _run_loop(self):
136 136 """Run my loop, ignoring EINTR events in the poller"""
137 137 while True:
138 138 try:
139 139 self.ioloop.start()
140 140 except ZMQError as e:
141 141 if e.errno == errno.EINTR:
142 142 continue
143 143 else:
144 144 raise
145 145 except Exception:
146 146 if self._exiting:
147 147 break
148 148 else:
149 149 raise
150 150 else:
151 151 break
152 152
153 153 def stop(self):
154 154 """Stop the channel's event loop and join its thread.
155 155
156 156 This calls :method:`Thread.join` and returns when the thread
157 157 terminates. :class:`RuntimeError` will be raised if
158 158 :method:`self.start` is called again.
159 159 """
160 160 self.join()
161 161
162 162 @property
163 163 def address(self):
164 164 """Get the channel's address as a zmq url string.
165 165
166 166 These URLS have the form: 'tcp://127.0.0.1:5555'.
167 167 """
168 168 return self._address
169 169
170 170 def _queue_send(self, msg):
171 171 """Queue a message to be sent from the IOLoop's thread.
172
172
173 173 Parameters
174 174 ----------
175 175 msg : message to send
176
176
177 177 This is threadsafe, as it uses IOLoop.add_callback to give the loop's
178 178 thread control of the action.
179 179 """
180 180 def thread_send():
181 181 self.session.send(self.stream, msg)
182 182 self.ioloop.add_callback(thread_send)
183 183
184 184 def _handle_recv(self, msg):
185 185 """Callback for stream.on_recv.
186 186
187 187 Unpacks message, and calls handlers with it.
188 188 """
189 189 ident,smsg = self.session.feed_identities(msg)
190 190 self.call_handlers(self.session.unserialize(smsg))
191
191
192 192
193 193
194 194 class ShellChannel(ZMQSocketChannel):
195 195 """The shell channel for issuing request/replies to the kernel."""
196 196
197 197 command_queue = None
198 198 # flag for whether execute requests should be allowed to call raw_input:
199 199 allow_stdin = True
200 200
201 201 def __init__(self, context, session, address):
202 202 super(ShellChannel, self).__init__(context, session, address)
203 203 self.ioloop = ioloop.IOLoop()
204 204
205 205 def run(self):
206 206 """The thread's main activity. Call start() instead."""
207 207 self.socket = self.context.socket(zmq.DEALER)
208 208 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
209 209 self.socket.connect(self.address)
210 210 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
211 211 self.stream.on_recv(self._handle_recv)
212 212 self._run_loop()
213 213 try:
214 214 self.socket.close()
215 215 except:
216 216 pass
217 217
218 218 def stop(self):
219 219 """Stop the channel's event loop and join its thread."""
220 220 self.ioloop.stop()
221 221 super(ShellChannel, self).stop()
222 222
223 223 def call_handlers(self, msg):
224 224 """This method is called in the ioloop thread when a message arrives.
225 225
226 226 Subclasses should override this method to handle incoming messages.
227 227 It is important to remember that this method is called in the thread
228 228 so that some logic must be done to ensure that the application leve
229 229 handlers are called in the application thread.
230 230 """
231 231 raise NotImplementedError('call_handlers must be defined in a subclass.')
232 232
233 233 def execute(self, code, silent=False, store_history=True,
234 234 user_variables=None, user_expressions=None, allow_stdin=None):
235 235 """Execute code in the kernel.
236 236
237 237 Parameters
238 238 ----------
239 239 code : str
240 240 A string of Python code.
241 241
242 242 silent : bool, optional (default False)
243 243 If set, the kernel will execute the code as quietly possible, and
244 244 will force store_history to be False.
245 245
246 246 store_history : bool, optional (default True)
247 247 If set, the kernel will store command history. This is forced
248 248 to be False if silent is True.
249 249
250 250 user_variables : list, optional
251 251 A list of variable names to pull from the user's namespace. They
252 252 will come back as a dict with these names as keys and their
253 253 :func:`repr` as values.
254 254
255 255 user_expressions : dict, optional
256 256 A dict mapping names to expressions to be evaluated in the user's
257 257 dict. The expression values are returned as strings formatted using
258 258 :func:`repr`.
259 259
260 260 allow_stdin : bool, optional (default self.allow_stdin)
261 261 Flag for whether the kernel can send stdin requests to frontends.
262 262
263 Some frontends (e.g. the Notebook) do not support stdin requests.
263 Some frontends (e.g. the Notebook) do not support stdin requests.
264 264 If raw_input is called from code executed from such a frontend, a
265 265 StdinNotImplementedError will be raised.
266 266
267 267 Returns
268 268 -------
269 269 The msg_id of the message sent.
270 270 """
271 271 if user_variables is None:
272 272 user_variables = []
273 273 if user_expressions is None:
274 274 user_expressions = {}
275 275 if allow_stdin is None:
276 276 allow_stdin = self.allow_stdin
277
278
277
278
279 279 # Don't waste network traffic if inputs are invalid
280 280 if not isinstance(code, basestring):
281 281 raise ValueError('code %r must be a string' % code)
282 282 validate_string_list(user_variables)
283 283 validate_string_dict(user_expressions)
284 284
285 285 # Create class for content/msg creation. Related to, but possibly
286 286 # not in Session.
287 287 content = dict(code=code, silent=silent, store_history=store_history,
288 288 user_variables=user_variables,
289 289 user_expressions=user_expressions,
290 290 allow_stdin=allow_stdin,
291 291 )
292 292 msg = self.session.msg('execute_request', content)
293 293 self._queue_send(msg)
294 294 return msg['header']['msg_id']
295 295
296 296 def complete(self, text, line, cursor_pos, block=None):
297 297 """Tab complete text in the kernel's namespace.
298 298
299 299 Parameters
300 300 ----------
301 301 text : str
302 302 The text to complete.
303 303 line : str
304 304 The full line of text that is the surrounding context for the
305 305 text to complete.
306 306 cursor_pos : int
307 307 The position of the cursor in the line where the completion was
308 308 requested.
309 309 block : str, optional
310 310 The full block of code in which the completion is being requested.
311 311
312 312 Returns
313 313 -------
314 314 The msg_id of the message sent.
315 315 """
316 316 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
317 317 msg = self.session.msg('complete_request', content)
318 318 self._queue_send(msg)
319 319 return msg['header']['msg_id']
320 320
321 321 def object_info(self, oname, detail_level=0):
322 322 """Get metadata information about an object in the kernel's namespace.
323 323
324 324 Parameters
325 325 ----------
326 326 oname : str
327 327 A string specifying the object name.
328 328 detail_level : int, optional
329 329 The level of detail for the introspection (0-2)
330 330
331 331 Returns
332 332 -------
333 333 The msg_id of the message sent.
334 334 """
335 335 content = dict(oname=oname, detail_level=detail_level)
336 336 msg = self.session.msg('object_info_request', content)
337 337 self._queue_send(msg)
338 338 return msg['header']['msg_id']
339 339
340 340 def history(self, raw=True, output=False, hist_access_type='range', **kwargs):
341 341 """Get entries from the kernel's history list.
342 342
343 343 Parameters
344 344 ----------
345 345 raw : bool
346 346 If True, return the raw input.
347 347 output : bool
348 348 If True, then return the output as well.
349 349 hist_access_type : str
350 350 'range' (fill in session, start and stop params), 'tail' (fill in n)
351 351 or 'search' (fill in pattern param).
352 352
353 353 session : int
354 354 For a range request, the session from which to get lines. Session
355 355 numbers are positive integers; negative ones count back from the
356 356 current session.
357 357 start : int
358 358 The first line number of a history range.
359 359 stop : int
360 360 The final (excluded) line number of a history range.
361 361
362 362 n : int
363 363 The number of lines of history to get for a tail request.
364 364
365 365 pattern : str
366 366 The glob-syntax pattern for a search request.
367 367
368 368 Returns
369 369 -------
370 370 The msg_id of the message sent.
371 371 """
372 372 content = dict(raw=raw, output=output, hist_access_type=hist_access_type,
373 373 **kwargs)
374 374 msg = self.session.msg('history_request', content)
375 375 self._queue_send(msg)
376 376 return msg['header']['msg_id']
377 377
378 378 def kernel_info(self):
379 379 """Request kernel info."""
380 380 msg = self.session.msg('kernel_info_request')
381 381 self._queue_send(msg)
382 382 return msg['header']['msg_id']
383 383
384 384 def shutdown(self, restart=False):
385 385 """Request an immediate kernel shutdown.
386 386
387 387 Upon receipt of the (empty) reply, client code can safely assume that
388 388 the kernel has shut down and it's safe to forcefully terminate it if
389 389 it's still alive.
390 390
391 391 The kernel will send the reply via a function registered with Python's
392 392 atexit module, ensuring it's truly done as the kernel is done with all
393 393 normal operation.
394 394 """
395 395 # Send quit message to kernel. Once we implement kernel-side setattr,
396 396 # this should probably be done that way, but for now this will do.
397 397 msg = self.session.msg('shutdown_request', {'restart':restart})
398 398 self._queue_send(msg)
399 399 return msg['header']['msg_id']
400 400
401 401
402 402
403 403 class IOPubChannel(ZMQSocketChannel):
404 404 """The iopub channel which listens for messages that the kernel publishes.
405 405
406 406 This channel is where all output is published to frontends.
407 407 """
408 408
409 409 def __init__(self, context, session, address):
410 410 super(IOPubChannel, self).__init__(context, session, address)
411 411 self.ioloop = ioloop.IOLoop()
412 412
413 413 def run(self):
414 414 """The thread's main activity. Call start() instead."""
415 415 self.socket = self.context.socket(zmq.SUB)
416 416 self.socket.setsockopt(zmq.SUBSCRIBE,b'')
417 417 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
418 418 self.socket.connect(self.address)
419 419 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
420 420 self.stream.on_recv(self._handle_recv)
421 421 self._run_loop()
422 422 try:
423 423 self.socket.close()
424 424 except:
425 425 pass
426 426
427 427 def stop(self):
428 428 """Stop the channel's event loop and join its thread."""
429 429 self.ioloop.stop()
430 430 super(IOPubChannel, self).stop()
431 431
432 432 def call_handlers(self, msg):
433 433 """This method is called in the ioloop thread when a message arrives.
434 434
435 435 Subclasses should override this method to handle incoming messages.
436 436 It is important to remember that this method is called in the thread
437 437 so that some logic must be done to ensure that the application leve
438 438 handlers are called in the application thread.
439 439 """
440 440 raise NotImplementedError('call_handlers must be defined in a subclass.')
441 441
442 442 def flush(self, timeout=1.0):
443 443 """Immediately processes all pending messages on the iopub channel.
444 444
445 445 Callers should use this method to ensure that :method:`call_handlers`
446 446 has been called for all messages that have been received on the
447 447 0MQ SUB socket of this channel.
448 448
449 449 This method is thread safe.
450 450
451 451 Parameters
452 452 ----------
453 453 timeout : float, optional
454 454 The maximum amount of time to spend flushing, in seconds. The
455 455 default is one second.
456 456 """
457 457 # We do the IOLoop callback process twice to ensure that the IOLoop
458 458 # gets to perform at least one full poll.
459 459 stop_time = time.time() + timeout
460 460 for i in xrange(2):
461 461 self._flushed = False
462 462 self.ioloop.add_callback(self._flush)
463 463 while not self._flushed and time.time() < stop_time:
464 464 time.sleep(0.01)
465 465
466 466 def _flush(self):
467 467 """Callback for :method:`self.flush`."""
468 468 self.stream.flush()
469 469 self._flushed = True
470 470
471 471
472 472 class StdInChannel(ZMQSocketChannel):
473 473 """The stdin channel to handle raw_input requests that the kernel makes."""
474 474
475 475 msg_queue = None
476 476
477 477 def __init__(self, context, session, address):
478 478 super(StdInChannel, self).__init__(context, session, address)
479 479 self.ioloop = ioloop.IOLoop()
480 480
481 481 def run(self):
482 482 """The thread's main activity. Call start() instead."""
483 483 self.socket = self.context.socket(zmq.DEALER)
484 484 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
485 485 self.socket.connect(self.address)
486 486 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
487 487 self.stream.on_recv(self._handle_recv)
488 488 self._run_loop()
489 489 try:
490 490 self.socket.close()
491 491 except:
492 492 pass
493 493
494 494 def stop(self):
495 495 """Stop the channel's event loop and join its thread."""
496 496 self.ioloop.stop()
497 497 super(StdInChannel, self).stop()
498 498
499 499 def call_handlers(self, msg):
500 500 """This method is called in the ioloop thread when a message arrives.
501 501
502 502 Subclasses should override this method to handle incoming messages.
503 503 It is important to remember that this method is called in the thread
504 504 so that some logic must be done to ensure that the application leve
505 505 handlers are called in the application thread.
506 506 """
507 507 raise NotImplementedError('call_handlers must be defined in a subclass.')
508 508
509 509 def input(self, string):
510 510 """Send a string of raw input to the kernel."""
511 511 content = dict(value=string)
512 512 msg = self.session.msg('input_reply', content)
513 513 self._queue_send(msg)
514 514
515 515
516 516 class HBChannel(ZMQSocketChannel):
517 517 """The heartbeat channel which monitors the kernel heartbeat.
518 518
519 519 Note that the heartbeat channel is paused by default. As long as you start
520 520 this channel, the kernel manager will ensure that it is paused and un-paused
521 521 as appropriate.
522 522 """
523 523
524 524 time_to_dead = 3.0
525 525 socket = None
526 526 poller = None
527 527 _running = None
528 528 _pause = None
529 529 _beating = None
530 530
531 531 def __init__(self, context, session, address):
532 532 super(HBChannel, self).__init__(context, session, address)
533 533 self._running = False
534 534 self._pause =True
535 535 self.poller = zmq.Poller()
536 536
537 537 def _create_socket(self):
538 538 if self.socket is not None:
539 539 # close previous socket, before opening a new one
540 540 self.poller.unregister(self.socket)
541 541 self.socket.close()
542 542 self.socket = self.context.socket(zmq.REQ)
543 543 self.socket.setsockopt(zmq.LINGER, 0)
544 544 self.socket.connect(self.address)
545
545
546 546 self.poller.register(self.socket, zmq.POLLIN)
547
547
548 548 def _poll(self, start_time):
549 549 """poll for heartbeat replies until we reach self.time_to_dead.
550
550
551 551 Ignores interrupts, and returns the result of poll(), which
552 552 will be an empty list if no messages arrived before the timeout,
553 553 or the event tuple if there is a message to receive.
554 554 """
555
555
556 556 until_dead = self.time_to_dead - (time.time() - start_time)
557 557 # ensure poll at least once
558 558 until_dead = max(until_dead, 1e-3)
559 559 events = []
560 560 while True:
561 561 try:
562 562 events = self.poller.poll(1000 * until_dead)
563 563 except ZMQError as e:
564 564 if e.errno == errno.EINTR:
565 565 # ignore interrupts during heartbeat
566 566 # this may never actually happen
567 567 until_dead = self.time_to_dead - (time.time() - start_time)
568 568 until_dead = max(until_dead, 1e-3)
569 569 pass
570 570 else:
571 571 raise
572 572 except Exception:
573 573 if self._exiting:
574 574 break
575 575 else:
576 576 raise
577 577 else:
578 578 break
579 579 return events
580 580
581 581 def run(self):
582 582 """The thread's main activity. Call start() instead."""
583 583 self._create_socket()
584 584 self._running = True
585 585 self._beating = True
586
586
587 587 while self._running:
588 588 if self._pause:
589 589 # just sleep, and skip the rest of the loop
590 590 time.sleep(self.time_to_dead)
591 591 continue
592
592
593 593 since_last_heartbeat = 0.0
594 594 # io.rprint('Ping from HB channel') # dbg
595 595 # no need to catch EFSM here, because the previous event was
596 596 # either a recv or connect, which cannot be followed by EFSM
597 597 self.socket.send(b'ping')
598 598 request_time = time.time()
599 599 ready = self._poll(request_time)
600 600 if ready:
601 601 self._beating = True
602 602 # the poll above guarantees we have something to recv
603 603 self.socket.recv()
604 604 # sleep the remainder of the cycle
605 605 remainder = self.time_to_dead - (time.time() - request_time)
606 606 if remainder > 0:
607 607 time.sleep(remainder)
608 608 continue
609 609 else:
610 610 # nothing was received within the time limit, signal heart failure
611 611 self._beating = False
612 612 since_last_heartbeat = time.time() - request_time
613 613 self.call_handlers(since_last_heartbeat)
614 614 # and close/reopen the socket, because the REQ/REP cycle has been broken
615 615 self._create_socket()
616 616 continue
617 617 try:
618 618 self.socket.close()
619 619 except:
620 620 pass
621 621
622 622 def pause(self):
623 623 """Pause the heartbeat."""
624 624 self._pause = True
625 625
626 626 def unpause(self):
627 627 """Unpause the heartbeat."""
628 628 self._pause = False
629 629
630 630 def is_beating(self):
631 631 """Is the heartbeat running and responsive (and not paused)."""
632 632 if self.is_alive() and not self._pause and self._beating:
633 633 return True
634 634 else:
635 635 return False
636 636
637 637 def stop(self):
638 638 """Stop the channel's event loop and join its thread."""
639 639 self._running = False
640 640 super(HBChannel, self).stop()
641 641
642 642 def call_handlers(self, since_last_heartbeat):
643 643 """This method is called in the ioloop thread when a message arrives.
644 644
645 645 Subclasses should override this method to handle incoming messages.
646 646 It is important to remember that this method is called in the thread
647 647 so that some logic must be done to ensure that the application level
648 648 handlers are called in the application thread.
649 649 """
650 650 raise NotImplementedError('call_handlers must be defined in a subclass.')
651 651
652 652
653 653 #-----------------------------------------------------------------------------
654 654 # Main kernel manager class
655 655 #-----------------------------------------------------------------------------
656 656
657 657 class KernelManager(Configurable):
658 658 """Manages a single kernel on this host along with its channels.
659 659
660 660 There are four channels associated with each kernel:
661 661
662 662 * shell: for request/reply calls to the kernel.
663 663 * iopub: for the kernel to publish results to frontends.
664 664 * hb: for monitoring the kernel's heartbeat.
665 665 * stdin: for frontends to reply to raw_input calls in the kernel.
666 666
667 667 The usage of the channels that this class manages is optional. It is
668 668 entirely possible to connect to the kernels directly using ZeroMQ
669 669 sockets. These channels are useful primarily for talking to a kernel
670 670 whose :class:`KernelManager` is in the same process.
671 671
672 672 This version manages kernels started using Popen.
673 673 """
674 674 # The PyZMQ Context to use for communication with the kernel.
675 675 context = Instance(zmq.Context)
676 676 def _context_default(self):
677 677 return zmq.Context.instance()
678 678
679 679 # The Session to use for communication with the kernel.
680 680 session = Instance(Session)
681 681 def _session_default(self):
682 682 return Session(config=self.config)
683 683
684 684 # The kernel process with which the KernelManager is communicating.
685 685 # generally a Popen instance
686 kernel = Any()
687
686 kernel = Any()
687
688 688 kernel_cmd = List(Unicode, config=True,
689 689 help="""The Popen Command to launch the kernel.
690 Override this if you have a custom
690 Override this if you have a custom
691 691 """
692 692 )
693 693
694 694 def _kernel_cmd_changed(self, name, old, new):
695 695 self.ipython_kernel = False
696 696
697 697 ipython_kernel = Bool(True)
698 698
699 699 # The addresses for the communication channels.
700 700 connection_file = Unicode('')
701
701
702 702 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
703 703
704 704 ip = Unicode(LOCALHOST, config=True,
705 705 help="""Set the kernel\'s IP address [default localhost].
706 706 If the IP address is something other than localhost, then
707 707 Consoles on other machines will be able to connect
708 708 to the Kernel, so be careful!"""
709 709 )
710 710
711 711 def _ip_default(self):
712 712 if self.transport == 'ipc':
713 713 if self.connection_file:
714 714 return os.path.splitext(self.connection_file)[0] + '-ipc'
715 715 else:
716 716 return 'kernel-ipc'
717 717 else:
718 718 return LOCALHOST
719 719
720 720 def _ip_changed(self, name, old, new):
721 721 if new == '*':
722 722 self.ip = '0.0.0.0'
723 723
724 724 shell_port = Integer(0)
725 725 iopub_port = Integer(0)
726 726 stdin_port = Integer(0)
727 727 hb_port = Integer(0)
728 728
729 729 # The classes to use for the various channels.
730 730 shell_channel_class = Type(ShellChannel)
731 731 iopub_channel_class = Type(IOPubChannel)
732 732 stdin_channel_class = Type(StdInChannel)
733 733 hb_channel_class = Type(HBChannel)
734 734
735 735 # Protected traits.
736 736 _launch_args = Any
737 737 _shell_channel = Any
738 738 _iopub_channel = Any
739 739 _stdin_channel = Any
740 740 _hb_channel = Any
741 741 _connection_file_written=Bool(False)
742 742
743 743 autorestart = Bool(False, config=True,
744 744 help="""Should we autorestart the kernel if it dies."""
745 745 )
746 746
747 747 def __del__(self):
748 748 self.cleanup_connection_file()
749 749
750 750 #--------------------------------------------------------------------------
751 751 # Channel management methods:
752 752 #--------------------------------------------------------------------------
753 753
754 754 def start_channels(self, shell=True, iopub=True, stdin=True, hb=True):
755 755 """Starts the channels for this kernel.
756 756
757 757 This will create the channels if they do not exist and then start
758 758 them (their activity runs in a thread). If port numbers of 0 are
759 being used (random ports) then you must first call
759 being used (random ports) then you must first call
760 760 :method:`start_kernel`. If the channels have been stopped and you
761 761 call this, :class:`RuntimeError` will be raised.
762 762 """
763 763 if shell:
764 764 self.shell_channel.start()
765 765 if iopub:
766 766 self.iopub_channel.start()
767 767 if stdin:
768 768 self.stdin_channel.start()
769 769 self.shell_channel.allow_stdin = True
770 770 else:
771 771 self.shell_channel.allow_stdin = False
772 772 if hb:
773 773 self.hb_channel.start()
774 774
775 775 def stop_channels(self):
776 776 """Stops all the running channels for this kernel.
777 777
778 778 This stops their event loops and joins their threads.
779 779 """
780 780 if self.shell_channel.is_alive():
781 781 self.shell_channel.stop()
782 782 if self.iopub_channel.is_alive():
783 783 self.iopub_channel.stop()
784 784 if self.stdin_channel.is_alive():
785 785 self.stdin_channel.stop()
786 786 if self.hb_channel.is_alive():
787 787 self.hb_channel.stop()
788 788
789 789 @property
790 790 def channels_running(self):
791 791 """Are any of the channels created and running?"""
792 792 return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or
793 793 self.stdin_channel.is_alive() or self.hb_channel.is_alive())
794 794
795 795 def _make_url(self, port):
796 796 """Make a zmq url with a port.
797 797
798 798 There are two cases that this handles:
799 799
800 800 * tcp: tcp://ip:port
801 801 * ipc: ipc://ip-port
802 802 """
803 803 if self.transport == 'tcp':
804 804 return "tcp://%s:%i" % (self.ip, port)
805 805 else:
806 806 return "%s://%s-%s" % (self.transport, self.ip, port)
807 807
808 808 @property
809 809 def shell_channel(self):
810 810 """Get the shell channel object for this kernel."""
811 811 if self._shell_channel is None:
812 812 self._shell_channel = self.shell_channel_class(
813 813 self.context, self.session, self._make_url(self.shell_port)
814 814 )
815 815 return self._shell_channel
816 816
817 817 @property
818 818 def iopub_channel(self):
819 819 """Get the iopub channel object for this kernel."""
820 820 if self._iopub_channel is None:
821 821 self._iopub_channel = self.iopub_channel_class(
822 822 self.context, self.session, self._make_url(self.iopub_port)
823 823 )
824 824 return self._iopub_channel
825 825
826 826 @property
827 827 def stdin_channel(self):
828 828 """Get the stdin channel object for this kernel."""
829 829 if self._stdin_channel is None:
830 830 self._stdin_channel = self.stdin_channel_class(
831 831 self.context, self.session, self._make_url(self.stdin_port)
832 832 )
833 833 return self._stdin_channel
834 834
835 835 @property
836 836 def hb_channel(self):
837 837 """Get the hb channel object for this kernel."""
838 838 if self._hb_channel is None:
839 839 self._hb_channel = self.hb_channel_class(
840 840 self.context, self.session, self._make_url(self.hb_port)
841 841 )
842 842 return self._hb_channel
843 843
844 844 #--------------------------------------------------------------------------
845 845 # Connection and ipc file management
846 846 #--------------------------------------------------------------------------
847
847
848 848 def cleanup_connection_file(self):
849 849 """Cleanup connection file *if we wrote it*
850
850
851 851 Will not raise if the connection file was already removed somehow.
852 852 """
853 853 if self._connection_file_written:
854 854 # cleanup connection files on full shutdown of kernel we started
855 855 self._connection_file_written = False
856 856 try:
857 857 os.remove(self.connection_file)
858 858 except (IOError, OSError, AttributeError):
859 859 pass
860
860
861 861 def cleanup_ipc_files(self):
862 862 """Cleanup ipc files if we wrote them."""
863 863 if self.transport != 'ipc':
864 864 return
865 865 for port in (self.shell_port, self.iopub_port, self.stdin_port, self.hb_port):
866 866 ipcfile = "%s-%i" % (self.ip, port)
867 867 try:
868 868 os.remove(ipcfile)
869 869 except (IOError, OSError):
870 870 pass
871 871
872 872 def load_connection_file(self):
873 873 """Load connection info from JSON dict in self.connection_file."""
874 874 with open(self.connection_file) as f:
875 875 cfg = json.loads(f.read())
876 876
877 877 from pprint import pprint
878 878 pprint(cfg)
879 879 self.transport = cfg.get('transport', 'tcp')
880 880 self.ip = cfg['ip']
881 881 self.shell_port = cfg['shell_port']
882 882 self.stdin_port = cfg['stdin_port']
883 883 self.iopub_port = cfg['iopub_port']
884 884 self.hb_port = cfg['hb_port']
885 885 self.session.key = str_to_bytes(cfg['key'])
886
886
887 887 def write_connection_file(self):
888 888 """Write connection info to JSON dict in self.connection_file."""
889 889 if self._connection_file_written:
890 890 return
891 891 self.connection_file,cfg = write_connection_file(self.connection_file,
892 892 transport=self.transport, ip=self.ip, key=self.session.key,
893 893 stdin_port=self.stdin_port, iopub_port=self.iopub_port,
894 894 shell_port=self.shell_port, hb_port=self.hb_port)
895 895 # write_connection_file also sets default ports:
896 896 self.shell_port = cfg['shell_port']
897 897 self.stdin_port = cfg['stdin_port']
898 898 self.iopub_port = cfg['iopub_port']
899 899 self.hb_port = cfg['hb_port']
900
900
901 901 self._connection_file_written = True
902 902
903 903 #--------------------------------------------------------------------------
904 904 # Kernel restarter
905 905 #--------------------------------------------------------------------------
906 906
907 907 def start_restarter(self):
908 908 pass
909 909
910 910 def stop_restarter(self):
911 911 pass
912 912
913 913 #--------------------------------------------------------------------------
914 914 # Kernel management
915 915 #--------------------------------------------------------------------------
916 916
917 917 def format_kernel_cmd(self, **kw):
918 918 """format templated args (e.g. {connection_file})"""
919 919 if self.kernel_cmd:
920 920 cmd = self.kernel_cmd
921 921 else:
922 922 cmd = make_ipkernel_cmd(
923 923 'from IPython.kernel.zmq.kernelapp import main; main()',
924 924 **kw
925 925 )
926 926 ns = dict(connection_file=self.connection_file)
927 927 ns.update(self._launch_args)
928 928 return [ c.format(**ns) for c in cmd ]
929
929
930 930 def _launch_kernel(self, kernel_cmd, **kw):
931 931 """actually launch the kernel
932
932
933 933 override in a subclass to launch kernel subprocesses differently
934 934 """
935 935 return launch_kernel(kernel_cmd, **kw)
936
936
937 937 def start_kernel(self, **kw):
938 938 """Starts a kernel on this host in a separate process.
939 939
940 940 If random ports (port=0) are being used, this method must be called
941 941 before the channels are created.
942 942
943 943 Parameters:
944 944 -----------
945 945 **kw : optional
946 946 keyword arguments that are passed down to build the kernel_cmd
947 947 and launching the kernel (e.g. Popen kwargs).
948 948 """
949 949 if self.transport == 'tcp' and self.ip not in LOCAL_IPS:
950 950 raise RuntimeError("Can only launch a kernel on a local interface. "
951 951 "Make sure that the '*_address' attributes are "
952 952 "configured properly. "
953 953 "Currently valid addresses are: %s"%LOCAL_IPS
954 954 )
955
955
956 956 # write connection file / get default ports
957 957 self.write_connection_file()
958 958
959 959 # save kwargs for use in restart
960 960 self._launch_args = kw.copy()
961 961 # build the Popen cmd
962 962 kernel_cmd = self.format_kernel_cmd(**kw)
963 963 # launch the kernel subprocess
964 964 self.kernel = self._launch_kernel(kernel_cmd,
965 965 ipython_kernel=self.ipython_kernel,
966 966 **kw)
967 967 self.start_restarter()
968 968
969 969 def shutdown_kernel(self, now=False, restart=False):
970 """Attempts to the stop the kernel process cleanly.
970 """Attempts to the stop the kernel process cleanly.
971 971
972 972 This attempts to shutdown the kernels cleanly by:
973 973
974 974 1. Sending it a shutdown message over the shell channel.
975 975 2. If that fails, the kernel is shutdown forcibly by sending it
976 976 a signal.
977 977
978 978 Parameters:
979 979 -----------
980 980 now : bool
981 981 Should the kernel be forcible killed *now*. This skips the
982 982 first, nice shutdown attempt.
983 983 restart: bool
984 984 Will this kernel be restarted after it is shutdown. When this
985 985 is True, connection files will not be cleaned up.
986 986 """
987 987
988 988 # Pause the heart beat channel if it exists.
989 989 if self._hb_channel is not None:
990 990 self._hb_channel.pause()
991 991
992 992 # Stop monitoring for restarting while we shutdown.
993 993 self.stop_restarter()
994 994
995 995 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
996 996 if sys.platform == 'win32':
997 997 self._kill_kernel()
998 998 return
999 999
1000 1000 if now:
1001 1001 if self.has_kernel:
1002 1002 self._kill_kernel()
1003 1003 else:
1004 1004 # Don't send any additional kernel kill messages immediately, to give
1005 1005 # the kernel a chance to properly execute shutdown actions. Wait for at
1006 1006 # most 1s, checking every 0.1s.
1007 1007 self.shell_channel.shutdown(restart=restart)
1008 1008 for i in range(10):
1009 1009 if self.is_alive():
1010 1010 time.sleep(0.1)
1011 1011 else:
1012 1012 break
1013 1013 else:
1014 1014 # OK, we've waited long enough.
1015 1015 if self.has_kernel:
1016 1016 self._kill_kernel()
1017 1017
1018 1018 if not restart:
1019 1019 self.cleanup_connection_file()
1020 1020 self.cleanup_ipc_files()
1021 1021 else:
1022 1022 self.cleanup_ipc_files()
1023 1023
1024 1024 def restart_kernel(self, now=False, **kw):
1025 1025 """Restarts a kernel with the arguments that were used to launch it.
1026 1026
1027 1027 If the old kernel was launched with random ports, the same ports will be
1028 1028 used for the new kernel. The same connection file is used again.
1029 1029
1030 1030 Parameters
1031 1031 ----------
1032 1032 now : bool, optional
1033 1033 If True, the kernel is forcefully restarted *immediately*, without
1034 1034 having a chance to do any cleanup action. Otherwise the kernel is
1035 1035 given 1s to clean up before a forceful restart is issued.
1036 1036
1037 1037 In all cases the kernel is restarted, the only difference is whether
1038 1038 it is given a chance to perform a clean shutdown or not.
1039 1039
1040 1040 **kw : optional
1041 1041 Any options specified here will overwrite those used to launch the
1042 1042 kernel.
1043 1043 """
1044 1044 if self._launch_args is None:
1045 1045 raise RuntimeError("Cannot restart the kernel. "
1046 1046 "No previous call to 'start_kernel'.")
1047 1047 else:
1048 1048 # Stop currently running kernel.
1049 1049 self.shutdown_kernel(now=now, restart=True)
1050 1050
1051 1051 # Start new kernel.
1052 1052 self._launch_args.update(kw)
1053 1053 self.start_kernel(**self._launch_args)
1054 1054
1055 1055 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
1056 1056 # unless there is some delay here.
1057 1057 if sys.platform == 'win32':
1058 1058 time.sleep(0.2)
1059 1059
1060 1060 @property
1061 1061 def has_kernel(self):
1062 1062 """Has a kernel been started that we are managing."""
1063 1063 return self.kernel is not None
1064 1064
1065 1065 def _kill_kernel(self):
1066 1066 """Kill the running kernel.
1067 1067
1068 1068 This is a private method, callers should use shutdown_kernel(now=True).
1069 1069 """
1070 1070 if self.has_kernel:
1071 1071
1072 1072 # Signal the kernel to terminate (sends SIGKILL on Unix and calls
1073 1073 # TerminateProcess() on Win32).
1074 1074 try:
1075 1075 self.kernel.kill()
1076 1076 except OSError as e:
1077 1077 # In Windows, we will get an Access Denied error if the process
1078 1078 # has already terminated. Ignore it.
1079 1079 if sys.platform == 'win32':
1080 1080 if e.winerror != 5:
1081 1081 raise
1082 1082 # On Unix, we may get an ESRCH error if the process has already
1083 1083 # terminated. Ignore it.
1084 1084 else:
1085 1085 from errno import ESRCH
1086 1086 if e.errno != ESRCH:
1087 1087 raise
1088 1088
1089 1089 # Block until the kernel terminates.
1090 1090 self.kernel.wait()
1091 1091 self.kernel = None
1092 1092 else:
1093 1093 raise RuntimeError("Cannot kill kernel. No kernel is running!")
1094 1094
1095 1095 def interrupt_kernel(self):
1096 1096 """Interrupts the kernel by sending it a signal.
1097 1097
1098 1098 Unlike ``signal_kernel``, this operation is well supported on all
1099 1099 platforms.
1100 1100 """
1101 1101 if self.has_kernel:
1102 1102 if sys.platform == 'win32':
1103 1103 from .zmq.parentpoller import ParentPollerWindows as Poller
1104 1104 Poller.send_interrupt(self.kernel.win32_interrupt_event)
1105 1105 else:
1106 1106 self.kernel.send_signal(signal.SIGINT)
1107 1107 else:
1108 1108 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
1109 1109
1110 1110 def signal_kernel(self, signum):
1111 1111 """Sends a signal to the kernel.
1112 1112
1113 1113 Note that since only SIGTERM is supported on Windows, this function is
1114 1114 only useful on Unix systems.
1115 1115 """
1116 1116 if self.has_kernel:
1117 1117 self.kernel.send_signal(signum)
1118 1118 else:
1119 1119 raise RuntimeError("Cannot signal kernel. No kernel is running!")
1120 1120
1121 1121 def is_alive(self):
1122 1122 """Is the kernel process still running?"""
1123 1123 if self.has_kernel:
1124 1124 if self.kernel.poll() is None:
1125 1125 return True
1126 1126 else:
1127 1127 return False
1128 1128 elif self._hb_channel is not None:
1129 1129 # We didn't start the kernel with this KernelManager so we
1130 1130 # use the heartbeat.
1131 1131 return self._hb_channel.is_beating()
1132 1132 else:
1133 1133 # no heartbeat and not local, we can't tell if it's running,
1134 1134 # so naively return True
1135 1135 return True
1136 1136
1137 1137
1138 1138 #-----------------------------------------------------------------------------
1139 1139 # ABC Registration
1140 1140 #-----------------------------------------------------------------------------
1141 1141
1142 1142 ShellChannelABC.register(ShellChannel)
1143 1143 IOPubChannelABC.register(IOPubChannel)
1144 1144 HBChannelABC.register(HBChannel)
1145 1145 StdInChannelABC.register(StdInChannel)
1146 1146 KernelManagerABC.register(KernelManager)
1147
@@ -1,226 +1,225 b''
1 1 """Abstract base classes for kernel manager and channels."""
2 2
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (C) 2013 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 # Standard library imports.
15 15 import abc
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Channels
19 19 #-----------------------------------------------------------------------------
20 20
21 21
22 22 class ChannelABC(object):
23 23 """A base class for all channel ABCs."""
24 24
25 25 __metaclass__ = abc.ABCMeta
26 26
27 27 @abc.abstractmethod
28 28 def start(self):
29 29 pass
30 30
31 31 @abc.abstractmethod
32 32 def stop(self):
33 33 pass
34 34
35 35 @abc.abstractmethod
36 36 def is_alive(self):
37 37 pass
38 38
39 39
40 40 class ShellChannelABC(ChannelABC):
41 41 """ShellChannel ABC.
42 42
43 43 The docstrings for this class can be found in the base implementation:
44 44
45 45 `IPython.kernel.kernelmanager.ShellChannel`
46 46 """
47 47
48 48 @abc.abstractproperty
49 49 def allow_stdin(self):
50 50 pass
51 51
52 52 @abc.abstractmethod
53 53 def execute(self, code, silent=False, store_history=True,
54 54 user_variables=None, user_expressions=None, allow_stdin=None):
55 55 pass
56 56
57 57 @abc.abstractmethod
58 58 def complete(self, text, line, cursor_pos, block=None):
59 59 pass
60 60
61 61 @abc.abstractmethod
62 62 def object_info(self, oname, detail_level=0):
63 63 pass
64 64
65 65 @abc.abstractmethod
66 66 def history(self, raw=True, output=False, hist_access_type='range', **kwargs):
67 67 pass
68 68
69 69 @abc.abstractmethod
70 70 def kernel_info(self):
71 71 pass
72 72
73 73 @abc.abstractmethod
74 74 def shutdown(self, restart=False):
75 75 pass
76 76
77 77
78 78 class IOPubChannelABC(ChannelABC):
79 79 """IOPubChannel ABC.
80 80
81 81 The docstrings for this class can be found in the base implementation:
82 82
83 83 `IPython.kernel.kernelmanager.IOPubChannel`
84 84 """
85 85
86 86 @abc.abstractmethod
87 87 def flush(self, timeout=1.0):
88 88 pass
89 89
90 90
91 91 class StdInChannelABC(ChannelABC):
92 92 """StdInChannel ABC.
93 93
94 94 The docstrings for this class can be found in the base implementation:
95 95
96 96 `IPython.kernel.kernelmanager.StdInChannel`
97 97 """
98 98
99 99 @abc.abstractmethod
100 100 def input(self, string):
101 101 pass
102 102
103 103
104 104 class HBChannelABC(ChannelABC):
105 105 """HBChannel ABC.
106 106
107 107 The docstrings for this class can be found in the base implementation:
108 108
109 109 `IPython.kernel.kernelmanager.HBChannel`
110 110 """
111 111
112 112 @abc.abstractproperty
113 113 def time_to_dead(self):
114 114 pass
115 115
116 116 @abc.abstractmethod
117 117 def pause(self):
118 118 pass
119 119
120 120 @abc.abstractmethod
121 121 def unpause(self):
122 122 pass
123 123
124 124 @abc.abstractmethod
125 125 def is_beating(self):
126 126 pass
127 127
128 128
129 129 #-----------------------------------------------------------------------------
130 130 # Main kernel manager class
131 131 #-----------------------------------------------------------------------------
132 132
133 133 class KernelManagerABC(object):
134 134 """KernelManager ABC.
135 135
136 136 The docstrings for this class can be found in the base implementation:
137 137
138 138 `IPython.kernel.kernelmanager.KernelManager`
139 139 """
140 140
141 141 __metaclass__ = abc.ABCMeta
142 142
143 143 @abc.abstractproperty
144 144 def kernel(self):
145 145 pass
146 146
147 147 @abc.abstractproperty
148 148 def shell_channel_class(self):
149 149 pass
150 150
151 151 @abc.abstractproperty
152 152 def iopub_channel_class(self):
153 153 pass
154 154
155 155 @abc.abstractproperty
156 156 def hb_channel_class(self):
157 157 pass
158 158
159 159 @abc.abstractproperty
160 160 def stdin_channel_class(self):
161 161 pass
162 162
163 163 #--------------------------------------------------------------------------
164 164 # Channel management methods
165 165 #--------------------------------------------------------------------------
166 166
167 167 @abc.abstractmethod
168 168 def start_channels(self, shell=True, iopub=True, stdin=True, hb=True):
169 169 pass
170 170
171 171 @abc.abstractmethod
172 172 def stop_channels(self):
173 173 pass
174 174
175 175 @abc.abstractproperty
176 176 def channels_running(self):
177 177 pass
178 178
179 179 @abc.abstractproperty
180 180 def shell_channel(self):
181 181 pass
182 182
183 183 @abc.abstractproperty
184 184 def iopub_channel(self):
185 185 pass
186 186
187 187 @abc.abstractproperty
188 188 def stdin_channel(self):
189 189 pass
190 190
191 191 @abc.abstractproperty
192 192 def hb_channel(self):
193 193 pass
194 194
195 195 #--------------------------------------------------------------------------
196 196 # Kernel management
197 197 #--------------------------------------------------------------------------
198 198
199 199 @abc.abstractmethod
200 200 def start_kernel(self, **kw):
201 201 pass
202 202
203 203 @abc.abstractmethod
204 204 def shutdown_kernel(self, now=False, restart=False):
205 205 pass
206 206
207 207 @abc.abstractmethod
208 208 def restart_kernel(self, now=False, **kw):
209 209 pass
210 210
211 211 @abc.abstractproperty
212 212 def has_kernel(self):
213 213 pass
214 214
215 215 @abc.abstractmethod
216 216 def interrupt_kernel(self):
217 217 pass
218 218
219 219 @abc.abstractmethod
220 220 def signal_kernel(self, signum):
221 221 pass
222 222
223 223 @abc.abstractmethod
224 224 def is_alive(self):
225 225 pass
226
General Comments 0
You need to be logged in to leave comments. Login now