##// END OF EJS Templates
bring multiline-hist fix from trunk into zmq console
MinRK -
Show More
@@ -1,306 +1,311
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 sys
21 import sys
22 import time
22 import time
23
23
24 from Queue import Empty
24 from Queue import Empty
25
25
26 from IPython.core.alias import AliasManager, AliasError
26 from IPython.core.alias import AliasManager, AliasError
27 from IPython.core import page
27 from IPython.core import page
28 from IPython.utils.warn import warn, error, fatal
28 from IPython.utils.warn import warn, error, fatal
29 from IPython.utils import io
29 from IPython.utils import io
30
30
31 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
31 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
32 from IPython.frontend.terminal.console.completer import ZMQCompleter
32 from IPython.frontend.terminal.console.completer import ZMQCompleter
33
33
34
34
35 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
35 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
36 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
36 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
37 _executing = False
37 _executing = False
38
38
39 def __init__(self, *args, **kwargs):
39 def __init__(self, *args, **kwargs):
40 self.km = kwargs.pop('kernel_manager')
40 self.km = kwargs.pop('kernel_manager')
41 self.session_id = self.km.session.session
41 self.session_id = self.km.session.session
42 super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs)
42 super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs)
43
43
44 def init_completer(self):
44 def init_completer(self):
45 """Initialize the completion machinery.
45 """Initialize the completion machinery.
46
46
47 This creates completion machinery that can be used by client code,
47 This creates completion machinery that can be used by client code,
48 either interactively in-process (typically triggered by the readline
48 either interactively in-process (typically triggered by the readline
49 library), programatically (such as in test suites) or out-of-prcess
49 library), programatically (such as in test suites) or out-of-prcess
50 (typically over the network by remote frontends).
50 (typically over the network by remote frontends).
51 """
51 """
52 from IPython.core.completerlib import (module_completer,
52 from IPython.core.completerlib import (module_completer,
53 magic_run_completer, cd_completer)
53 magic_run_completer, cd_completer)
54
54
55 self.Completer = ZMQCompleter(self, self.km)
55 self.Completer = ZMQCompleter(self, self.km)
56
56
57
57
58 self.set_hook('complete_command', module_completer, str_key = 'import')
58 self.set_hook('complete_command', module_completer, str_key = 'import')
59 self.set_hook('complete_command', module_completer, str_key = 'from')
59 self.set_hook('complete_command', module_completer, str_key = 'from')
60 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
60 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
61 self.set_hook('complete_command', cd_completer, str_key = '%cd')
61 self.set_hook('complete_command', cd_completer, str_key = '%cd')
62
62
63 # Only configure readline if we truly are using readline. IPython can
63 # Only configure readline if we truly are using readline. IPython can
64 # do tab-completion over the network, in GUIs, etc, where readline
64 # do tab-completion over the network, in GUIs, etc, where readline
65 # itself may be absent
65 # itself may be absent
66 if self.has_readline:
66 if self.has_readline:
67 self.set_readline_completer()
67 self.set_readline_completer()
68
68
69 def run_cell(self, cell, store_history=True):
69 def run_cell(self, cell, store_history=True):
70 """Run a complete IPython cell.
70 """Run a complete IPython cell.
71
71
72 Parameters
72 Parameters
73 ----------
73 ----------
74 cell : str
74 cell : str
75 The code (including IPython code such as %magic functions) to run.
75 The code (including IPython code such as %magic functions) to run.
76 store_history : bool
76 store_history : bool
77 If True, the raw and translated cell will be stored in IPython's
77 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
78 history. For user code calling back into IPython's machinery, this
79 should be set to False.
79 should be set to False.
80 """
80 """
81 if (not cell) or cell.isspace():
81 if (not cell) or cell.isspace():
82 return
82 return
83
83
84 self._executing = True
84 self._executing = True
85 # flush stale replies, which could have been ignored, due to missed heartbeats
85 # flush stale replies, which could have been ignored, due to missed heartbeats
86 while self.km.shell_channel.msg_ready():
86 while self.km.shell_channel.msg_ready():
87 self.km.shell_channel.get_msg()
87 self.km.shell_channel.get_msg()
88 # shell_channel.execute takes 'hidden', which is the inverse of store_hist
88 # shell_channel.execute takes 'hidden', which is the inverse of store_hist
89 msg_id = self.km.shell_channel.execute(cell, not store_history)
89 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:
90 while not self.km.shell_channel.msg_ready() and self.km.is_alive:
91 try:
91 try:
92 self.handle_stdin_request(timeout=0.05)
92 self.handle_stdin_request(timeout=0.05)
93 except Empty:
93 except Empty:
94 # display intermediate print statements, etc.
94 # display intermediate print statements, etc.
95 self.handle_iopub()
95 self.handle_iopub()
96 pass
96 pass
97 if self.km.shell_channel.msg_ready():
97 if self.km.shell_channel.msg_ready():
98 self.handle_execute_reply(msg_id)
98 self.handle_execute_reply(msg_id)
99 self._executing = False
99 self._executing = False
100
100
101 #-----------------
101 #-----------------
102 # message handlers
102 # message handlers
103 #-----------------
103 #-----------------
104
104
105 def handle_execute_reply(self, msg_id):
105 def handle_execute_reply(self, msg_id):
106 msg = self.km.shell_channel.get_msg()
106 msg = self.km.shell_channel.get_msg()
107 if msg["parent_header"].get("msg_id", None) == msg_id:
107 if msg["parent_header"].get("msg_id", None) == msg_id:
108
108
109 self.handle_iopub()
109 self.handle_iopub()
110
110
111 content = msg["content"]
111 content = msg["content"]
112 status = content['status']
112 status = content['status']
113
113
114 if status == 'aborted':
114 if status == 'aborted':
115 self.write('Aborted\n')
115 self.write('Aborted\n')
116 return
116 return
117 elif status == 'ok':
117 elif status == 'ok':
118 # print execution payloads as well:
118 # print execution payloads as well:
119 for item in content["payload"]:
119 for item in content["payload"]:
120 text = item.get('text', None)
120 text = item.get('text', None)
121 if text:
121 if text:
122 page.page(text)
122 page.page(text)
123
123
124 elif status == 'error':
124 elif status == 'error':
125 for frame in content["traceback"]:
125 for frame in content["traceback"]:
126 print(frame, file=io.stderr)
126 print(frame, file=io.stderr)
127
127
128 self.execution_count = int(content["execution_count"] + 1)
128 self.execution_count = int(content["execution_count"] + 1)
129
129
130
130
131 def handle_iopub(self):
131 def handle_iopub(self):
132 """ Method to procces subscribe channel's messages
132 """ Method to procces subscribe channel's messages
133
133
134 This method reads a message and processes the content in different
134 This method reads a message and processes the content in different
135 outputs like stdout, stderr, pyout and status
135 outputs like stdout, stderr, pyout and status
136
136
137 Arguments:
137 Arguments:
138 sub_msg: message receive from kernel in the sub socket channel
138 sub_msg: message receive from kernel in the sub socket channel
139 capture by kernel manager.
139 capture by kernel manager.
140 """
140 """
141 while self.km.sub_channel.msg_ready():
141 while self.km.sub_channel.msg_ready():
142 sub_msg = self.km.sub_channel.get_msg()
142 sub_msg = self.km.sub_channel.get_msg()
143 msg_type = sub_msg['header']['msg_type']
143 msg_type = sub_msg['header']['msg_type']
144 if self.session_id == sub_msg['parent_header']['session']:
144 if self.session_id == sub_msg['parent_header']['session']:
145 if msg_type == 'status' :
145 if msg_type == 'status' :
146 if sub_msg["content"]["execution_state"] == "busy" :
146 if sub_msg["content"]["execution_state"] == "busy" :
147 pass
147 pass
148
148
149 elif msg_type == 'stream' :
149 elif msg_type == 'stream' :
150 if sub_msg["content"]["name"] == "stdout":
150 if sub_msg["content"]["name"] == "stdout":
151 print(sub_msg["content"]["data"], file=io.stdout, end="")
151 print(sub_msg["content"]["data"], file=io.stdout, end="")
152 io.stdout.flush()
152 io.stdout.flush()
153 elif sub_msg["content"]["name"] == "stderr" :
153 elif sub_msg["content"]["name"] == "stderr" :
154 print(sub_msg["content"]["data"], file=io.stderr, end="")
154 print(sub_msg["content"]["data"], file=io.stderr, end="")
155 io.stderr.flush()
155 io.stderr.flush()
156
156
157 elif msg_type == 'pyout':
157 elif msg_type == 'pyout':
158 self.execution_count = int(sub_msg["content"]["execution_count"])
158 self.execution_count = int(sub_msg["content"]["execution_count"])
159 format_dict = sub_msg["content"]["data"]
159 format_dict = sub_msg["content"]["data"]
160 # taken from DisplayHook.__call__:
160 # taken from DisplayHook.__call__:
161 hook = self.displayhook
161 hook = self.displayhook
162 hook.start_displayhook()
162 hook.start_displayhook()
163 hook.write_output_prompt()
163 hook.write_output_prompt()
164 hook.write_format_data(format_dict)
164 hook.write_format_data(format_dict)
165 hook.log_output(format_dict)
165 hook.log_output(format_dict)
166 hook.finish_displayhook()
166 hook.finish_displayhook()
167
167
168 def handle_stdin_request(self, timeout=0.1):
168 def handle_stdin_request(self, timeout=0.1):
169 """ Method to capture raw_input
169 """ Method to capture raw_input
170 """
170 """
171 msg_rep = self.km.stdin_channel.get_msg(timeout=timeout)
171 msg_rep = self.km.stdin_channel.get_msg(timeout=timeout)
172 if self.session_id == msg_rep["parent_header"]["session"] :
172 if self.session_id == msg_rep["parent_header"]["session"] :
173 raw_data = raw_input(msg_rep["content"]["prompt"])
173 raw_data = raw_input(msg_rep["content"]["prompt"])
174 self.km.stdin_channel.input(raw_data)
174 self.km.stdin_channel.input(raw_data)
175
175
176 def mainloop(self, display_banner=False):
176 def mainloop(self, display_banner=False):
177 while True:
177 while True:
178 try:
178 try:
179 self.interact(display_banner=display_banner)
179 self.interact(display_banner=display_banner)
180 #self.interact_with_readline()
180 #self.interact_with_readline()
181 # XXX for testing of a readline-decoupled repl loop, call
181 # XXX for testing of a readline-decoupled repl loop, call
182 # interact_with_readline above
182 # interact_with_readline above
183 break
183 break
184 except KeyboardInterrupt:
184 except KeyboardInterrupt:
185 # this should not be necessary, but KeyboardInterrupt
185 # this should not be necessary, but KeyboardInterrupt
186 # handling seems rather unpredictable...
186 # handling seems rather unpredictable...
187 self.write("\nKeyboardInterrupt in interact()\n")
187 self.write("\nKeyboardInterrupt in interact()\n")
188
188
189 def wait_for_kernel(self, timeout=None):
189 def wait_for_kernel(self, timeout=None):
190 """method to wait for a kernel to be ready"""
190 """method to wait for a kernel to be ready"""
191 tic = time.time()
191 tic = time.time()
192 self.km.hb_channel.unpause()
192 self.km.hb_channel.unpause()
193 while True:
193 while True:
194 self.run_cell('1', False)
194 self.run_cell('1', False)
195 if self.km.hb_channel.is_beating():
195 if self.km.hb_channel.is_beating():
196 # heart failure was not the reason this returned
196 # heart failure was not the reason this returned
197 break
197 break
198 else:
198 else:
199 # heart failed
199 # heart failed
200 if timeout is not None and (time.time() - tic) > timeout:
200 if timeout is not None and (time.time() - tic) > timeout:
201 return False
201 return False
202 return True
202 return True
203
203
204 def interact(self, display_banner=None):
204 def interact(self, display_banner=None):
205 """Closely emulate the interactive Python console."""
205 """Closely emulate the interactive Python console."""
206
206
207 # batch run -> do not interact
207 # batch run -> do not interact
208 if self.exit_now:
208 if self.exit_now:
209 return
209 return
210
210
211 if display_banner is None:
211 if display_banner is None:
212 display_banner = self.display_banner
212 display_banner = self.display_banner
213
213
214 if isinstance(display_banner, basestring):
214 if isinstance(display_banner, basestring):
215 self.show_banner(display_banner)
215 self.show_banner(display_banner)
216 elif display_banner:
216 elif display_banner:
217 self.show_banner()
217 self.show_banner()
218
218
219 more = False
219 more = False
220
220
221 # run a non-empty no-op, so that we don't get a prompt until
221 # 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
222 # we know the kernel is ready. This keeps the connection
223 # message above the first prompt.
223 # message above the first prompt.
224 if not self.wait_for_kernel(3):
224 if not self.wait_for_kernel(3):
225 error("Kernel did not respond\n")
225 error("Kernel did not respond\n")
226 return
226 return
227
227
228 if self.has_readline:
228 if self.has_readline:
229 self.readline_startup_hook(self.pre_readline)
229 self.readline_startup_hook(self.pre_readline)
230 hlen_b4_cell = self.readline.get_current_history_length()
231 else:
232 hlen_b4_cell = 0
230 # exit_now is set by a call to %Exit or %Quit, through the
233 # exit_now is set by a call to %Exit or %Quit, through the
231 # ask_exit callback.
234 # ask_exit callback.
232
235
233 while not self.exit_now:
236 while not self.exit_now:
234 if not self.km.is_alive:
237 if not self.km.is_alive:
235 # kernel died, prompt for action or exit
238 # kernel died, prompt for action or exit
236 action = "restart" if self.km.has_kernel else "wait for restart"
239 action = "restart" if self.km.has_kernel else "wait for restart"
237 ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
240 ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
238 if ans:
241 if ans:
239 if self.km.has_kernel:
242 if self.km.has_kernel:
240 self.km.restart_kernel(True)
243 self.km.restart_kernel(True)
241 self.wait_for_kernel(3)
244 self.wait_for_kernel(3)
242 else:
245 else:
243 self.exit_now = True
246 self.exit_now = True
244 continue
247 continue
245 try:
248 try:
246 # protect prompt block from KeyboardInterrupt
249 # protect prompt block from KeyboardInterrupt
247 # when sitting on ctrl-C
250 # when sitting on ctrl-C
248 self.hooks.pre_prompt_hook()
251 self.hooks.pre_prompt_hook()
249 if more:
252 if more:
250 try:
253 try:
251 prompt = self.hooks.generate_prompt(True)
254 prompt = self.hooks.generate_prompt(True)
252 except Exception:
255 except Exception:
253 self.showtraceback()
256 self.showtraceback()
254 if self.autoindent:
257 if self.autoindent:
255 self.rl_do_indent = True
258 self.rl_do_indent = True
256
259
257 else:
260 else:
258 try:
261 try:
259 prompt = self.hooks.generate_prompt(False)
262 prompt = self.hooks.generate_prompt(False)
260 except Exception:
263 except Exception:
261 self.showtraceback()
264 self.showtraceback()
262
265
263 line = self.raw_input(prompt)
266 line = self.raw_input(prompt)
264 if self.exit_now:
267 if self.exit_now:
265 # quick exit on sys.std[in|out] close
268 # quick exit on sys.std[in|out] close
266 break
269 break
267 if self.autoindent:
270 if self.autoindent:
268 self.rl_do_indent = False
271 self.rl_do_indent = False
269
272
270 except KeyboardInterrupt:
273 except KeyboardInterrupt:
271 #double-guard against keyboardinterrupts during kbdint handling
274 #double-guard against keyboardinterrupts during kbdint handling
272 try:
275 try:
273 self.write('\nKeyboardInterrupt\n')
276 self.write('\nKeyboardInterrupt\n')
274 self.input_splitter.reset()
277 source_raw = self.input_splitter.source_raw_reset()[1]
278 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
275 more = False
279 more = False
276 except KeyboardInterrupt:
280 except KeyboardInterrupt:
277 pass
281 pass
278 except EOFError:
282 except EOFError:
279 if self.autoindent:
283 if self.autoindent:
280 self.rl_do_indent = False
284 self.rl_do_indent = False
281 if self.has_readline:
285 if self.has_readline:
282 self.readline_startup_hook(None)
286 self.readline_startup_hook(None)
283 self.write('\n')
287 self.write('\n')
284 self.exit()
288 self.exit()
285 except bdb.BdbQuit:
289 except bdb.BdbQuit:
286 warn('The Python debugger has exited with a BdbQuit exception.\n'
290 warn('The Python debugger has exited with a BdbQuit exception.\n'
287 'Because of how pdb handles the stack, it is impossible\n'
291 'Because of how pdb handles the stack, it is impossible\n'
288 'for IPython to properly format this particular exception.\n'
292 'for IPython to properly format this particular exception.\n'
289 'IPython will resume normal operation.')
293 'IPython will resume normal operation.')
290 except:
294 except:
291 # exceptions here are VERY RARE, but they can be triggered
295 # exceptions here are VERY RARE, but they can be triggered
292 # asynchronously by signal handlers, for example.
296 # asynchronously by signal handlers, for example.
293 self.showtraceback()
297 self.showtraceback()
294 else:
298 else:
295 self.input_splitter.push(line)
299 self.input_splitter.push(line)
296 more = self.input_splitter.push_accepts_more()
300 more = self.input_splitter.push_accepts_more()
297 if (self.SyntaxTB.last_syntax_error and
301 if (self.SyntaxTB.last_syntax_error and
298 self.autoedit_syntax):
302 self.autoedit_syntax):
299 self.edit_syntax_error()
303 self.edit_syntax_error()
300 if not more:
304 if not more:
301 source_raw = self.input_splitter.source_reset()
305 source_raw = self.input_splitter.source_reset()
306 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
302 self.run_cell(source_raw)
307 self.run_cell(source_raw)
303
308
304
309
305 # Turn off the exit flag, so the mainloop can be restarted if desired
310 # Turn off the exit flag, so the mainloop can be restarted if desired
306 self.exit_now = False
311 self.exit_now = False
General Comments 0
You need to be logged in to leave comments. Login now