##// END OF EJS Templates
[termconsole] raw_input improvements...
MinRK -
Show More
@@ -1,311 +1,337 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Frontend of ipython working with python-zmq
2 """Frontend of ipython working with python-zmq
3
3
4 Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs.
4 Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs.
5
5
6 For more details, see the ipython-zmq design
6 For more details, see the ipython-zmq design
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import bdb
20 import bdb
21 import signal
21 import sys
22 import sys
22 import time
23 import time
23
24
24 from Queue import Empty
25 from Queue import Empty
25
26
26 from IPython.core.alias import AliasManager, AliasError
27 from IPython.core.alias import AliasManager, AliasError
27 from IPython.core import page
28 from IPython.core import page
28 from IPython.utils.warn import warn, error, fatal
29 from IPython.utils.warn import warn, error, fatal
29 from IPython.utils import io
30 from IPython.utils import io
30
31
31 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
32 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
32 from IPython.frontend.terminal.console.completer import ZMQCompleter
33 from IPython.frontend.terminal.console.completer import ZMQCompleter
33
34
34
35
35 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
36 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
36 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
37 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
37 _executing = False
38 _executing = False
38
39
39 def __init__(self, *args, **kwargs):
40 def __init__(self, *args, **kwargs):
40 self.km = kwargs.pop('kernel_manager')
41 self.km = kwargs.pop('kernel_manager')
41 self.session_id = self.km.session.session
42 self.session_id = self.km.session.session
42 super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs)
43 super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs)
43
44
44 def init_completer(self):
45 def init_completer(self):
45 """Initialize the completion machinery.
46 """Initialize the completion machinery.
46
47
47 This creates completion machinery that can be used by client code,
48 This creates completion machinery that can be used by client code,
48 either interactively in-process (typically triggered by the readline
49 either interactively in-process (typically triggered by the readline
49 library), programatically (such as in test suites) or out-of-prcess
50 library), programatically (such as in test suites) or out-of-prcess
50 (typically over the network by remote frontends).
51 (typically over the network by remote frontends).
51 """
52 """
52 from IPython.core.completerlib import (module_completer,
53 from IPython.core.completerlib import (module_completer,
53 magic_run_completer, cd_completer)
54 magic_run_completer, cd_completer)
54
55
55 self.Completer = ZMQCompleter(self, self.km)
56 self.Completer = ZMQCompleter(self, self.km)
56
57
57
58
58 self.set_hook('complete_command', module_completer, str_key = 'import')
59 self.set_hook('complete_command', module_completer, str_key = 'import')
59 self.set_hook('complete_command', module_completer, str_key = 'from')
60 self.set_hook('complete_command', module_completer, str_key = 'from')
60 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
61 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
61 self.set_hook('complete_command', cd_completer, str_key = '%cd')
62 self.set_hook('complete_command', cd_completer, str_key = '%cd')
62
63
63 # Only configure readline if we truly are using readline. IPython can
64 # Only configure readline if we truly are using readline. IPython can
64 # do tab-completion over the network, in GUIs, etc, where readline
65 # do tab-completion over the network, in GUIs, etc, where readline
65 # itself may be absent
66 # itself may be absent
66 if self.has_readline:
67 if self.has_readline:
67 self.set_readline_completer()
68 self.set_readline_completer()
68
69
69 def run_cell(self, cell, store_history=True):
70 def run_cell(self, cell, store_history=True):
70 """Run a complete IPython cell.
71 """Run a complete IPython cell.
71
72
72 Parameters
73 Parameters
73 ----------
74 ----------
74 cell : str
75 cell : str
75 The code (including IPython code such as %magic functions) to run.
76 The code (including IPython code such as %magic functions) to run.
76 store_history : bool
77 store_history : bool
77 If True, the raw and translated cell will be stored in IPython's
78 If True, the raw and translated cell will be stored in IPython's
78 history. For user code calling back into IPython's machinery, this
79 history. For user code calling back into IPython's machinery, this
79 should be set to False.
80 should be set to False.
80 """
81 """
81 if (not cell) or cell.isspace():
82 if (not cell) or cell.isspace():
82 return
83 return
83
84
84 self._executing = True
85 self._executing = True
85 # flush stale replies, which could have been ignored, due to missed heartbeats
86 # flush stale replies, which could have been ignored, due to missed heartbeats
86 while self.km.shell_channel.msg_ready():
87 while self.km.shell_channel.msg_ready():
87 self.km.shell_channel.get_msg()
88 self.km.shell_channel.get_msg()
88 # shell_channel.execute takes 'hidden', which is the inverse of store_hist
89 # shell_channel.execute takes 'hidden', which is the inverse of store_hist
89 msg_id = self.km.shell_channel.execute(cell, not store_history)
90 msg_id = self.km.shell_channel.execute(cell, not store_history)
90 while not self.km.shell_channel.msg_ready() and self.km.is_alive:
91 while not self.km.shell_channel.msg_ready() and self.km.is_alive:
91 try:
92 try:
92 self.handle_stdin_request(timeout=0.05)
93 self.handle_stdin_request(timeout=0.05)
93 except Empty:
94 except Empty:
94 # display intermediate print statements, etc.
95 # display intermediate print statements, etc.
95 self.handle_iopub()
96 self.handle_iopub()
96 pass
97 pass
97 if self.km.shell_channel.msg_ready():
98 if self.km.shell_channel.msg_ready():
98 self.handle_execute_reply(msg_id)
99 self.handle_execute_reply(msg_id)
99 self._executing = False
100 self._executing = False
100
101
101 #-----------------
102 #-----------------
102 # message handlers
103 # message handlers
103 #-----------------
104 #-----------------
104
105
105 def handle_execute_reply(self, msg_id):
106 def handle_execute_reply(self, msg_id):
106 msg = self.km.shell_channel.get_msg()
107 msg = self.km.shell_channel.get_msg()
107 if msg["parent_header"].get("msg_id", None) == msg_id:
108 if msg["parent_header"].get("msg_id", None) == msg_id:
108
109
109 self.handle_iopub()
110 self.handle_iopub()
110
111
111 content = msg["content"]
112 content = msg["content"]
112 status = content['status']
113 status = content['status']
113
114
114 if status == 'aborted':
115 if status == 'aborted':
115 self.write('Aborted\n')
116 self.write('Aborted\n')
116 return
117 return
117 elif status == 'ok':
118 elif status == 'ok':
118 # print execution payloads as well:
119 # print execution payloads as well:
119 for item in content["payload"]:
120 for item in content["payload"]:
120 text = item.get('text', None)
121 text = item.get('text', None)
121 if text:
122 if text:
122 page.page(text)
123 page.page(text)
123
124
124 elif status == 'error':
125 elif status == 'error':
125 for frame in content["traceback"]:
126 for frame in content["traceback"]:
126 print(frame, file=io.stderr)
127 print(frame, file=io.stderr)
127
128
128 self.execution_count = int(content["execution_count"] + 1)
129 self.execution_count = int(content["execution_count"] + 1)
129
130
130
131
131 def handle_iopub(self):
132 def handle_iopub(self):
132 """ Method to procces subscribe channel's messages
133 """ Method to procces subscribe channel's messages
133
134
134 This method reads a message and processes the content in different
135 This method reads a message and processes the content in different
135 outputs like stdout, stderr, pyout and status
136 outputs like stdout, stderr, pyout and status
136
137
137 Arguments:
138 Arguments:
138 sub_msg: message receive from kernel in the sub socket channel
139 sub_msg: message receive from kernel in the sub socket channel
139 capture by kernel manager.
140 capture by kernel manager.
140 """
141 """
141 while self.km.sub_channel.msg_ready():
142 while self.km.sub_channel.msg_ready():
142 sub_msg = self.km.sub_channel.get_msg()
143 sub_msg = self.km.sub_channel.get_msg()
143 msg_type = sub_msg['header']['msg_type']
144 msg_type = sub_msg['header']['msg_type']
144 if self.session_id == sub_msg['parent_header']['session']:
145 if self.session_id == sub_msg['parent_header']['session']:
145 if msg_type == 'status' :
146 if msg_type == 'status' :
146 if sub_msg["content"]["execution_state"] == "busy" :
147 if sub_msg["content"]["execution_state"] == "busy" :
147 pass
148 pass
148
149
149 elif msg_type == 'stream' :
150 elif msg_type == 'stream' :
150 if sub_msg["content"]["name"] == "stdout":
151 if sub_msg["content"]["name"] == "stdout":
151 print(sub_msg["content"]["data"], file=io.stdout, end="")
152 print(sub_msg["content"]["data"], file=io.stdout, end="")
152 io.stdout.flush()
153 io.stdout.flush()
153 elif sub_msg["content"]["name"] == "stderr" :
154 elif sub_msg["content"]["name"] == "stderr" :
154 print(sub_msg["content"]["data"], file=io.stderr, end="")
155 print(sub_msg["content"]["data"], file=io.stderr, end="")
155 io.stderr.flush()
156 io.stderr.flush()
156
157
157 elif msg_type == 'pyout':
158 elif msg_type == 'pyout':
158 self.execution_count = int(sub_msg["content"]["execution_count"])
159 self.execution_count = int(sub_msg["content"]["execution_count"])
159 format_dict = sub_msg["content"]["data"]
160 format_dict = sub_msg["content"]["data"]
160 # taken from DisplayHook.__call__:
161 # taken from DisplayHook.__call__:
161 hook = self.displayhook
162 hook = self.displayhook
162 hook.start_displayhook()
163 hook.start_displayhook()
163 hook.write_output_prompt()
164 hook.write_output_prompt()
164 hook.write_format_data(format_dict)
165 hook.write_format_data(format_dict)
165 hook.log_output(format_dict)
166 hook.log_output(format_dict)
166 hook.finish_displayhook()
167 hook.finish_displayhook()
167
168
168 def handle_stdin_request(self, timeout=0.1):
169 def handle_stdin_request(self, timeout=0.1):
169 """ Method to capture raw_input
170 """ Method to capture raw_input
170 """
171 """
171 msg_rep = self.km.stdin_channel.get_msg(timeout=timeout)
172 msg_rep = self.km.stdin_channel.get_msg(timeout=timeout)
173 # in case any iopub came while we were waiting:
174 self.handle_iopub()
172 if self.session_id == msg_rep["parent_header"]["session"] :
175 if self.session_id == msg_rep["parent_header"]["session"]:
176 # wrap SIGINT handler
177 real_handler = signal.getsignal(signal.SIGINT)
178 def double_int(sig,frame):
179 # call real handler (forwards sigint to kernel),
180 # then raise local interrupt, stopping local raw_input
181 real_handler(sig,frame)
182 raise KeyboardInterrupt
183 signal.signal(signal.SIGINT, double_int)
184
185 try:
173 raw_data = raw_input(msg_rep["content"]["prompt"])
186 raw_data = raw_input(msg_rep["content"]["prompt"])
187 except EOFError:
188 # turn EOFError into EOF character
189 raw_data = '\x04'
190 except KeyboardInterrupt:
191 sys.stdout.write('\n')
192 return
193 finally:
194 # restore SIGINT handler
195 signal.signal(signal.SIGINT, real_handler)
196
197 # only send stdin reply if there *was not* another request
198 # or execution finished while we were reading.
199 if not (self.km.stdin_channel.msg_ready() or self.km.shell_channel.msg_ready()):
174 self.km.stdin_channel.input(raw_data)
200 self.km.stdin_channel.input(raw_data)
175
201
176 def mainloop(self, display_banner=False):
202 def mainloop(self, display_banner=False):
177 while True:
203 while True:
178 try:
204 try:
179 self.interact(display_banner=display_banner)
205 self.interact(display_banner=display_banner)
180 #self.interact_with_readline()
206 #self.interact_with_readline()
181 # XXX for testing of a readline-decoupled repl loop, call
207 # XXX for testing of a readline-decoupled repl loop, call
182 # interact_with_readline above
208 # interact_with_readline above
183 break
209 break
184 except KeyboardInterrupt:
210 except KeyboardInterrupt:
185 # this should not be necessary, but KeyboardInterrupt
211 # this should not be necessary, but KeyboardInterrupt
186 # handling seems rather unpredictable...
212 # handling seems rather unpredictable...
187 self.write("\nKeyboardInterrupt in interact()\n")
213 self.write("\nKeyboardInterrupt in interact()\n")
188
214
189 def wait_for_kernel(self, timeout=None):
215 def wait_for_kernel(self, timeout=None):
190 """method to wait for a kernel to be ready"""
216 """method to wait for a kernel to be ready"""
191 tic = time.time()
217 tic = time.time()
192 self.km.hb_channel.unpause()
218 self.km.hb_channel.unpause()
193 while True:
219 while True:
194 self.run_cell('1', False)
220 self.run_cell('1', False)
195 if self.km.hb_channel.is_beating():
221 if self.km.hb_channel.is_beating():
196 # heart failure was not the reason this returned
222 # heart failure was not the reason this returned
197 break
223 break
198 else:
224 else:
199 # heart failed
225 # heart failed
200 if timeout is not None and (time.time() - tic) > timeout:
226 if timeout is not None and (time.time() - tic) > timeout:
201 return False
227 return False
202 return True
228 return True
203
229
204 def interact(self, display_banner=None):
230 def interact(self, display_banner=None):
205 """Closely emulate the interactive Python console."""
231 """Closely emulate the interactive Python console."""
206
232
207 # batch run -> do not interact
233 # batch run -> do not interact
208 if self.exit_now:
234 if self.exit_now:
209 return
235 return
210
236
211 if display_banner is None:
237 if display_banner is None:
212 display_banner = self.display_banner
238 display_banner = self.display_banner
213
239
214 if isinstance(display_banner, basestring):
240 if isinstance(display_banner, basestring):
215 self.show_banner(display_banner)
241 self.show_banner(display_banner)
216 elif display_banner:
242 elif display_banner:
217 self.show_banner()
243 self.show_banner()
218
244
219 more = False
245 more = False
220
246
221 # run a non-empty no-op, so that we don't get a prompt until
247 # run a non-empty no-op, so that we don't get a prompt until
222 # we know the kernel is ready. This keeps the connection
248 # we know the kernel is ready. This keeps the connection
223 # message above the first prompt.
249 # message above the first prompt.
224 if not self.wait_for_kernel(3):
250 if not self.wait_for_kernel(3):
225 error("Kernel did not respond\n")
251 error("Kernel did not respond\n")
226 return
252 return
227
253
228 if self.has_readline:
254 if self.has_readline:
229 self.readline_startup_hook(self.pre_readline)
255 self.readline_startup_hook(self.pre_readline)
230 hlen_b4_cell = self.readline.get_current_history_length()
256 hlen_b4_cell = self.readline.get_current_history_length()
231 else:
257 else:
232 hlen_b4_cell = 0
258 hlen_b4_cell = 0
233 # exit_now is set by a call to %Exit or %Quit, through the
259 # exit_now is set by a call to %Exit or %Quit, through the
234 # ask_exit callback.
260 # ask_exit callback.
235
261
236 while not self.exit_now:
262 while not self.exit_now:
237 if not self.km.is_alive:
263 if not self.km.is_alive:
238 # kernel died, prompt for action or exit
264 # kernel died, prompt for action or exit
239 action = "restart" if self.km.has_kernel else "wait for restart"
265 action = "restart" if self.km.has_kernel else "wait for restart"
240 ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
266 ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
241 if ans:
267 if ans:
242 if self.km.has_kernel:
268 if self.km.has_kernel:
243 self.km.restart_kernel(True)
269 self.km.restart_kernel(True)
244 self.wait_for_kernel(3)
270 self.wait_for_kernel(3)
245 else:
271 else:
246 self.exit_now = True
272 self.exit_now = True
247 continue
273 continue
248 try:
274 try:
249 # protect prompt block from KeyboardInterrupt
275 # protect prompt block from KeyboardInterrupt
250 # when sitting on ctrl-C
276 # when sitting on ctrl-C
251 self.hooks.pre_prompt_hook()
277 self.hooks.pre_prompt_hook()
252 if more:
278 if more:
253 try:
279 try:
254 prompt = self.hooks.generate_prompt(True)
280 prompt = self.hooks.generate_prompt(True)
255 except Exception:
281 except Exception:
256 self.showtraceback()
282 self.showtraceback()
257 if self.autoindent:
283 if self.autoindent:
258 self.rl_do_indent = True
284 self.rl_do_indent = True
259
285
260 else:
286 else:
261 try:
287 try:
262 prompt = self.hooks.generate_prompt(False)
288 prompt = self.hooks.generate_prompt(False)
263 except Exception:
289 except Exception:
264 self.showtraceback()
290 self.showtraceback()
265
291
266 line = self.raw_input(prompt)
292 line = self.raw_input(prompt)
267 if self.exit_now:
293 if self.exit_now:
268 # quick exit on sys.std[in|out] close
294 # quick exit on sys.std[in|out] close
269 break
295 break
270 if self.autoindent:
296 if self.autoindent:
271 self.rl_do_indent = False
297 self.rl_do_indent = False
272
298
273 except KeyboardInterrupt:
299 except KeyboardInterrupt:
274 #double-guard against keyboardinterrupts during kbdint handling
300 #double-guard against keyboardinterrupts during kbdint handling
275 try:
301 try:
276 self.write('\nKeyboardInterrupt\n')
302 self.write('\nKeyboardInterrupt\n')
277 source_raw = self.input_splitter.source_raw_reset()[1]
303 source_raw = self.input_splitter.source_raw_reset()[1]
278 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
304 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
279 more = False
305 more = False
280 except KeyboardInterrupt:
306 except KeyboardInterrupt:
281 pass
307 pass
282 except EOFError:
308 except EOFError:
283 if self.autoindent:
309 if self.autoindent:
284 self.rl_do_indent = False
310 self.rl_do_indent = False
285 if self.has_readline:
311 if self.has_readline:
286 self.readline_startup_hook(None)
312 self.readline_startup_hook(None)
287 self.write('\n')
313 self.write('\n')
288 self.exit()
314 self.exit()
289 except bdb.BdbQuit:
315 except bdb.BdbQuit:
290 warn('The Python debugger has exited with a BdbQuit exception.\n'
316 warn('The Python debugger has exited with a BdbQuit exception.\n'
291 'Because of how pdb handles the stack, it is impossible\n'
317 'Because of how pdb handles the stack, it is impossible\n'
292 'for IPython to properly format this particular exception.\n'
318 'for IPython to properly format this particular exception.\n'
293 'IPython will resume normal operation.')
319 'IPython will resume normal operation.')
294 except:
320 except:
295 # exceptions here are VERY RARE, but they can be triggered
321 # exceptions here are VERY RARE, but they can be triggered
296 # asynchronously by signal handlers, for example.
322 # asynchronously by signal handlers, for example.
297 self.showtraceback()
323 self.showtraceback()
298 else:
324 else:
299 self.input_splitter.push(line)
325 self.input_splitter.push(line)
300 more = self.input_splitter.push_accepts_more()
326 more = self.input_splitter.push_accepts_more()
301 if (self.SyntaxTB.last_syntax_error and
327 if (self.SyntaxTB.last_syntax_error and
302 self.autoedit_syntax):
328 self.autoedit_syntax):
303 self.edit_syntax_error()
329 self.edit_syntax_error()
304 if not more:
330 if not more:
305 source_raw = self.input_splitter.source_reset()
331 source_raw = self.input_splitter.source_reset()
306 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
332 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
307 self.run_cell(source_raw)
333 self.run_cell(source_raw)
308
334
309
335
310 # Turn off the exit flag, so the mainloop can be restarted if desired
336 # Turn off the exit flag, so the mainloop can be restarted if desired
311 self.exit_now = False
337 self.exit_now = False
@@ -1,648 +1,651 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 from signal import (
25 from signal import (
26 signal, default_int_handler, SIGINT, SIG_IGN
26 signal, default_int_handler, SIGINT, SIG_IGN
27 )
27 )
28 # System library imports.
28 # System library imports.
29 import zmq
29 import zmq
30
30
31 # Local imports.
31 # Local imports.
32 from IPython.core import pylabtools
32 from IPython.core import pylabtools
33 from IPython.config.configurable import Configurable
33 from IPython.config.configurable import Configurable
34 from IPython.config.application import boolean_flag, catch_config_error
34 from IPython.config.application import boolean_flag, catch_config_error
35 from IPython.core.application import ProfileDir
35 from IPython.core.application import ProfileDir
36 from IPython.core.error import StdinNotImplementedError
36 from IPython.core.error import StdinNotImplementedError
37 from IPython.core.shellapp import (
37 from IPython.core.shellapp import (
38 InteractiveShellApp, shell_flags, shell_aliases
38 InteractiveShellApp, shell_flags, shell_aliases
39 )
39 )
40 from IPython.utils import io
40 from IPython.utils import io
41 from IPython.utils import py3compat
41 from IPython.utils import py3compat
42 from IPython.utils.jsonutil import json_clean
42 from IPython.utils.jsonutil import json_clean
43 from IPython.utils.traitlets import (
43 from IPython.utils.traitlets import (
44 Any, Instance, Float, Dict, CaselessStrEnum
44 Any, Instance, Float, Dict, CaselessStrEnum
45 )
45 )
46
46
47 from entry_point import base_launch_kernel
47 from entry_point import base_launch_kernel
48 from kernelapp import KernelApp, kernel_flags, kernel_aliases
48 from kernelapp import KernelApp, kernel_flags, kernel_aliases
49 from session import Session, Message
49 from session import Session, Message
50 from zmqshell import ZMQInteractiveShell
50 from zmqshell import ZMQInteractiveShell
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Main kernel class
54 # Main kernel class
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 class Kernel(Configurable):
57 class Kernel(Configurable):
58
58
59 #---------------------------------------------------------------------------
59 #---------------------------------------------------------------------------
60 # Kernel interface
60 # Kernel interface
61 #---------------------------------------------------------------------------
61 #---------------------------------------------------------------------------
62
62
63 # attribute to override with a GUI
63 # attribute to override with a GUI
64 eventloop = Any(None)
64 eventloop = Any(None)
65
65
66 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
66 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
67 session = Instance(Session)
67 session = Instance(Session)
68 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
68 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
69 shell_socket = Instance('zmq.Socket')
69 shell_socket = Instance('zmq.Socket')
70 iopub_socket = Instance('zmq.Socket')
70 iopub_socket = Instance('zmq.Socket')
71 stdin_socket = Instance('zmq.Socket')
71 stdin_socket = Instance('zmq.Socket')
72 log = Instance(logging.Logger)
72 log = Instance(logging.Logger)
73
73
74 # Private interface
74 # Private interface
75
75
76 # Time to sleep after flushing the stdout/err buffers in each execute
76 # Time to sleep after flushing the stdout/err buffers in each execute
77 # cycle. While this introduces a hard limit on the minimal latency of the
77 # cycle. While this introduces a hard limit on the minimal latency of the
78 # execute cycle, it helps prevent output synchronization problems for
78 # execute cycle, it helps prevent output synchronization problems for
79 # clients.
79 # clients.
80 # Units are in seconds. The minimum zmq latency on local host is probably
80 # Units are in seconds. The minimum zmq latency on local host is probably
81 # ~150 microseconds, set this to 500us for now. We may need to increase it
81 # ~150 microseconds, set this to 500us for now. We may need to increase it
82 # a little if it's not enough after more interactive testing.
82 # a little if it's not enough after more interactive testing.
83 _execute_sleep = Float(0.0005, config=True)
83 _execute_sleep = Float(0.0005, config=True)
84
84
85 # Frequency of the kernel's event loop.
85 # Frequency of the kernel's event loop.
86 # Units are in seconds, kernel subclasses for GUI toolkits may need to
86 # Units are in seconds, kernel subclasses for GUI toolkits may need to
87 # adapt to milliseconds.
87 # adapt to milliseconds.
88 _poll_interval = Float(0.05, config=True)
88 _poll_interval = Float(0.05, config=True)
89
89
90 # If the shutdown was requested over the network, we leave here the
90 # If the shutdown was requested over the network, we leave here the
91 # necessary reply message so it can be sent by our registered atexit
91 # necessary reply message so it can be sent by our registered atexit
92 # handler. This ensures that the reply is only sent to clients truly at
92 # handler. This ensures that the reply is only sent to clients truly at
93 # the end of our shutdown process (which happens after the underlying
93 # the end of our shutdown process (which happens after the underlying
94 # IPython shell's own shutdown).
94 # IPython shell's own shutdown).
95 _shutdown_message = None
95 _shutdown_message = None
96
96
97 # This is a dict of port number that the kernel is listening on. It is set
97 # This is a dict of port number that the kernel is listening on. It is set
98 # by record_ports and used by connect_request.
98 # by record_ports and used by connect_request.
99 _recorded_ports = Dict()
99 _recorded_ports = Dict()
100
100
101
101
102
102
103 def __init__(self, **kwargs):
103 def __init__(self, **kwargs):
104 super(Kernel, self).__init__(**kwargs)
104 super(Kernel, self).__init__(**kwargs)
105
105
106 # Before we even start up the shell, register *first* our exit handlers
106 # Before we even start up the shell, register *first* our exit handlers
107 # so they come before the shell's
107 # so they come before the shell's
108 atexit.register(self._at_shutdown)
108 atexit.register(self._at_shutdown)
109
109
110 # Initialize the InteractiveShell subclass
110 # Initialize the InteractiveShell subclass
111 self.shell = ZMQInteractiveShell.instance(config=self.config,
111 self.shell = ZMQInteractiveShell.instance(config=self.config,
112 profile_dir = self.profile_dir,
112 profile_dir = self.profile_dir,
113 )
113 )
114 self.shell.displayhook.session = self.session
114 self.shell.displayhook.session = self.session
115 self.shell.displayhook.pub_socket = self.iopub_socket
115 self.shell.displayhook.pub_socket = self.iopub_socket
116 self.shell.display_pub.session = self.session
116 self.shell.display_pub.session = self.session
117 self.shell.display_pub.pub_socket = self.iopub_socket
117 self.shell.display_pub.pub_socket = self.iopub_socket
118
118
119 # TMP - hack while developing
119 # TMP - hack while developing
120 self.shell._reply_content = None
120 self.shell._reply_content = None
121
121
122 # Build dict of handlers for message types
122 # Build dict of handlers for message types
123 msg_types = [ 'execute_request', 'complete_request',
123 msg_types = [ 'execute_request', 'complete_request',
124 'object_info_request', 'history_request',
124 'object_info_request', 'history_request',
125 'connect_request', 'shutdown_request']
125 'connect_request', 'shutdown_request']
126 self.handlers = {}
126 self.handlers = {}
127 for msg_type in msg_types:
127 for msg_type in msg_types:
128 self.handlers[msg_type] = getattr(self, msg_type)
128 self.handlers[msg_type] = getattr(self, msg_type)
129
129
130 def do_one_iteration(self):
130 def do_one_iteration(self):
131 """Do one iteration of the kernel's evaluation loop.
131 """Do one iteration of the kernel's evaluation loop.
132 """
132 """
133 try:
133 try:
134 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
134 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
135 except Exception:
135 except Exception:
136 self.log.warn("Invalid Message:", exc_info=True)
136 self.log.warn("Invalid Message:", exc_info=True)
137 return
137 return
138 if msg is None:
138 if msg is None:
139 return
139 return
140
140
141 msg_type = msg['header']['msg_type']
141 msg_type = msg['header']['msg_type']
142
142
143 # This assert will raise in versions of zeromq 2.0.7 and lesser.
143 # This assert will raise in versions of zeromq 2.0.7 and lesser.
144 # We now require 2.0.8 or above, so we can uncomment for safety.
144 # We now require 2.0.8 or above, so we can uncomment for safety.
145 # print(ident,msg, file=sys.__stdout__)
145 # print(ident,msg, file=sys.__stdout__)
146 assert ident is not None, "Missing message part."
146 assert ident is not None, "Missing message part."
147
147
148 # Print some info about this message and leave a '--->' marker, so it's
148 # Print some info about this message and leave a '--->' marker, so it's
149 # easier to trace visually the message chain when debugging. Each
149 # easier to trace visually the message chain when debugging. Each
150 # handler prints its message at the end.
150 # handler prints its message at the end.
151 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
151 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
152 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
152 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
153
153
154 # Find and call actual handler for message
154 # Find and call actual handler for message
155 handler = self.handlers.get(msg_type, None)
155 handler = self.handlers.get(msg_type, None)
156 if handler is None:
156 if handler is None:
157 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
157 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
158 else:
158 else:
159 handler(ident, msg)
159 handler(ident, msg)
160
160
161 # Check whether we should exit, in case the incoming message set the
161 # Check whether we should exit, in case the incoming message set the
162 # exit flag on
162 # exit flag on
163 if self.shell.exit_now:
163 if self.shell.exit_now:
164 self.log.debug('\nExiting IPython kernel...')
164 self.log.debug('\nExiting IPython kernel...')
165 # We do a normal, clean exit, which allows any actions registered
165 # We do a normal, clean exit, which allows any actions registered
166 # via atexit (such as history saving) to take place.
166 # via atexit (such as history saving) to take place.
167 sys.exit(0)
167 sys.exit(0)
168
168
169
169
170 def start(self):
170 def start(self):
171 """ Start the kernel main loop.
171 """ Start the kernel main loop.
172 """
172 """
173 # a KeyboardInterrupt (SIGINT) can occur on any python statement, so
173 # a KeyboardInterrupt (SIGINT) can occur on any python statement, so
174 # let's ignore (SIG_IGN) them until we're in a place to handle them properly
174 # let's ignore (SIG_IGN) them until we're in a place to handle them properly
175 signal(SIGINT,SIG_IGN)
175 signal(SIGINT,SIG_IGN)
176 poller = zmq.Poller()
176 poller = zmq.Poller()
177 poller.register(self.shell_socket, zmq.POLLIN)
177 poller.register(self.shell_socket, zmq.POLLIN)
178 # loop while self.eventloop has not been overridden
178 # loop while self.eventloop has not been overridden
179 while self.eventloop is None:
179 while self.eventloop is None:
180 try:
180 try:
181 # scale by extra factor of 10, because there is no
181 # scale by extra factor of 10, because there is no
182 # reason for this to be anything less than ~ 0.1s
182 # reason for this to be anything less than ~ 0.1s
183 # since it is a real poller and will respond
183 # since it is a real poller and will respond
184 # to events immediately
184 # to events immediately
185
185
186 # double nested try/except, to properly catch KeyboardInterrupt
186 # double nested try/except, to properly catch KeyboardInterrupt
187 # due to pyzmq Issue #130
187 # due to pyzmq Issue #130
188 try:
188 try:
189 poller.poll(10*1000*self._poll_interval)
189 poller.poll(10*1000*self._poll_interval)
190 # restore raising of KeyboardInterrupt
190 # restore raising of KeyboardInterrupt
191 signal(SIGINT, default_int_handler)
191 signal(SIGINT, default_int_handler)
192 self.do_one_iteration()
192 self.do_one_iteration()
193 except:
193 except:
194 raise
194 raise
195 finally:
195 finally:
196 # prevent raising of KeyboardInterrupt
196 # prevent raising of KeyboardInterrupt
197 signal(SIGINT,SIG_IGN)
197 signal(SIGINT,SIG_IGN)
198 except KeyboardInterrupt:
198 except KeyboardInterrupt:
199 # Ctrl-C shouldn't crash the kernel
199 # Ctrl-C shouldn't crash the kernel
200 io.raw_print("KeyboardInterrupt caught in kernel")
200 io.raw_print("KeyboardInterrupt caught in kernel")
201 # stop ignoring sigint, now that we are out of our own loop,
201 # stop ignoring sigint, now that we are out of our own loop,
202 # we don't want to prevent future code from handling it
202 # we don't want to prevent future code from handling it
203 signal(SIGINT, default_int_handler)
203 signal(SIGINT, default_int_handler)
204 if self.eventloop is not None:
204 if self.eventloop is not None:
205 try:
205 try:
206 self.eventloop(self)
206 self.eventloop(self)
207 except KeyboardInterrupt:
207 except KeyboardInterrupt:
208 # Ctrl-C shouldn't crash the kernel
208 # Ctrl-C shouldn't crash the kernel
209 io.raw_print("KeyboardInterrupt caught in kernel")
209 io.raw_print("KeyboardInterrupt caught in kernel")
210
210
211
211
212 def record_ports(self, ports):
212 def record_ports(self, ports):
213 """Record the ports that this kernel is using.
213 """Record the ports that this kernel is using.
214
214
215 The creator of the Kernel instance must call this methods if they
215 The creator of the Kernel instance must call this methods if they
216 want the :meth:`connect_request` method to return the port numbers.
216 want the :meth:`connect_request` method to return the port numbers.
217 """
217 """
218 self._recorded_ports = ports
218 self._recorded_ports = ports
219
219
220 #---------------------------------------------------------------------------
220 #---------------------------------------------------------------------------
221 # Kernel request handlers
221 # Kernel request handlers
222 #---------------------------------------------------------------------------
222 #---------------------------------------------------------------------------
223
223
224 def _publish_pyin(self, code, parent):
224 def _publish_pyin(self, code, parent):
225 """Publish the code request on the pyin stream."""
225 """Publish the code request on the pyin stream."""
226
226
227 self.session.send(self.iopub_socket, u'pyin', {u'code':code},
227 self.session.send(self.iopub_socket, u'pyin', {u'code':code},
228 parent=parent)
228 parent=parent)
229
229
230 def execute_request(self, ident, parent):
230 def execute_request(self, ident, parent):
231
231
232 self.session.send(self.iopub_socket,
232 self.session.send(self.iopub_socket,
233 u'status',
233 u'status',
234 {u'execution_state':u'busy'},
234 {u'execution_state':u'busy'},
235 parent=parent )
235 parent=parent )
236
236
237 try:
237 try:
238 content = parent[u'content']
238 content = parent[u'content']
239 code = content[u'code']
239 code = content[u'code']
240 silent = content[u'silent']
240 silent = content[u'silent']
241 except:
241 except:
242 self.log.error("Got bad msg: ")
242 self.log.error("Got bad msg: ")
243 self.log.error(str(Message(parent)))
243 self.log.error(str(Message(parent)))
244 return
244 return
245
245
246 shell = self.shell # we'll need this a lot here
246 shell = self.shell # we'll need this a lot here
247
247
248 # Replace raw_input. Note that is not sufficient to replace
248 # Replace raw_input. Note that is not sufficient to replace
249 # raw_input in the user namespace.
249 # raw_input in the user namespace.
250 if content.get('allow_stdin', False):
250 if content.get('allow_stdin', False):
251 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
251 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
252 else:
252 else:
253 raw_input = lambda prompt='' : self._no_raw_input()
253 raw_input = lambda prompt='' : self._no_raw_input()
254
254
255 if py3compat.PY3:
255 if py3compat.PY3:
256 __builtin__.input = raw_input
256 __builtin__.input = raw_input
257 else:
257 else:
258 __builtin__.raw_input = raw_input
258 __builtin__.raw_input = raw_input
259
259
260 # Set the parent message of the display hook and out streams.
260 # Set the parent message of the display hook and out streams.
261 shell.displayhook.set_parent(parent)
261 shell.displayhook.set_parent(parent)
262 shell.display_pub.set_parent(parent)
262 shell.display_pub.set_parent(parent)
263 sys.stdout.set_parent(parent)
263 sys.stdout.set_parent(parent)
264 sys.stderr.set_parent(parent)
264 sys.stderr.set_parent(parent)
265
265
266 # Re-broadcast our input for the benefit of listening clients, and
266 # Re-broadcast our input for the benefit of listening clients, and
267 # start computing output
267 # start computing output
268 if not silent:
268 if not silent:
269 self._publish_pyin(code, parent)
269 self._publish_pyin(code, parent)
270
270
271 reply_content = {}
271 reply_content = {}
272 try:
272 try:
273 if silent:
273 if silent:
274 # run_code uses 'exec' mode, so no displayhook will fire, and it
274 # run_code uses 'exec' mode, so no displayhook will fire, and it
275 # doesn't call logging or history manipulations. Print
275 # doesn't call logging or history manipulations. Print
276 # statements in that code will obviously still execute.
276 # statements in that code will obviously still execute.
277 shell.run_code(code)
277 shell.run_code(code)
278 else:
278 else:
279 # FIXME: the shell calls the exception handler itself.
279 # FIXME: the shell calls the exception handler itself.
280 shell.run_cell(code, store_history=True)
280 shell.run_cell(code, store_history=True)
281 except:
281 except:
282 status = u'error'
282 status = u'error'
283 # FIXME: this code right now isn't being used yet by default,
283 # FIXME: this code right now isn't being used yet by default,
284 # because the run_cell() call above directly fires off exception
284 # because the run_cell() call above directly fires off exception
285 # reporting. This code, therefore, is only active in the scenario
285 # reporting. This code, therefore, is only active in the scenario
286 # where runlines itself has an unhandled exception. We need to
286 # where runlines itself has an unhandled exception. We need to
287 # uniformize this, for all exception construction to come from a
287 # uniformize this, for all exception construction to come from a
288 # single location in the codbase.
288 # single location in the codbase.
289 etype, evalue, tb = sys.exc_info()
289 etype, evalue, tb = sys.exc_info()
290 tb_list = traceback.format_exception(etype, evalue, tb)
290 tb_list = traceback.format_exception(etype, evalue, tb)
291 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
291 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
292 else:
292 else:
293 status = u'ok'
293 status = u'ok'
294
294
295 reply_content[u'status'] = status
295 reply_content[u'status'] = status
296
296
297 # Return the execution counter so clients can display prompts
297 # Return the execution counter so clients can display prompts
298 reply_content['execution_count'] = shell.execution_count -1
298 reply_content['execution_count'] = shell.execution_count -1
299
299
300 # FIXME - fish exception info out of shell, possibly left there by
300 # FIXME - fish exception info out of shell, possibly left there by
301 # runlines. We'll need to clean up this logic later.
301 # runlines. We'll need to clean up this logic later.
302 if shell._reply_content is not None:
302 if shell._reply_content is not None:
303 reply_content.update(shell._reply_content)
303 reply_content.update(shell._reply_content)
304 # reset after use
304 # reset after use
305 shell._reply_content = None
305 shell._reply_content = None
306
306
307 # At this point, we can tell whether the main code execution succeeded
307 # At this point, we can tell whether the main code execution succeeded
308 # or not. If it did, we proceed to evaluate user_variables/expressions
308 # or not. If it did, we proceed to evaluate user_variables/expressions
309 if reply_content['status'] == 'ok':
309 if reply_content['status'] == 'ok':
310 reply_content[u'user_variables'] = \
310 reply_content[u'user_variables'] = \
311 shell.user_variables(content[u'user_variables'])
311 shell.user_variables(content[u'user_variables'])
312 reply_content[u'user_expressions'] = \
312 reply_content[u'user_expressions'] = \
313 shell.user_expressions(content[u'user_expressions'])
313 shell.user_expressions(content[u'user_expressions'])
314 else:
314 else:
315 # If there was an error, don't even try to compute variables or
315 # If there was an error, don't even try to compute variables or
316 # expressions
316 # expressions
317 reply_content[u'user_variables'] = {}
317 reply_content[u'user_variables'] = {}
318 reply_content[u'user_expressions'] = {}
318 reply_content[u'user_expressions'] = {}
319
319
320 # Payloads should be retrieved regardless of outcome, so we can both
320 # Payloads should be retrieved regardless of outcome, so we can both
321 # recover partial output (that could have been generated early in a
321 # recover partial output (that could have been generated early in a
322 # block, before an error) and clear the payload system always.
322 # block, before an error) and clear the payload system always.
323 reply_content[u'payload'] = shell.payload_manager.read_payload()
323 reply_content[u'payload'] = shell.payload_manager.read_payload()
324 # Be agressive about clearing the payload because we don't want
324 # Be agressive about clearing the payload because we don't want
325 # it to sit in memory until the next execute_request comes in.
325 # it to sit in memory until the next execute_request comes in.
326 shell.payload_manager.clear_payload()
326 shell.payload_manager.clear_payload()
327
327
328 # Flush output before sending the reply.
328 # Flush output before sending the reply.
329 sys.stdout.flush()
329 sys.stdout.flush()
330 sys.stderr.flush()
330 sys.stderr.flush()
331 # FIXME: on rare occasions, the flush doesn't seem to make it to the
331 # FIXME: on rare occasions, the flush doesn't seem to make it to the
332 # clients... This seems to mitigate the problem, but we definitely need
332 # clients... This seems to mitigate the problem, but we definitely need
333 # to better understand what's going on.
333 # to better understand what's going on.
334 if self._execute_sleep:
334 if self._execute_sleep:
335 time.sleep(self._execute_sleep)
335 time.sleep(self._execute_sleep)
336
336
337 # Send the reply.
337 # Send the reply.
338 reply_content = json_clean(reply_content)
338 reply_content = json_clean(reply_content)
339 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
339 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
340 reply_content, parent, ident=ident)
340 reply_content, parent, ident=ident)
341 self.log.debug(str(reply_msg))
341 self.log.debug(str(reply_msg))
342
342
343 if reply_msg['content']['status'] == u'error':
343 if reply_msg['content']['status'] == u'error':
344 self._abort_queue()
344 self._abort_queue()
345
345
346 self.session.send(self.iopub_socket,
346 self.session.send(self.iopub_socket,
347 u'status',
347 u'status',
348 {u'execution_state':u'idle'},
348 {u'execution_state':u'idle'},
349 parent=parent )
349 parent=parent )
350
350
351 def complete_request(self, ident, parent):
351 def complete_request(self, ident, parent):
352 txt, matches = self._complete(parent)
352 txt, matches = self._complete(parent)
353 matches = {'matches' : matches,
353 matches = {'matches' : matches,
354 'matched_text' : txt,
354 'matched_text' : txt,
355 'status' : 'ok'}
355 'status' : 'ok'}
356 matches = json_clean(matches)
356 matches = json_clean(matches)
357 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
357 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
358 matches, parent, ident)
358 matches, parent, ident)
359 self.log.debug(str(completion_msg))
359 self.log.debug(str(completion_msg))
360
360
361 def object_info_request(self, ident, parent):
361 def object_info_request(self, ident, parent):
362 object_info = self.shell.object_inspect(parent['content']['oname'])
362 object_info = self.shell.object_inspect(parent['content']['oname'])
363 # Before we send this object over, we scrub it for JSON usage
363 # Before we send this object over, we scrub it for JSON usage
364 oinfo = json_clean(object_info)
364 oinfo = json_clean(object_info)
365 msg = self.session.send(self.shell_socket, 'object_info_reply',
365 msg = self.session.send(self.shell_socket, 'object_info_reply',
366 oinfo, parent, ident)
366 oinfo, parent, ident)
367 self.log.debug(msg)
367 self.log.debug(msg)
368
368
369 def history_request(self, ident, parent):
369 def history_request(self, ident, parent):
370 # We need to pull these out, as passing **kwargs doesn't work with
370 # We need to pull these out, as passing **kwargs doesn't work with
371 # unicode keys before Python 2.6.5.
371 # unicode keys before Python 2.6.5.
372 hist_access_type = parent['content']['hist_access_type']
372 hist_access_type = parent['content']['hist_access_type']
373 raw = parent['content']['raw']
373 raw = parent['content']['raw']
374 output = parent['content']['output']
374 output = parent['content']['output']
375 if hist_access_type == 'tail':
375 if hist_access_type == 'tail':
376 n = parent['content']['n']
376 n = parent['content']['n']
377 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
377 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
378 include_latest=True)
378 include_latest=True)
379
379
380 elif hist_access_type == 'range':
380 elif hist_access_type == 'range':
381 session = parent['content']['session']
381 session = parent['content']['session']
382 start = parent['content']['start']
382 start = parent['content']['start']
383 stop = parent['content']['stop']
383 stop = parent['content']['stop']
384 hist = self.shell.history_manager.get_range(session, start, stop,
384 hist = self.shell.history_manager.get_range(session, start, stop,
385 raw=raw, output=output)
385 raw=raw, output=output)
386
386
387 elif hist_access_type == 'search':
387 elif hist_access_type == 'search':
388 pattern = parent['content']['pattern']
388 pattern = parent['content']['pattern']
389 hist = self.shell.history_manager.search(pattern, raw=raw,
389 hist = self.shell.history_manager.search(pattern, raw=raw,
390 output=output)
390 output=output)
391
391
392 else:
392 else:
393 hist = []
393 hist = []
394 content = {'history' : list(hist)}
394 content = {'history' : list(hist)}
395 content = json_clean(content)
395 content = json_clean(content)
396 msg = self.session.send(self.shell_socket, 'history_reply',
396 msg = self.session.send(self.shell_socket, 'history_reply',
397 content, parent, ident)
397 content, parent, ident)
398 self.log.debug(str(msg))
398 self.log.debug(str(msg))
399
399
400 def connect_request(self, ident, parent):
400 def connect_request(self, ident, parent):
401 if self._recorded_ports is not None:
401 if self._recorded_ports is not None:
402 content = self._recorded_ports.copy()
402 content = self._recorded_ports.copy()
403 else:
403 else:
404 content = {}
404 content = {}
405 msg = self.session.send(self.shell_socket, 'connect_reply',
405 msg = self.session.send(self.shell_socket, 'connect_reply',
406 content, parent, ident)
406 content, parent, ident)
407 self.log.debug(msg)
407 self.log.debug(msg)
408
408
409 def shutdown_request(self, ident, parent):
409 def shutdown_request(self, ident, parent):
410 self.shell.exit_now = True
410 self.shell.exit_now = True
411 self._shutdown_message = self.session.msg(u'shutdown_reply',
411 self._shutdown_message = self.session.msg(u'shutdown_reply',
412 parent['content'], parent)
412 parent['content'], parent)
413 sys.exit(0)
413 sys.exit(0)
414
414
415 #---------------------------------------------------------------------------
415 #---------------------------------------------------------------------------
416 # Protected interface
416 # Protected interface
417 #---------------------------------------------------------------------------
417 #---------------------------------------------------------------------------
418
418
419 def _abort_queue(self):
419 def _abort_queue(self):
420 while True:
420 while True:
421 try:
421 try:
422 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
422 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
423 except Exception:
423 except Exception:
424 self.log.warn("Invalid Message:", exc_info=True)
424 self.log.warn("Invalid Message:", exc_info=True)
425 continue
425 continue
426 if msg is None:
426 if msg is None:
427 break
427 break
428 else:
428 else:
429 assert ident is not None, \
429 assert ident is not None, \
430 "Unexpected missing message part."
430 "Unexpected missing message part."
431
431
432 self.log.debug("Aborting:\n"+str(Message(msg)))
432 self.log.debug("Aborting:\n"+str(Message(msg)))
433 msg_type = msg['header']['msg_type']
433 msg_type = msg['header']['msg_type']
434 reply_type = msg_type.split('_')[0] + '_reply'
434 reply_type = msg_type.split('_')[0] + '_reply'
435 reply_msg = self.session.send(self.shell_socket, reply_type,
435 reply_msg = self.session.send(self.shell_socket, reply_type,
436 {'status' : 'aborted'}, msg, ident=ident)
436 {'status' : 'aborted'}, msg, ident=ident)
437 self.log.debug(reply_msg)
437 self.log.debug(reply_msg)
438 # We need to wait a bit for requests to come in. This can probably
438 # We need to wait a bit for requests to come in. This can probably
439 # be set shorter for true asynchronous clients.
439 # be set shorter for true asynchronous clients.
440 time.sleep(0.1)
440 time.sleep(0.1)
441
441
442 def _no_raw_input(self):
442 def _no_raw_input(self):
443 """Raise StdinNotImplentedError if active frontend doesn't support
443 """Raise StdinNotImplentedError if active frontend doesn't support
444 stdin."""
444 stdin."""
445 raise StdinNotImplementedError("raw_input was called, but this "
445 raise StdinNotImplementedError("raw_input was called, but this "
446 "frontend does not support stdin.")
446 "frontend does not support stdin.")
447
447
448 def _raw_input(self, prompt, ident, parent):
448 def _raw_input(self, prompt, ident, parent):
449 # Flush output before making the request.
449 # Flush output before making the request.
450 sys.stderr.flush()
450 sys.stderr.flush()
451 sys.stdout.flush()
451 sys.stdout.flush()
452
452
453 # Send the input request.
453 # Send the input request.
454 content = json_clean(dict(prompt=prompt))
454 content = json_clean(dict(prompt=prompt))
455 self.session.send(self.stdin_socket, u'input_request', content, parent,
455 self.session.send(self.stdin_socket, u'input_request', content, parent,
456 ident=ident)
456 ident=ident)
457
457
458 # Await a response.
458 # Await a response.
459 while True:
459 while True:
460 try:
460 try:
461 ident, reply = self.session.recv(self.stdin_socket, 0)
461 ident, reply = self.session.recv(self.stdin_socket, 0)
462 except Exception:
462 except Exception:
463 self.log.warn("Invalid Message:", exc_info=True)
463 self.log.warn("Invalid Message:", exc_info=True)
464 else:
464 else:
465 break
465 break
466 try:
466 try:
467 value = reply['content']['value']
467 value = reply['content']['value']
468 except:
468 except:
469 self.log.error("Got bad raw_input reply: ")
469 self.log.error("Got bad raw_input reply: ")
470 self.log.error(str(Message(parent)))
470 self.log.error(str(Message(parent)))
471 value = ''
471 value = ''
472 if value == '\x04':
473 # EOF
474 raise EOFError
472 return value
475 return value
473
476
474 def _complete(self, msg):
477 def _complete(self, msg):
475 c = msg['content']
478 c = msg['content']
476 try:
479 try:
477 cpos = int(c['cursor_pos'])
480 cpos = int(c['cursor_pos'])
478 except:
481 except:
479 # If we don't get something that we can convert to an integer, at
482 # If we don't get something that we can convert to an integer, at
480 # least attempt the completion guessing the cursor is at the end of
483 # least attempt the completion guessing the cursor is at the end of
481 # the text, if there's any, and otherwise of the line
484 # the text, if there's any, and otherwise of the line
482 cpos = len(c['text'])
485 cpos = len(c['text'])
483 if cpos==0:
486 if cpos==0:
484 cpos = len(c['line'])
487 cpos = len(c['line'])
485 return self.shell.complete(c['text'], c['line'], cpos)
488 return self.shell.complete(c['text'], c['line'], cpos)
486
489
487 def _object_info(self, context):
490 def _object_info(self, context):
488 symbol, leftover = self._symbol_from_context(context)
491 symbol, leftover = self._symbol_from_context(context)
489 if symbol is not None and not leftover:
492 if symbol is not None and not leftover:
490 doc = getattr(symbol, '__doc__', '')
493 doc = getattr(symbol, '__doc__', '')
491 else:
494 else:
492 doc = ''
495 doc = ''
493 object_info = dict(docstring = doc)
496 object_info = dict(docstring = doc)
494 return object_info
497 return object_info
495
498
496 def _symbol_from_context(self, context):
499 def _symbol_from_context(self, context):
497 if not context:
500 if not context:
498 return None, context
501 return None, context
499
502
500 base_symbol_string = context[0]
503 base_symbol_string = context[0]
501 symbol = self.shell.user_ns.get(base_symbol_string, None)
504 symbol = self.shell.user_ns.get(base_symbol_string, None)
502 if symbol is None:
505 if symbol is None:
503 symbol = __builtin__.__dict__.get(base_symbol_string, None)
506 symbol = __builtin__.__dict__.get(base_symbol_string, None)
504 if symbol is None:
507 if symbol is None:
505 return None, context
508 return None, context
506
509
507 context = context[1:]
510 context = context[1:]
508 for i, name in enumerate(context):
511 for i, name in enumerate(context):
509 new_symbol = getattr(symbol, name, None)
512 new_symbol = getattr(symbol, name, None)
510 if new_symbol is None:
513 if new_symbol is None:
511 return symbol, context[i:]
514 return symbol, context[i:]
512 else:
515 else:
513 symbol = new_symbol
516 symbol = new_symbol
514
517
515 return symbol, []
518 return symbol, []
516
519
517 def _at_shutdown(self):
520 def _at_shutdown(self):
518 """Actions taken at shutdown by the kernel, called by python's atexit.
521 """Actions taken at shutdown by the kernel, called by python's atexit.
519 """
522 """
520 # io.rprint("Kernel at_shutdown") # dbg
523 # io.rprint("Kernel at_shutdown") # dbg
521 if self._shutdown_message is not None:
524 if self._shutdown_message is not None:
522 self.session.send(self.shell_socket, self._shutdown_message)
525 self.session.send(self.shell_socket, self._shutdown_message)
523 self.session.send(self.iopub_socket, self._shutdown_message)
526 self.session.send(self.iopub_socket, self._shutdown_message)
524 self.log.debug(str(self._shutdown_message))
527 self.log.debug(str(self._shutdown_message))
525 # A very short sleep to give zmq time to flush its message buffers
528 # A very short sleep to give zmq time to flush its message buffers
526 # before Python truly shuts down.
529 # before Python truly shuts down.
527 time.sleep(0.01)
530 time.sleep(0.01)
528
531
529 #-----------------------------------------------------------------------------
532 #-----------------------------------------------------------------------------
530 # Aliases and Flags for the IPKernelApp
533 # Aliases and Flags for the IPKernelApp
531 #-----------------------------------------------------------------------------
534 #-----------------------------------------------------------------------------
532
535
533 flags = dict(kernel_flags)
536 flags = dict(kernel_flags)
534 flags.update(shell_flags)
537 flags.update(shell_flags)
535
538
536 addflag = lambda *args: flags.update(boolean_flag(*args))
539 addflag = lambda *args: flags.update(boolean_flag(*args))
537
540
538 flags['pylab'] = (
541 flags['pylab'] = (
539 {'IPKernelApp' : {'pylab' : 'auto'}},
542 {'IPKernelApp' : {'pylab' : 'auto'}},
540 """Pre-load matplotlib and numpy for interactive use with
543 """Pre-load matplotlib and numpy for interactive use with
541 the default matplotlib backend."""
544 the default matplotlib backend."""
542 )
545 )
543
546
544 aliases = dict(kernel_aliases)
547 aliases = dict(kernel_aliases)
545 aliases.update(shell_aliases)
548 aliases.update(shell_aliases)
546
549
547 # it's possible we don't want short aliases for *all* of these:
550 # it's possible we don't want short aliases for *all* of these:
548 aliases.update(dict(
551 aliases.update(dict(
549 pylab='IPKernelApp.pylab',
552 pylab='IPKernelApp.pylab',
550 ))
553 ))
551
554
552 #-----------------------------------------------------------------------------
555 #-----------------------------------------------------------------------------
553 # The IPKernelApp class
556 # The IPKernelApp class
554 #-----------------------------------------------------------------------------
557 #-----------------------------------------------------------------------------
555
558
556 class IPKernelApp(KernelApp, InteractiveShellApp):
559 class IPKernelApp(KernelApp, InteractiveShellApp):
557 name = 'ipkernel'
560 name = 'ipkernel'
558
561
559 aliases = Dict(aliases)
562 aliases = Dict(aliases)
560 flags = Dict(flags)
563 flags = Dict(flags)
561 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
564 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
562 # configurables
565 # configurables
563 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
566 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
564 config=True,
567 config=True,
565 help="""Pre-load matplotlib and numpy for interactive use,
568 help="""Pre-load matplotlib and numpy for interactive use,
566 selecting a particular matplotlib backend and loop integration.
569 selecting a particular matplotlib backend and loop integration.
567 """
570 """
568 )
571 )
569
572
570 @catch_config_error
573 @catch_config_error
571 def initialize(self, argv=None):
574 def initialize(self, argv=None):
572 super(IPKernelApp, self).initialize(argv)
575 super(IPKernelApp, self).initialize(argv)
573 self.init_shell()
576 self.init_shell()
574 self.init_extensions()
577 self.init_extensions()
575 self.init_code()
578 self.init_code()
576
579
577 def init_kernel(self):
580 def init_kernel(self):
578
581
579 kernel = Kernel(config=self.config, session=self.session,
582 kernel = Kernel(config=self.config, session=self.session,
580 shell_socket=self.shell_socket,
583 shell_socket=self.shell_socket,
581 iopub_socket=self.iopub_socket,
584 iopub_socket=self.iopub_socket,
582 stdin_socket=self.stdin_socket,
585 stdin_socket=self.stdin_socket,
583 log=self.log,
586 log=self.log,
584 profile_dir=self.profile_dir,
587 profile_dir=self.profile_dir,
585 )
588 )
586 self.kernel = kernel
589 self.kernel = kernel
587 kernel.record_ports(self.ports)
590 kernel.record_ports(self.ports)
588 shell = kernel.shell
591 shell = kernel.shell
589 if self.pylab:
592 if self.pylab:
590 try:
593 try:
591 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
594 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
592 shell.enable_pylab(gui, import_all=self.pylab_import_all)
595 shell.enable_pylab(gui, import_all=self.pylab_import_all)
593 except Exception:
596 except Exception:
594 self.log.error("Pylab initialization failed", exc_info=True)
597 self.log.error("Pylab initialization failed", exc_info=True)
595 # print exception straight to stdout, because normally
598 # print exception straight to stdout, because normally
596 # _showtraceback associates the reply with an execution,
599 # _showtraceback associates the reply with an execution,
597 # which means frontends will never draw it, as this exception
600 # which means frontends will never draw it, as this exception
598 # is not associated with any execute request.
601 # is not associated with any execute request.
599
602
600 # replace pyerr-sending traceback with stdout
603 # replace pyerr-sending traceback with stdout
601 _showtraceback = shell._showtraceback
604 _showtraceback = shell._showtraceback
602 def print_tb(etype, evalue, stb):
605 def print_tb(etype, evalue, stb):
603 print ("Error initializing pylab, pylab mode will not "
606 print ("Error initializing pylab, pylab mode will not "
604 "be active", file=io.stderr)
607 "be active", file=io.stderr)
605 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
608 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
606 shell._showtraceback = print_tb
609 shell._showtraceback = print_tb
607
610
608 # send the traceback over stdout
611 # send the traceback over stdout
609 shell.showtraceback(tb_offset=0)
612 shell.showtraceback(tb_offset=0)
610
613
611 # restore proper _showtraceback method
614 # restore proper _showtraceback method
612 shell._showtraceback = _showtraceback
615 shell._showtraceback = _showtraceback
613
616
614
617
615 def init_shell(self):
618 def init_shell(self):
616 self.shell = self.kernel.shell
619 self.shell = self.kernel.shell
617 self.shell.configurables.append(self)
620 self.shell.configurables.append(self)
618
621
619
622
620 #-----------------------------------------------------------------------------
623 #-----------------------------------------------------------------------------
621 # Kernel main and launch functions
624 # Kernel main and launch functions
622 #-----------------------------------------------------------------------------
625 #-----------------------------------------------------------------------------
623
626
624 def launch_kernel(*args, **kwargs):
627 def launch_kernel(*args, **kwargs):
625 """Launches a localhost IPython kernel, binding to the specified ports.
628 """Launches a localhost IPython kernel, binding to the specified ports.
626
629
627 This function simply calls entry_point.base_launch_kernel with the right
630 This function simply calls entry_point.base_launch_kernel with the right
628 first command to start an ipkernel. See base_launch_kernel for arguments.
631 first command to start an ipkernel. See base_launch_kernel for arguments.
629
632
630 Returns
633 Returns
631 -------
634 -------
632 A tuple of form:
635 A tuple of form:
633 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
636 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
634 where kernel_process is a Popen object and the ports are integers.
637 where kernel_process is a Popen object and the ports are integers.
635 """
638 """
636 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
639 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
637 *args, **kwargs)
640 *args, **kwargs)
638
641
639
642
640 def main():
643 def main():
641 """Run an IPKernel as an application"""
644 """Run an IPKernel as an application"""
642 app = IPKernelApp.instance()
645 app = IPKernelApp.instance()
643 app.initialize()
646 app.initialize()
644 app.start()
647 app.start()
645
648
646
649
647 if __name__ == '__main__':
650 if __name__ == '__main__':
648 main()
651 main()
General Comments 0
You need to be logged in to leave comments. Login now