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