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