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