##// END OF EJS Templates
ensure excepthook is restored in OSXKernel mainloop...
MinRK -
Show More
@@ -1,769 +1,773 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import __builtin__
19 import __builtin__
20 import atexit
20 import atexit
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24 import logging
24 import logging
25 # System library imports.
25 # System library imports.
26 import zmq
26 import zmq
27
27
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.config.application import boolean_flag
30 from IPython.config.application import boolean_flag
31 from IPython.core.application import ProfileDir
31 from IPython.core.application import ProfileDir
32 from IPython.core.shellapp import (
32 from IPython.core.shellapp import (
33 InteractiveShellApp, shell_flags, shell_aliases
33 InteractiveShellApp, shell_flags, shell_aliases
34 )
34 )
35 from IPython.utils import io
35 from IPython.utils import io
36 from IPython.utils import py3compat
36 from IPython.utils import py3compat
37 from IPython.utils.jsonutil import json_clean
37 from IPython.utils.jsonutil import json_clean
38 from IPython.lib import pylabtools
38 from IPython.lib import pylabtools
39 from IPython.utils.traitlets import (
39 from IPython.utils.traitlets import (
40 List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
40 List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
41 )
41 )
42
42
43 from entry_point import base_launch_kernel
43 from entry_point import base_launch_kernel
44 from kernelapp import KernelApp, kernel_flags, kernel_aliases
44 from kernelapp import KernelApp, kernel_flags, kernel_aliases
45 from iostream import OutStream
45 from iostream import OutStream
46 from session import Session, Message
46 from session import Session, Message
47 from zmqshell import ZMQInteractiveShell
47 from zmqshell import ZMQInteractiveShell
48
48
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Main kernel class
51 # Main kernel class
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 class Kernel(Configurable):
54 class Kernel(Configurable):
55
55
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57 # Kernel interface
57 # Kernel interface
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59
59
60 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
60 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
61 session = Instance(Session)
61 session = Instance(Session)
62 shell_socket = Instance('zmq.Socket')
62 shell_socket = Instance('zmq.Socket')
63 iopub_socket = Instance('zmq.Socket')
63 iopub_socket = Instance('zmq.Socket')
64 stdin_socket = Instance('zmq.Socket')
64 stdin_socket = Instance('zmq.Socket')
65 log = Instance(logging.Logger)
65 log = Instance(logging.Logger)
66
66
67 # Private interface
67 # Private interface
68
68
69 # Time to sleep after flushing the stdout/err buffers in each execute
69 # Time to sleep after flushing the stdout/err buffers in each execute
70 # cycle. While this introduces a hard limit on the minimal latency of the
70 # cycle. While this introduces a hard limit on the minimal latency of the
71 # execute cycle, it helps prevent output synchronization problems for
71 # execute cycle, it helps prevent output synchronization problems for
72 # clients.
72 # clients.
73 # Units are in seconds. The minimum zmq latency on local host is probably
73 # Units are in seconds. The minimum zmq latency on local host is probably
74 # ~150 microseconds, set this to 500us for now. We may need to increase it
74 # ~150 microseconds, set this to 500us for now. We may need to increase it
75 # a little if it's not enough after more interactive testing.
75 # a little if it's not enough after more interactive testing.
76 _execute_sleep = Float(0.0005, config=True)
76 _execute_sleep = Float(0.0005, config=True)
77
77
78 # Frequency of the kernel's event loop.
78 # Frequency of the kernel's event loop.
79 # Units are in seconds, kernel subclasses for GUI toolkits may need to
79 # Units are in seconds, kernel subclasses for GUI toolkits may need to
80 # adapt to milliseconds.
80 # adapt to milliseconds.
81 _poll_interval = Float(0.05, config=True)
81 _poll_interval = Float(0.05, config=True)
82
82
83 # If the shutdown was requested over the network, we leave here the
83 # If the shutdown was requested over the network, we leave here the
84 # necessary reply message so it can be sent by our registered atexit
84 # necessary reply message so it can be sent by our registered atexit
85 # handler. This ensures that the reply is only sent to clients truly at
85 # handler. This ensures that the reply is only sent to clients truly at
86 # the end of our shutdown process (which happens after the underlying
86 # the end of our shutdown process (which happens after the underlying
87 # IPython shell's own shutdown).
87 # IPython shell's own shutdown).
88 _shutdown_message = None
88 _shutdown_message = None
89
89
90 # This is a dict of port number that the kernel is listening on. It is set
90 # This is a dict of port number that the kernel is listening on. It is set
91 # by record_ports and used by connect_request.
91 # by record_ports and used by connect_request.
92 _recorded_ports = Dict()
92 _recorded_ports = Dict()
93
93
94
94
95
95
96 def __init__(self, **kwargs):
96 def __init__(self, **kwargs):
97 super(Kernel, self).__init__(**kwargs)
97 super(Kernel, self).__init__(**kwargs)
98
98
99 # Before we even start up the shell, register *first* our exit handlers
99 # Before we even start up the shell, register *first* our exit handlers
100 # so they come before the shell's
100 # so they come before the shell's
101 atexit.register(self._at_shutdown)
101 atexit.register(self._at_shutdown)
102
102
103 # Initialize the InteractiveShell subclass
103 # Initialize the InteractiveShell subclass
104 self.shell = ZMQInteractiveShell.instance(config=self.config)
104 self.shell = ZMQInteractiveShell.instance(config=self.config)
105 self.shell.displayhook.session = self.session
105 self.shell.displayhook.session = self.session
106 self.shell.displayhook.pub_socket = self.iopub_socket
106 self.shell.displayhook.pub_socket = self.iopub_socket
107 self.shell.display_pub.session = self.session
107 self.shell.display_pub.session = self.session
108 self.shell.display_pub.pub_socket = self.iopub_socket
108 self.shell.display_pub.pub_socket = self.iopub_socket
109
109
110 # TMP - hack while developing
110 # TMP - hack while developing
111 self.shell._reply_content = None
111 self.shell._reply_content = None
112
112
113 # Build dict of handlers for message types
113 # Build dict of handlers for message types
114 msg_types = [ 'execute_request', 'complete_request',
114 msg_types = [ 'execute_request', 'complete_request',
115 'object_info_request', 'history_request',
115 'object_info_request', 'history_request',
116 'connect_request', 'shutdown_request']
116 'connect_request', 'shutdown_request']
117 self.handlers = {}
117 self.handlers = {}
118 for msg_type in msg_types:
118 for msg_type in msg_types:
119 self.handlers[msg_type] = getattr(self, msg_type)
119 self.handlers[msg_type] = getattr(self, msg_type)
120
120
121 def do_one_iteration(self):
121 def do_one_iteration(self):
122 """Do one iteration of the kernel's evaluation loop.
122 """Do one iteration of the kernel's evaluation loop.
123 """
123 """
124 try:
124 try:
125 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
125 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
126 except Exception:
126 except Exception:
127 self.log.warn("Invalid Message:", exc_info=True)
127 self.log.warn("Invalid Message:", exc_info=True)
128 return
128 return
129 if msg is None:
129 if msg is None:
130 return
130 return
131
131
132 msg_type = msg['header']['msg_type']
132 msg_type = msg['header']['msg_type']
133
133
134 # This assert will raise in versions of zeromq 2.0.7 and lesser.
134 # This assert will raise in versions of zeromq 2.0.7 and lesser.
135 # We now require 2.0.8 or above, so we can uncomment for safety.
135 # We now require 2.0.8 or above, so we can uncomment for safety.
136 # print(ident,msg, file=sys.__stdout__)
136 # print(ident,msg, file=sys.__stdout__)
137 assert ident is not None, "Missing message part."
137 assert ident is not None, "Missing message part."
138
138
139 # Print some info about this message and leave a '--->' marker, so it's
139 # Print some info about this message and leave a '--->' marker, so it's
140 # easier to trace visually the message chain when debugging. Each
140 # easier to trace visually the message chain when debugging. Each
141 # handler prints its message at the end.
141 # handler prints its message at the end.
142 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
142 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
143 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
143 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
144
144
145 # Find and call actual handler for message
145 # Find and call actual handler for message
146 handler = self.handlers.get(msg_type, None)
146 handler = self.handlers.get(msg_type, None)
147 if handler is None:
147 if handler is None:
148 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
148 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
149 else:
149 else:
150 handler(ident, msg)
150 handler(ident, msg)
151
151
152 # Check whether we should exit, in case the incoming message set the
152 # Check whether we should exit, in case the incoming message set the
153 # exit flag on
153 # exit flag on
154 if self.shell.exit_now:
154 if self.shell.exit_now:
155 self.log.debug('\nExiting IPython kernel...')
155 self.log.debug('\nExiting IPython kernel...')
156 # We do a normal, clean exit, which allows any actions registered
156 # We do a normal, clean exit, which allows any actions registered
157 # via atexit (such as history saving) to take place.
157 # via atexit (such as history saving) to take place.
158 sys.exit(0)
158 sys.exit(0)
159
159
160
160
161 def start(self):
161 def start(self):
162 """ Start the kernel main loop.
162 """ Start the kernel main loop.
163 """
163 """
164 poller = zmq.Poller()
164 poller = zmq.Poller()
165 poller.register(self.shell_socket, zmq.POLLIN)
165 poller.register(self.shell_socket, zmq.POLLIN)
166 while True:
166 while True:
167 try:
167 try:
168 # scale by extra factor of 10, because there is no
168 # scale by extra factor of 10, because there is no
169 # reason for this to be anything less than ~ 0.1s
169 # reason for this to be anything less than ~ 0.1s
170 # since it is a real poller and will respond
170 # since it is a real poller and will respond
171 # to events immediately
171 # to events immediately
172
172
173 # double nested try/except, to properly catch KeyboardInterrupt
173 # double nested try/except, to properly catch KeyboardInterrupt
174 # due to pyzmq Issue #130
174 # due to pyzmq Issue #130
175 try:
175 try:
176 poller.poll(10*1000*self._poll_interval)
176 poller.poll(10*1000*self._poll_interval)
177 self.do_one_iteration()
177 self.do_one_iteration()
178 except:
178 except:
179 raise
179 raise
180 except KeyboardInterrupt:
180 except KeyboardInterrupt:
181 # Ctrl-C shouldn't crash the kernel
181 # Ctrl-C shouldn't crash the kernel
182 io.raw_print("KeyboardInterrupt caught in kernel")
182 io.raw_print("KeyboardInterrupt caught in kernel")
183
183
184 def record_ports(self, ports):
184 def record_ports(self, ports):
185 """Record the ports that this kernel is using.
185 """Record the ports that this kernel is using.
186
186
187 The creator of the Kernel instance must call this methods if they
187 The creator of the Kernel instance must call this methods if they
188 want the :meth:`connect_request` method to return the port numbers.
188 want the :meth:`connect_request` method to return the port numbers.
189 """
189 """
190 self._recorded_ports = ports
190 self._recorded_ports = ports
191
191
192 #---------------------------------------------------------------------------
192 #---------------------------------------------------------------------------
193 # Kernel request handlers
193 # Kernel request handlers
194 #---------------------------------------------------------------------------
194 #---------------------------------------------------------------------------
195
195
196 def _publish_pyin(self, code, parent):
196 def _publish_pyin(self, code, parent):
197 """Publish the code request on the pyin stream."""
197 """Publish the code request on the pyin stream."""
198
198
199 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
199 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
200
200
201 def execute_request(self, ident, parent):
201 def execute_request(self, ident, parent):
202
202
203 status_msg = self.session.send(self.iopub_socket,
203 status_msg = self.session.send(self.iopub_socket,
204 u'status',
204 u'status',
205 {u'execution_state':u'busy'},
205 {u'execution_state':u'busy'},
206 parent=parent
206 parent=parent
207 )
207 )
208
208
209 try:
209 try:
210 content = parent[u'content']
210 content = parent[u'content']
211 code = content[u'code']
211 code = content[u'code']
212 silent = content[u'silent']
212 silent = content[u'silent']
213 except:
213 except:
214 self.log.error("Got bad msg: ")
214 self.log.error("Got bad msg: ")
215 self.log.error(str(Message(parent)))
215 self.log.error(str(Message(parent)))
216 return
216 return
217
217
218 shell = self.shell # we'll need this a lot here
218 shell = self.shell # we'll need this a lot here
219
219
220 # Replace raw_input. Note that is not sufficient to replace
220 # Replace raw_input. Note that is not sufficient to replace
221 # raw_input in the user namespace.
221 # raw_input in the user namespace.
222 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
222 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
223 if py3compat.PY3:
223 if py3compat.PY3:
224 __builtin__.input = raw_input
224 __builtin__.input = raw_input
225 else:
225 else:
226 __builtin__.raw_input = raw_input
226 __builtin__.raw_input = raw_input
227
227
228 # Set the parent message of the display hook and out streams.
228 # Set the parent message of the display hook and out streams.
229 shell.displayhook.set_parent(parent)
229 shell.displayhook.set_parent(parent)
230 shell.display_pub.set_parent(parent)
230 shell.display_pub.set_parent(parent)
231 sys.stdout.set_parent(parent)
231 sys.stdout.set_parent(parent)
232 sys.stderr.set_parent(parent)
232 sys.stderr.set_parent(parent)
233
233
234 # Re-broadcast our input for the benefit of listening clients, and
234 # Re-broadcast our input for the benefit of listening clients, and
235 # start computing output
235 # start computing output
236 if not silent:
236 if not silent:
237 self._publish_pyin(code, parent)
237 self._publish_pyin(code, parent)
238
238
239 reply_content = {}
239 reply_content = {}
240 try:
240 try:
241 if silent:
241 if silent:
242 # run_code uses 'exec' mode, so no displayhook will fire, and it
242 # run_code uses 'exec' mode, so no displayhook will fire, and it
243 # doesn't call logging or history manipulations. Print
243 # doesn't call logging or history manipulations. Print
244 # statements in that code will obviously still execute.
244 # statements in that code will obviously still execute.
245 shell.run_code(code)
245 shell.run_code(code)
246 else:
246 else:
247 # FIXME: the shell calls the exception handler itself.
247 # FIXME: the shell calls the exception handler itself.
248 shell.run_cell(code)
248 shell.run_cell(code)
249 except:
249 except:
250 status = u'error'
250 status = u'error'
251 # FIXME: this code right now isn't being used yet by default,
251 # FIXME: this code right now isn't being used yet by default,
252 # because the run_cell() call above directly fires off exception
252 # because the run_cell() call above directly fires off exception
253 # reporting. This code, therefore, is only active in the scenario
253 # reporting. This code, therefore, is only active in the scenario
254 # where runlines itself has an unhandled exception. We need to
254 # where runlines itself has an unhandled exception. We need to
255 # uniformize this, for all exception construction to come from a
255 # uniformize this, for all exception construction to come from a
256 # single location in the codbase.
256 # single location in the codbase.
257 etype, evalue, tb = sys.exc_info()
257 etype, evalue, tb = sys.exc_info()
258 tb_list = traceback.format_exception(etype, evalue, tb)
258 tb_list = traceback.format_exception(etype, evalue, tb)
259 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
259 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
260 else:
260 else:
261 status = u'ok'
261 status = u'ok'
262
262
263 reply_content[u'status'] = status
263 reply_content[u'status'] = status
264
264
265 # Return the execution counter so clients can display prompts
265 # Return the execution counter so clients can display prompts
266 reply_content['execution_count'] = shell.execution_count -1
266 reply_content['execution_count'] = shell.execution_count -1
267
267
268 # FIXME - fish exception info out of shell, possibly left there by
268 # FIXME - fish exception info out of shell, possibly left there by
269 # runlines. We'll need to clean up this logic later.
269 # runlines. We'll need to clean up this logic later.
270 if shell._reply_content is not None:
270 if shell._reply_content is not None:
271 reply_content.update(shell._reply_content)
271 reply_content.update(shell._reply_content)
272 # reset after use
272 # reset after use
273 shell._reply_content = None
273 shell._reply_content = None
274
274
275 # At this point, we can tell whether the main code execution succeeded
275 # At this point, we can tell whether the main code execution succeeded
276 # or not. If it did, we proceed to evaluate user_variables/expressions
276 # or not. If it did, we proceed to evaluate user_variables/expressions
277 if reply_content['status'] == 'ok':
277 if reply_content['status'] == 'ok':
278 reply_content[u'user_variables'] = \
278 reply_content[u'user_variables'] = \
279 shell.user_variables(content[u'user_variables'])
279 shell.user_variables(content[u'user_variables'])
280 reply_content[u'user_expressions'] = \
280 reply_content[u'user_expressions'] = \
281 shell.user_expressions(content[u'user_expressions'])
281 shell.user_expressions(content[u'user_expressions'])
282 else:
282 else:
283 # If there was an error, don't even try to compute variables or
283 # If there was an error, don't even try to compute variables or
284 # expressions
284 # expressions
285 reply_content[u'user_variables'] = {}
285 reply_content[u'user_variables'] = {}
286 reply_content[u'user_expressions'] = {}
286 reply_content[u'user_expressions'] = {}
287
287
288 # Payloads should be retrieved regardless of outcome, so we can both
288 # Payloads should be retrieved regardless of outcome, so we can both
289 # recover partial output (that could have been generated early in a
289 # recover partial output (that could have been generated early in a
290 # block, before an error) and clear the payload system always.
290 # block, before an error) and clear the payload system always.
291 reply_content[u'payload'] = shell.payload_manager.read_payload()
291 reply_content[u'payload'] = shell.payload_manager.read_payload()
292 # Be agressive about clearing the payload because we don't want
292 # Be agressive about clearing the payload because we don't want
293 # it to sit in memory until the next execute_request comes in.
293 # it to sit in memory until the next execute_request comes in.
294 shell.payload_manager.clear_payload()
294 shell.payload_manager.clear_payload()
295
295
296 # Flush output before sending the reply.
296 # Flush output before sending the reply.
297 sys.stdout.flush()
297 sys.stdout.flush()
298 sys.stderr.flush()
298 sys.stderr.flush()
299 # FIXME: on rare occasions, the flush doesn't seem to make it to the
299 # FIXME: on rare occasions, the flush doesn't seem to make it to the
300 # clients... This seems to mitigate the problem, but we definitely need
300 # clients... This seems to mitigate the problem, but we definitely need
301 # to better understand what's going on.
301 # to better understand what's going on.
302 if self._execute_sleep:
302 if self._execute_sleep:
303 time.sleep(self._execute_sleep)
303 time.sleep(self._execute_sleep)
304
304
305 # Send the reply.
305 # Send the reply.
306 reply_content = json_clean(reply_content)
306 reply_content = json_clean(reply_content)
307 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
307 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
308 reply_content, parent, ident=ident)
308 reply_content, parent, ident=ident)
309 self.log.debug(str(reply_msg))
309 self.log.debug(str(reply_msg))
310
310
311 if reply_msg['content']['status'] == u'error':
311 if reply_msg['content']['status'] == u'error':
312 self._abort_queue()
312 self._abort_queue()
313
313
314 status_msg = self.session.send(self.iopub_socket,
314 status_msg = self.session.send(self.iopub_socket,
315 u'status',
315 u'status',
316 {u'execution_state':u'idle'},
316 {u'execution_state':u'idle'},
317 parent=parent
317 parent=parent
318 )
318 )
319
319
320 def complete_request(self, ident, parent):
320 def complete_request(self, ident, parent):
321 txt, matches = self._complete(parent)
321 txt, matches = self._complete(parent)
322 matches = {'matches' : matches,
322 matches = {'matches' : matches,
323 'matched_text' : txt,
323 'matched_text' : txt,
324 'status' : 'ok'}
324 'status' : 'ok'}
325 matches = json_clean(matches)
325 matches = json_clean(matches)
326 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
326 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
327 matches, parent, ident)
327 matches, parent, ident)
328 self.log.debug(str(completion_msg))
328 self.log.debug(str(completion_msg))
329
329
330 def object_info_request(self, ident, parent):
330 def object_info_request(self, ident, parent):
331 object_info = self.shell.object_inspect(parent['content']['oname'])
331 object_info = self.shell.object_inspect(parent['content']['oname'])
332 # Before we send this object over, we scrub it for JSON usage
332 # Before we send this object over, we scrub it for JSON usage
333 oinfo = json_clean(object_info)
333 oinfo = json_clean(object_info)
334 msg = self.session.send(self.shell_socket, 'object_info_reply',
334 msg = self.session.send(self.shell_socket, 'object_info_reply',
335 oinfo, parent, ident)
335 oinfo, parent, ident)
336 self.log.debug(msg)
336 self.log.debug(msg)
337
337
338 def history_request(self, ident, parent):
338 def history_request(self, ident, parent):
339 # We need to pull these out, as passing **kwargs doesn't work with
339 # We need to pull these out, as passing **kwargs doesn't work with
340 # unicode keys before Python 2.6.5.
340 # unicode keys before Python 2.6.5.
341 hist_access_type = parent['content']['hist_access_type']
341 hist_access_type = parent['content']['hist_access_type']
342 raw = parent['content']['raw']
342 raw = parent['content']['raw']
343 output = parent['content']['output']
343 output = parent['content']['output']
344 if hist_access_type == 'tail':
344 if hist_access_type == 'tail':
345 n = parent['content']['n']
345 n = parent['content']['n']
346 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
346 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
347 include_latest=True)
347 include_latest=True)
348
348
349 elif hist_access_type == 'range':
349 elif hist_access_type == 'range':
350 session = parent['content']['session']
350 session = parent['content']['session']
351 start = parent['content']['start']
351 start = parent['content']['start']
352 stop = parent['content']['stop']
352 stop = parent['content']['stop']
353 hist = self.shell.history_manager.get_range(session, start, stop,
353 hist = self.shell.history_manager.get_range(session, start, stop,
354 raw=raw, output=output)
354 raw=raw, output=output)
355
355
356 elif hist_access_type == 'search':
356 elif hist_access_type == 'search':
357 pattern = parent['content']['pattern']
357 pattern = parent['content']['pattern']
358 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
358 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
359
359
360 else:
360 else:
361 hist = []
361 hist = []
362 content = {'history' : list(hist)}
362 content = {'history' : list(hist)}
363 content = json_clean(content)
363 content = json_clean(content)
364 msg = self.session.send(self.shell_socket, 'history_reply',
364 msg = self.session.send(self.shell_socket, 'history_reply',
365 content, parent, ident)
365 content, parent, ident)
366 self.log.debug(str(msg))
366 self.log.debug(str(msg))
367
367
368 def connect_request(self, ident, parent):
368 def connect_request(self, ident, parent):
369 if self._recorded_ports is not None:
369 if self._recorded_ports is not None:
370 content = self._recorded_ports.copy()
370 content = self._recorded_ports.copy()
371 else:
371 else:
372 content = {}
372 content = {}
373 msg = self.session.send(self.shell_socket, 'connect_reply',
373 msg = self.session.send(self.shell_socket, 'connect_reply',
374 content, parent, ident)
374 content, parent, ident)
375 self.log.debug(msg)
375 self.log.debug(msg)
376
376
377 def shutdown_request(self, ident, parent):
377 def shutdown_request(self, ident, parent):
378 self.shell.exit_now = True
378 self.shell.exit_now = True
379 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
379 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
380 sys.exit(0)
380 sys.exit(0)
381
381
382 #---------------------------------------------------------------------------
382 #---------------------------------------------------------------------------
383 # Protected interface
383 # Protected interface
384 #---------------------------------------------------------------------------
384 #---------------------------------------------------------------------------
385
385
386 def _abort_queue(self):
386 def _abort_queue(self):
387 while True:
387 while True:
388 try:
388 try:
389 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
389 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
390 except Exception:
390 except Exception:
391 self.log.warn("Invalid Message:", exc_info=True)
391 self.log.warn("Invalid Message:", exc_info=True)
392 continue
392 continue
393 if msg is None:
393 if msg is None:
394 break
394 break
395 else:
395 else:
396 assert ident is not None, \
396 assert ident is not None, \
397 "Unexpected missing message part."
397 "Unexpected missing message part."
398
398
399 self.log.debug("Aborting:\n"+str(Message(msg)))
399 self.log.debug("Aborting:\n"+str(Message(msg)))
400 msg_type = msg['header']['msg_type']
400 msg_type = msg['header']['msg_type']
401 reply_type = msg_type.split('_')[0] + '_reply'
401 reply_type = msg_type.split('_')[0] + '_reply'
402 reply_msg = self.session.send(self.shell_socket, reply_type,
402 reply_msg = self.session.send(self.shell_socket, reply_type,
403 {'status' : 'aborted'}, msg, ident=ident)
403 {'status' : 'aborted'}, msg, ident=ident)
404 self.log.debug(reply_msg)
404 self.log.debug(reply_msg)
405 # We need to wait a bit for requests to come in. This can probably
405 # We need to wait a bit for requests to come in. This can probably
406 # be set shorter for true asynchronous clients.
406 # be set shorter for true asynchronous clients.
407 time.sleep(0.1)
407 time.sleep(0.1)
408
408
409 def _raw_input(self, prompt, ident, parent):
409 def _raw_input(self, prompt, ident, parent):
410 # Flush output before making the request.
410 # Flush output before making the request.
411 sys.stderr.flush()
411 sys.stderr.flush()
412 sys.stdout.flush()
412 sys.stdout.flush()
413
413
414 # Send the input request.
414 # Send the input request.
415 content = json_clean(dict(prompt=prompt))
415 content = json_clean(dict(prompt=prompt))
416 msg = self.session.send(self.stdin_socket, u'input_request', content, parent)
416 msg = self.session.send(self.stdin_socket, u'input_request', content, parent)
417
417
418 # Await a response.
418 # Await a response.
419 while True:
419 while True:
420 try:
420 try:
421 ident, reply = self.session.recv(self.stdin_socket, 0)
421 ident, reply = self.session.recv(self.stdin_socket, 0)
422 except Exception:
422 except Exception:
423 self.log.warn("Invalid Message:", exc_info=True)
423 self.log.warn("Invalid Message:", exc_info=True)
424 else:
424 else:
425 break
425 break
426 try:
426 try:
427 value = reply['content']['value']
427 value = reply['content']['value']
428 except:
428 except:
429 self.log.error("Got bad raw_input reply: ")
429 self.log.error("Got bad raw_input reply: ")
430 self.log.error(str(Message(parent)))
430 self.log.error(str(Message(parent)))
431 value = ''
431 value = ''
432 return value
432 return value
433
433
434 def _complete(self, msg):
434 def _complete(self, msg):
435 c = msg['content']
435 c = msg['content']
436 try:
436 try:
437 cpos = int(c['cursor_pos'])
437 cpos = int(c['cursor_pos'])
438 except:
438 except:
439 # If we don't get something that we can convert to an integer, at
439 # If we don't get something that we can convert to an integer, at
440 # least attempt the completion guessing the cursor is at the end of
440 # least attempt the completion guessing the cursor is at the end of
441 # the text, if there's any, and otherwise of the line
441 # the text, if there's any, and otherwise of the line
442 cpos = len(c['text'])
442 cpos = len(c['text'])
443 if cpos==0:
443 if cpos==0:
444 cpos = len(c['line'])
444 cpos = len(c['line'])
445 return self.shell.complete(c['text'], c['line'], cpos)
445 return self.shell.complete(c['text'], c['line'], cpos)
446
446
447 def _object_info(self, context):
447 def _object_info(self, context):
448 symbol, leftover = self._symbol_from_context(context)
448 symbol, leftover = self._symbol_from_context(context)
449 if symbol is not None and not leftover:
449 if symbol is not None and not leftover:
450 doc = getattr(symbol, '__doc__', '')
450 doc = getattr(symbol, '__doc__', '')
451 else:
451 else:
452 doc = ''
452 doc = ''
453 object_info = dict(docstring = doc)
453 object_info = dict(docstring = doc)
454 return object_info
454 return object_info
455
455
456 def _symbol_from_context(self, context):
456 def _symbol_from_context(self, context):
457 if not context:
457 if not context:
458 return None, context
458 return None, context
459
459
460 base_symbol_string = context[0]
460 base_symbol_string = context[0]
461 symbol = self.shell.user_ns.get(base_symbol_string, None)
461 symbol = self.shell.user_ns.get(base_symbol_string, None)
462 if symbol is None:
462 if symbol is None:
463 symbol = __builtin__.__dict__.get(base_symbol_string, None)
463 symbol = __builtin__.__dict__.get(base_symbol_string, None)
464 if symbol is None:
464 if symbol is None:
465 return None, context
465 return None, context
466
466
467 context = context[1:]
467 context = context[1:]
468 for i, name in enumerate(context):
468 for i, name in enumerate(context):
469 new_symbol = getattr(symbol, name, None)
469 new_symbol = getattr(symbol, name, None)
470 if new_symbol is None:
470 if new_symbol is None:
471 return symbol, context[i:]
471 return symbol, context[i:]
472 else:
472 else:
473 symbol = new_symbol
473 symbol = new_symbol
474
474
475 return symbol, []
475 return symbol, []
476
476
477 def _at_shutdown(self):
477 def _at_shutdown(self):
478 """Actions taken at shutdown by the kernel, called by python's atexit.
478 """Actions taken at shutdown by the kernel, called by python's atexit.
479 """
479 """
480 # io.rprint("Kernel at_shutdown") # dbg
480 # io.rprint("Kernel at_shutdown") # dbg
481 if self._shutdown_message is not None:
481 if self._shutdown_message is not None:
482 self.session.send(self.shell_socket, self._shutdown_message)
482 self.session.send(self.shell_socket, self._shutdown_message)
483 self.session.send(self.iopub_socket, self._shutdown_message)
483 self.session.send(self.iopub_socket, self._shutdown_message)
484 self.log.debug(str(self._shutdown_message))
484 self.log.debug(str(self._shutdown_message))
485 # A very short sleep to give zmq time to flush its message buffers
485 # A very short sleep to give zmq time to flush its message buffers
486 # before Python truly shuts down.
486 # before Python truly shuts down.
487 time.sleep(0.01)
487 time.sleep(0.01)
488
488
489
489
490 class QtKernel(Kernel):
490 class QtKernel(Kernel):
491 """A Kernel subclass with Qt support."""
491 """A Kernel subclass with Qt support."""
492
492
493 def start(self):
493 def start(self):
494 """Start a kernel with QtPy4 event loop integration."""
494 """Start a kernel with QtPy4 event loop integration."""
495
495
496 from IPython.external.qt_for_kernel import QtCore
496 from IPython.external.qt_for_kernel import QtCore
497 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
497 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
498
498
499 self.app = get_app_qt4([" "])
499 self.app = get_app_qt4([" "])
500 self.app.setQuitOnLastWindowClosed(False)
500 self.app.setQuitOnLastWindowClosed(False)
501 self.timer = QtCore.QTimer()
501 self.timer = QtCore.QTimer()
502 self.timer.timeout.connect(self.do_one_iteration)
502 self.timer.timeout.connect(self.do_one_iteration)
503 # Units for the timer are in milliseconds
503 # Units for the timer are in milliseconds
504 self.timer.start(1000*self._poll_interval)
504 self.timer.start(1000*self._poll_interval)
505 start_event_loop_qt4(self.app)
505 start_event_loop_qt4(self.app)
506
506
507
507
508 class WxKernel(Kernel):
508 class WxKernel(Kernel):
509 """A Kernel subclass with Wx support."""
509 """A Kernel subclass with Wx support."""
510
510
511 def start(self):
511 def start(self):
512 """Start a kernel with wx event loop support."""
512 """Start a kernel with wx event loop support."""
513
513
514 import wx
514 import wx
515 from IPython.lib.guisupport import start_event_loop_wx
515 from IPython.lib.guisupport import start_event_loop_wx
516
516
517 doi = self.do_one_iteration
517 doi = self.do_one_iteration
518 # Wx uses milliseconds
518 # Wx uses milliseconds
519 poll_interval = int(1000*self._poll_interval)
519 poll_interval = int(1000*self._poll_interval)
520
520
521 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
521 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
522 # We make the Frame hidden when we create it in the main app below.
522 # We make the Frame hidden when we create it in the main app below.
523 class TimerFrame(wx.Frame):
523 class TimerFrame(wx.Frame):
524 def __init__(self, func):
524 def __init__(self, func):
525 wx.Frame.__init__(self, None, -1)
525 wx.Frame.__init__(self, None, -1)
526 self.timer = wx.Timer(self)
526 self.timer = wx.Timer(self)
527 # Units for the timer are in milliseconds
527 # Units for the timer are in milliseconds
528 self.timer.Start(poll_interval)
528 self.timer.Start(poll_interval)
529 self.Bind(wx.EVT_TIMER, self.on_timer)
529 self.Bind(wx.EVT_TIMER, self.on_timer)
530 self.func = func
530 self.func = func
531
531
532 def on_timer(self, event):
532 def on_timer(self, event):
533 self.func()
533 self.func()
534
534
535 # We need a custom wx.App to create our Frame subclass that has the
535 # We need a custom wx.App to create our Frame subclass that has the
536 # wx.Timer to drive the ZMQ event loop.
536 # wx.Timer to drive the ZMQ event loop.
537 class IPWxApp(wx.App):
537 class IPWxApp(wx.App):
538 def OnInit(self):
538 def OnInit(self):
539 self.frame = TimerFrame(doi)
539 self.frame = TimerFrame(doi)
540 self.frame.Show(False)
540 self.frame.Show(False)
541 return True
541 return True
542
542
543 # The redirect=False here makes sure that wx doesn't replace
543 # The redirect=False here makes sure that wx doesn't replace
544 # sys.stdout/stderr with its own classes.
544 # sys.stdout/stderr with its own classes.
545 self.app = IPWxApp(redirect=False)
545 self.app = IPWxApp(redirect=False)
546 start_event_loop_wx(self.app)
546 start_event_loop_wx(self.app)
547
547
548
548
549 class TkKernel(Kernel):
549 class TkKernel(Kernel):
550 """A Kernel subclass with Tk support."""
550 """A Kernel subclass with Tk support."""
551
551
552 def start(self):
552 def start(self):
553 """Start a Tk enabled event loop."""
553 """Start a Tk enabled event loop."""
554
554
555 import Tkinter
555 import Tkinter
556 doi = self.do_one_iteration
556 doi = self.do_one_iteration
557 # Tk uses milliseconds
557 # Tk uses milliseconds
558 poll_interval = int(1000*self._poll_interval)
558 poll_interval = int(1000*self._poll_interval)
559 # For Tkinter, we create a Tk object and call its withdraw method.
559 # For Tkinter, we create a Tk object and call its withdraw method.
560 class Timer(object):
560 class Timer(object):
561 def __init__(self, func):
561 def __init__(self, func):
562 self.app = Tkinter.Tk()
562 self.app = Tkinter.Tk()
563 self.app.withdraw()
563 self.app.withdraw()
564 self.func = func
564 self.func = func
565
565
566 def on_timer(self):
566 def on_timer(self):
567 self.func()
567 self.func()
568 self.app.after(poll_interval, self.on_timer)
568 self.app.after(poll_interval, self.on_timer)
569
569
570 def start(self):
570 def start(self):
571 self.on_timer() # Call it once to get things going.
571 self.on_timer() # Call it once to get things going.
572 self.app.mainloop()
572 self.app.mainloop()
573
573
574 self.timer = Timer(doi)
574 self.timer = Timer(doi)
575 self.timer.start()
575 self.timer.start()
576
576
577
577
578 class GTKKernel(Kernel):
578 class GTKKernel(Kernel):
579 """A Kernel subclass with GTK support."""
579 """A Kernel subclass with GTK support."""
580
580
581 def start(self):
581 def start(self):
582 """Start the kernel, coordinating with the GTK event loop"""
582 """Start the kernel, coordinating with the GTK event loop"""
583 from .gui.gtkembed import GTKEmbed
583 from .gui.gtkembed import GTKEmbed
584
584
585 gtk_kernel = GTKEmbed(self)
585 gtk_kernel = GTKEmbed(self)
586 gtk_kernel.start()
586 gtk_kernel.start()
587
587
588
588
589 class OSXKernel(TkKernel):
589 class OSXKernel(TkKernel):
590 """A Kernel subclass with Cocoa support via the matplotlib OSX backend."""
590 """A Kernel subclass with Cocoa support via the matplotlib OSX backend."""
591
591
592 def start(self):
592 def start(self):
593 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
593 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
594 via the matplotlib MacOSX backend.
594 via the matplotlib MacOSX backend.
595 """
595 """
596 import matplotlib
596 import matplotlib
597 if matplotlib.__version__ < '1.1.0':
597 if matplotlib.__version__ < '1.1.0':
598 self.log.warn(
598 self.log.warn(
599 "MacOSX backend in matplotlib %s doesn't have a Timer, "
599 "MacOSX backend in matplotlib %s doesn't have a Timer, "
600 "falling back on Tk for CFRunLoop integration. Note that "
600 "falling back on Tk for CFRunLoop integration. Note that "
601 "even this won't work if Tk is linked against X11 instead of "
601 "even this won't work if Tk is linked against X11 instead of "
602 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
602 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
603 "you must use matplotlib >= 1.1.0, or a native libtk."
603 "you must use matplotlib >= 1.1.0, or a native libtk."
604 )
604 )
605 return TkKernel.start(self)
605 return TkKernel.start(self)
606
606
607 from matplotlib.backends.backend_macosx import TimerMac, show
607 from matplotlib.backends.backend_macosx import TimerMac, show
608
608
609 # scale interval for sec->ms
609 # scale interval for sec->ms
610 poll_interval = int(1000*self._poll_interval)
610 poll_interval = int(1000*self._poll_interval)
611
611
612 real_excepthook = sys.excepthook
612 real_excepthook = sys.excepthook
613 def handle_int(etype, value, tb):
613 def handle_int(etype, value, tb):
614 """don't let KeyboardInterrupts look like crashes"""
614 """don't let KeyboardInterrupts look like crashes"""
615 if etype is KeyboardInterrupt:
615 if etype is KeyboardInterrupt:
616 io.raw_print("KeyboardInterrupt caught in CFRunLoop")
616 io.raw_print("KeyboardInterrupt caught in CFRunLoop")
617 else:
617 else:
618 real_excepthook(etype, value, tb)
618 real_excepthook(etype, value, tb)
619
619
620 # add doi() as a Timer to the CFRunLoop
620 # add doi() as a Timer to the CFRunLoop
621 def doi():
621 def doi():
622 # restore excepthook during IPython code
622 # restore excepthook during IPython code
623 sys.excepthook = real_excepthook
623 sys.excepthook = real_excepthook
624 self.do_one_iteration()
624 self.do_one_iteration()
625 # and back:
625 # and back:
626 sys.excepthook = handle_int
626 sys.excepthook = handle_int
627
627 t = TimerMac(poll_interval)
628 t = TimerMac(poll_interval)
628 t.add_callback(doi)
629 t.add_callback(doi)
629 t.start()
630 t.start()
630
631
631 # but still need a Poller for when there are no active windows,
632 # but still need a Poller for when there are no active windows,
632 # during which time mainloop() returns immediately
633 # during which time mainloop() returns immediately
633 poller = zmq.Poller()
634 poller = zmq.Poller()
634 poller.register(self.shell_socket, zmq.POLLIN)
635 poller.register(self.shell_socket, zmq.POLLIN)
635
636
636 while True:
637 while True:
637 try:
638 try:
638 # double nested try/except, to properly catch KeyboardInterrupt
639 # double nested try/except, to properly catch KeyboardInterrupt
639 # due to pyzmq Issue #130
640 # due to pyzmq Issue #130
640 try:
641 try:
641 # don't let interrupts during mainloop invoke crash_handler:
642 # don't let interrupts during mainloop invoke crash_handler:
642 sys.excepthook = handle_int
643 sys.excepthook = handle_int
643 show.mainloop()
644 show.mainloop()
644 sys.excepthook = real_excepthook
645 sys.excepthook = real_excepthook
645 # use poller if mainloop returned (no windows)
646 # use poller if mainloop returned (no windows)
646 # scale by extra factor of 10, since it's a real poll
647 # scale by extra factor of 10, since it's a real poll
647 poller.poll(10*poll_interval)
648 poller.poll(10*poll_interval)
648 self.do_one_iteration()
649 self.do_one_iteration()
649 except:
650 except:
650 raise
651 raise
651 except KeyboardInterrupt:
652 except KeyboardInterrupt:
652 # Ctrl-C shouldn't crash the kernel
653 # Ctrl-C shouldn't crash the kernel
653 io.raw_print("KeyboardInterrupt caught in kernel")
654 io.raw_print("KeyboardInterrupt caught in kernel")
655 finally:
656 # ensure excepthook is restored
657 sys.excepthook = real_excepthook
654
658
655
659
656 #-----------------------------------------------------------------------------
660 #-----------------------------------------------------------------------------
657 # Aliases and Flags for the IPKernelApp
661 # Aliases and Flags for the IPKernelApp
658 #-----------------------------------------------------------------------------
662 #-----------------------------------------------------------------------------
659
663
660 flags = dict(kernel_flags)
664 flags = dict(kernel_flags)
661 flags.update(shell_flags)
665 flags.update(shell_flags)
662
666
663 addflag = lambda *args: flags.update(boolean_flag(*args))
667 addflag = lambda *args: flags.update(boolean_flag(*args))
664
668
665 flags['pylab'] = (
669 flags['pylab'] = (
666 {'IPKernelApp' : {'pylab' : 'auto'}},
670 {'IPKernelApp' : {'pylab' : 'auto'}},
667 """Pre-load matplotlib and numpy for interactive use with
671 """Pre-load matplotlib and numpy for interactive use with
668 the default matplotlib backend."""
672 the default matplotlib backend."""
669 )
673 )
670
674
671 aliases = dict(kernel_aliases)
675 aliases = dict(kernel_aliases)
672 aliases.update(shell_aliases)
676 aliases.update(shell_aliases)
673
677
674 # it's possible we don't want short aliases for *all* of these:
678 # it's possible we don't want short aliases for *all* of these:
675 aliases.update(dict(
679 aliases.update(dict(
676 pylab='IPKernelApp.pylab',
680 pylab='IPKernelApp.pylab',
677 ))
681 ))
678
682
679 #-----------------------------------------------------------------------------
683 #-----------------------------------------------------------------------------
680 # The IPKernelApp class
684 # The IPKernelApp class
681 #-----------------------------------------------------------------------------
685 #-----------------------------------------------------------------------------
682
686
683 class IPKernelApp(KernelApp, InteractiveShellApp):
687 class IPKernelApp(KernelApp, InteractiveShellApp):
684 name = 'ipkernel'
688 name = 'ipkernel'
685
689
686 aliases = Dict(aliases)
690 aliases = Dict(aliases)
687 flags = Dict(flags)
691 flags = Dict(flags)
688 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
692 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
689 # configurables
693 # configurables
690 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
694 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
691 config=True,
695 config=True,
692 help="""Pre-load matplotlib and numpy for interactive use,
696 help="""Pre-load matplotlib and numpy for interactive use,
693 selecting a particular matplotlib backend and loop integration.
697 selecting a particular matplotlib backend and loop integration.
694 """
698 """
695 )
699 )
696 def initialize(self, argv=None):
700 def initialize(self, argv=None):
697 super(IPKernelApp, self).initialize(argv)
701 super(IPKernelApp, self).initialize(argv)
698 self.init_shell()
702 self.init_shell()
699 self.init_extensions()
703 self.init_extensions()
700 self.init_code()
704 self.init_code()
701
705
702 def init_kernel(self):
706 def init_kernel(self):
703 kernel_factory = Kernel
707 kernel_factory = Kernel
704
708
705 kernel_map = {
709 kernel_map = {
706 'qt' : QtKernel,
710 'qt' : QtKernel,
707 'qt4': QtKernel,
711 'qt4': QtKernel,
708 'inline': Kernel,
712 'inline': Kernel,
709 'osx': OSXKernel,
713 'osx': OSXKernel,
710 'wx' : WxKernel,
714 'wx' : WxKernel,
711 'tk' : TkKernel,
715 'tk' : TkKernel,
712 'gtk': GTKKernel,
716 'gtk': GTKKernel,
713 }
717 }
714
718
715 if self.pylab:
719 if self.pylab:
716 key = None if self.pylab == 'auto' else self.pylab
720 key = None if self.pylab == 'auto' else self.pylab
717 gui, backend = pylabtools.find_gui_and_backend(key)
721 gui, backend = pylabtools.find_gui_and_backend(key)
718 kernel_factory = kernel_map.get(gui)
722 kernel_factory = kernel_map.get(gui)
719 if kernel_factory is None:
723 if kernel_factory is None:
720 raise ValueError('GUI is not supported: %r' % gui)
724 raise ValueError('GUI is not supported: %r' % gui)
721 pylabtools.activate_matplotlib(backend)
725 pylabtools.activate_matplotlib(backend)
722
726
723 kernel = kernel_factory(config=self.config, session=self.session,
727 kernel = kernel_factory(config=self.config, session=self.session,
724 shell_socket=self.shell_socket,
728 shell_socket=self.shell_socket,
725 iopub_socket=self.iopub_socket,
729 iopub_socket=self.iopub_socket,
726 stdin_socket=self.stdin_socket,
730 stdin_socket=self.stdin_socket,
727 log=self.log
731 log=self.log
728 )
732 )
729 self.kernel = kernel
733 self.kernel = kernel
730 kernel.record_ports(self.ports)
734 kernel.record_ports(self.ports)
731
735
732 if self.pylab:
736 if self.pylab:
733 import_all = self.pylab_import_all
737 import_all = self.pylab_import_all
734 pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all,
738 pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all,
735 shell=kernel.shell)
739 shell=kernel.shell)
736
740
737 def init_shell(self):
741 def init_shell(self):
738 self.shell = self.kernel.shell
742 self.shell = self.kernel.shell
739
743
740
744
741 #-----------------------------------------------------------------------------
745 #-----------------------------------------------------------------------------
742 # Kernel main and launch functions
746 # Kernel main and launch functions
743 #-----------------------------------------------------------------------------
747 #-----------------------------------------------------------------------------
744
748
745 def launch_kernel(*args, **kwargs):
749 def launch_kernel(*args, **kwargs):
746 """Launches a localhost IPython kernel, binding to the specified ports.
750 """Launches a localhost IPython kernel, binding to the specified ports.
747
751
748 This function simply calls entry_point.base_launch_kernel with the right first
752 This function simply calls entry_point.base_launch_kernel with the right first
749 command to start an ipkernel. See base_launch_kernel for arguments.
753 command to start an ipkernel. See base_launch_kernel for arguments.
750
754
751 Returns
755 Returns
752 -------
756 -------
753 A tuple of form:
757 A tuple of form:
754 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
758 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
755 where kernel_process is a Popen object and the ports are integers.
759 where kernel_process is a Popen object and the ports are integers.
756 """
760 """
757 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
761 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
758 *args, **kwargs)
762 *args, **kwargs)
759
763
760
764
761 def main():
765 def main():
762 """Run an IPKernel as an application"""
766 """Run an IPKernel as an application"""
763 app = IPKernelApp.instance()
767 app = IPKernelApp.instance()
764 app.initialize()
768 app.initialize()
765 app.start()
769 app.start()
766
770
767
771
768 if __name__ == '__main__':
772 if __name__ == '__main__':
769 main()
773 main()
General Comments 0
You need to be logged in to leave comments. Login now