##// END OF EJS Templates
Redirect unused pipes to devnull
Takafumi Arakaki -
Show More
@@ -1,461 +1,462 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 signal
22 import os
22 23 import sys
23 24 import time
24 25 import tempfile
25 26 import subprocess
26 27 from io import BytesIO
27 28 import base64
28 29
29 30 from Queue import Empty
30 31
31 32 from IPython.core.alias import AliasManager, AliasError
32 33 from IPython.core import page
33 34 from IPython.utils.warn import warn, error, fatal
34 35 from IPython.utils import io
35 36 from IPython.utils.traitlets import List, Enum, Any
36 37
37 38 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
38 39 from IPython.frontend.terminal.console.completer import ZMQCompleter
39 40
40 41
41 42 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
42 43 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
43 44 _executing = False
44 45
45 46 image_handler = Enum(('PIL', 'stream', 'tempfile', 'callable'),
46 47 config=True, help=
47 48 """
48 49 Handler for image type output. This is useful, for example,
49 50 when connecting to the kernel in which pylab inline backend is
50 51 activated. There are four handlers defined. 'PIL': Use
51 52 Python Imaging Library to popup image; 'stream': Use an
52 53 external program to show the image. Image will be fed into
53 54 the STDIN of the program. You will need to configure
54 55 `stream_image_handler`; 'tempfile': Use an external program to
55 56 show the image. Image will be saved in a temporally file and
56 57 the program is called with the temporally file. You will need
57 58 to configure `tempfile_image_handler`; 'callable': You can set
58 59 any Python callable which is called with the image data. You
59 60 will need to configure `callable_image_handler`.
60 61 """
61 62 )
62 63
63 64 stream_image_handler = List(config=True, help=
64 65 """
65 66 Command to invoke an image viewer program when you are using
66 67 'stream' image handler. This option is a list of string where
67 68 the first element is the command itself and reminders are the
68 69 options for the command. Raw image data is given as STDIN to
69 70 the program.
70 71 """
71 72 )
72 73
73 74 tempfile_image_handler = List(config=True, help=
74 75 """
75 76 Command to invoke an image viewer program when you are using
76 77 'tempfile' image handler. This option is a list of string
77 78 where the first element is the command itself and reminders
78 79 are the options for the command. You can use {file} and
79 80 {format} in the string to represent the location of the
80 81 generated image file and image format.
81 82 """
82 83 )
83 84
84 85 callable_image_handler = Any(config=True, help=
85 86 """
86 87 Callable object called via 'callable' image handler with one
87 88 argument, `data`, which is `msg["content"]["data"]` where
88 89 `msg` is the message from iopub channel. For exmaple, you can
89 90 find base64 encoded PNG data as `data['image/png']`. You can
90 91 use {format} in the string to represent the image format.
91 92 """
92 93 )
93 94
94 95 mime_preference = List(
95 96 default_value=['image/png', 'image/jpeg', 'image/svg+xml'],
96 97 config=True, allow_none=False, help=
97 98 """
98 99 Preferred object representation MIME type in order. First
99 100 matched MIME type will be used.
100 101 """
101 102 )
102 103
103 104 def __init__(self, *args, **kwargs):
104 105 self.km = kwargs.pop('kernel_manager')
105 106 self.session_id = self.km.session.session
106 107 super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs)
107 108
108 109 def init_completer(self):
109 110 """Initialize the completion machinery.
110 111
111 112 This creates completion machinery that can be used by client code,
112 113 either interactively in-process (typically triggered by the readline
113 114 library), programatically (such as in test suites) or out-of-prcess
114 115 (typically over the network by remote frontends).
115 116 """
116 117 from IPython.core.completerlib import (module_completer,
117 118 magic_run_completer, cd_completer)
118 119
119 120 self.Completer = ZMQCompleter(self, self.km)
120 121
121 122
122 123 self.set_hook('complete_command', module_completer, str_key = 'import')
123 124 self.set_hook('complete_command', module_completer, str_key = 'from')
124 125 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
125 126 self.set_hook('complete_command', cd_completer, str_key = '%cd')
126 127
127 128 # Only configure readline if we truly are using readline. IPython can
128 129 # do tab-completion over the network, in GUIs, etc, where readline
129 130 # itself may be absent
130 131 if self.has_readline:
131 132 self.set_readline_completer()
132 133
133 134 def run_cell(self, cell, store_history=True):
134 135 """Run a complete IPython cell.
135 136
136 137 Parameters
137 138 ----------
138 139 cell : str
139 140 The code (including IPython code such as %magic functions) to run.
140 141 store_history : bool
141 142 If True, the raw and translated cell will be stored in IPython's
142 143 history. For user code calling back into IPython's machinery, this
143 144 should be set to False.
144 145 """
145 146 if (not cell) or cell.isspace():
146 147 return
147 148
148 149 if cell.strip() == 'exit':
149 150 # explicitly handle 'exit' command
150 151 return self.ask_exit()
151 152
152 153 self._executing = True
153 154 # flush stale replies, which could have been ignored, due to missed heartbeats
154 155 while self.km.shell_channel.msg_ready():
155 156 self.km.shell_channel.get_msg()
156 157 # shell_channel.execute takes 'hidden', which is the inverse of store_hist
157 158 msg_id = self.km.shell_channel.execute(cell, not store_history)
158 159 while not self.km.shell_channel.msg_ready() and self.km.is_alive:
159 160 try:
160 161 self.handle_stdin_request(timeout=0.05)
161 162 except Empty:
162 163 # display intermediate print statements, etc.
163 164 self.handle_iopub()
164 165 pass
165 166 if self.km.shell_channel.msg_ready():
166 167 self.handle_execute_reply(msg_id)
167 168 self._executing = False
168 169
169 170 #-----------------
170 171 # message handlers
171 172 #-----------------
172 173
173 174 def handle_execute_reply(self, msg_id):
174 175 msg = self.km.shell_channel.get_msg()
175 176 if msg["parent_header"].get("msg_id", None) == msg_id:
176 177
177 178 self.handle_iopub()
178 179
179 180 content = msg["content"]
180 181 status = content['status']
181 182
182 183 if status == 'aborted':
183 184 self.write('Aborted\n')
184 185 return
185 186 elif status == 'ok':
186 187 # print execution payloads as well:
187 188 for item in content["payload"]:
188 189 text = item.get('text', None)
189 190 if text:
190 191 page.page(text)
191 192
192 193 elif status == 'error':
193 194 for frame in content["traceback"]:
194 195 print(frame, file=io.stderr)
195 196
196 197 self.execution_count = int(content["execution_count"] + 1)
197 198
198 199
199 200 def handle_iopub(self):
200 201 """ Method to procces subscribe channel's messages
201 202
202 203 This method reads a message and processes the content in different
203 204 outputs like stdout, stderr, pyout and status
204 205
205 206 Arguments:
206 207 sub_msg: message receive from kernel in the sub socket channel
207 208 capture by kernel manager.
208 209 """
209 210 while self.km.sub_channel.msg_ready():
210 211 sub_msg = self.km.sub_channel.get_msg()
211 212 msg_type = sub_msg['header']['msg_type']
212 213 parent = sub_msg["parent_header"]
213 214 if (not parent) or self.session_id == parent['session']:
214 215 if msg_type == 'status' :
215 216 if sub_msg["content"]["execution_state"] == "busy" :
216 217 pass
217 218
218 219 elif msg_type == 'stream' :
219 220 if sub_msg["content"]["name"] == "stdout":
220 221 print(sub_msg["content"]["data"], file=io.stdout, end="")
221 222 io.stdout.flush()
222 223 elif sub_msg["content"]["name"] == "stderr" :
223 224 print(sub_msg["content"]["data"], file=io.stderr, end="")
224 225 io.stderr.flush()
225 226
226 227 elif msg_type == 'pyout':
227 228 self.execution_count = int(sub_msg["content"]["execution_count"])
228 229 format_dict = sub_msg["content"]["data"]
229 230 self.handle_rich_data(format_dict)
230 231 # taken from DisplayHook.__call__:
231 232 hook = self.displayhook
232 233 hook.start_displayhook()
233 234 hook.write_output_prompt()
234 235 hook.write_format_data(format_dict)
235 236 hook.log_output(format_dict)
236 237 hook.finish_displayhook()
237 238
238 239 elif msg_type == 'display_data':
239 240 self.handle_rich_data(sub_msg["content"]["data"])
240 241
241 242 _imagemime = {
242 243 'image/png': 'png',
243 244 'image/jpeg': 'jpeg',
244 245 'image/svg+xml': 'svg',
245 246 }
246 247
247 248 def handle_rich_data(self, data):
248 249 for mime in self.mime_preference:
249 250 if mime in data and mime in self._imagemime:
250 251 self.handle_image(data, mime)
251 252 return
252 253
253 254 def handle_image(self, data, mime):
254 255 handler = getattr(
255 256 self, 'handle_image_{0}'.format(self.image_handler), None)
256 257 if handler:
257 258 handler(data, mime)
258 259
259 260 def handle_image_PIL(self, data, mime):
260 261 if mime not in ('image/png', 'image/jpeg'):
261 262 return
262 263 import PIL
263 264 raw = base64.decodestring(data[mime])
264 265 img = PIL.Image.open(BytesIO(raw))
265 266 img.show()
266 267
267 268 def handle_image_stream(self, data, mime):
268 269 raw = base64.decodestring(data[mime])
269 270 imageformat = self._imagemime[mime]
270 271 fmt = dict(format=imageformat)
271 272 args = [s.format(**fmt) for s in self.stream_image_handler]
273 with open(os.devnull, 'w') as devnull:
272 274 proc = subprocess.Popen(
273 275 args, stdin=subprocess.PIPE,
274 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
276 stdout=devnull, stderr=devnull)
275 277 proc.communicate(raw)
276 278
277 279 def handle_image_tempfile(self, data, mime):
278 280 raw = base64.decodestring(data[mime])
279 281 imageformat = self._imagemime[mime]
280 282 ext = '.{0}'.format(imageformat)
281 with tempfile.NamedTemporaryFile(suffix=ext) as f:
283 with tempfile.NamedTemporaryFile(suffix=ext) as f, \
284 open(os.devnull, 'w') as devnull:
282 285 f.write(raw)
283 286 f.flush()
284 287 fmt = dict(file=f.name, format=imageformat)
285 288 args = [s.format(**fmt) for s in self.tempfile_image_handler]
286 subprocess.Popen(
287 args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
288 ).communicate()
289 subprocess.call(args, stdout=devnull, stderr=devnull)
289 290
290 291 def handle_image_callable(self, data, mime):
291 292 self.callable_image_handler(data)
292 293
293 294 def handle_stdin_request(self, timeout=0.1):
294 295 """ Method to capture raw_input
295 296 """
296 297 msg_rep = self.km.stdin_channel.get_msg(timeout=timeout)
297 298 # in case any iopub came while we were waiting:
298 299 self.handle_iopub()
299 300 if self.session_id == msg_rep["parent_header"].get("session"):
300 301 # wrap SIGINT handler
301 302 real_handler = signal.getsignal(signal.SIGINT)
302 303 def double_int(sig,frame):
303 304 # call real handler (forwards sigint to kernel),
304 305 # then raise local interrupt, stopping local raw_input
305 306 real_handler(sig,frame)
306 307 raise KeyboardInterrupt
307 308 signal.signal(signal.SIGINT, double_int)
308 309
309 310 try:
310 311 raw_data = raw_input(msg_rep["content"]["prompt"])
311 312 except EOFError:
312 313 # turn EOFError into EOF character
313 314 raw_data = '\x04'
314 315 except KeyboardInterrupt:
315 316 sys.stdout.write('\n')
316 317 return
317 318 finally:
318 319 # restore SIGINT handler
319 320 signal.signal(signal.SIGINT, real_handler)
320 321
321 322 # only send stdin reply if there *was not* another request
322 323 # or execution finished while we were reading.
323 324 if not (self.km.stdin_channel.msg_ready() or self.km.shell_channel.msg_ready()):
324 325 self.km.stdin_channel.input(raw_data)
325 326
326 327 def mainloop(self, display_banner=False):
327 328 while True:
328 329 try:
329 330 self.interact(display_banner=display_banner)
330 331 #self.interact_with_readline()
331 332 # XXX for testing of a readline-decoupled repl loop, call
332 333 # interact_with_readline above
333 334 break
334 335 except KeyboardInterrupt:
335 336 # this should not be necessary, but KeyboardInterrupt
336 337 # handling seems rather unpredictable...
337 338 self.write("\nKeyboardInterrupt in interact()\n")
338 339
339 340 def wait_for_kernel(self, timeout=None):
340 341 """method to wait for a kernel to be ready"""
341 342 tic = time.time()
342 343 self.km.hb_channel.unpause()
343 344 while True:
344 345 self.run_cell('1', False)
345 346 if self.km.hb_channel.is_beating():
346 347 # heart failure was not the reason this returned
347 348 break
348 349 else:
349 350 # heart failed
350 351 if timeout is not None and (time.time() - tic) > timeout:
351 352 return False
352 353 return True
353 354
354 355 def interact(self, display_banner=None):
355 356 """Closely emulate the interactive Python console."""
356 357
357 358 # batch run -> do not interact
358 359 if self.exit_now:
359 360 return
360 361
361 362 if display_banner is None:
362 363 display_banner = self.display_banner
363 364
364 365 if isinstance(display_banner, basestring):
365 366 self.show_banner(display_banner)
366 367 elif display_banner:
367 368 self.show_banner()
368 369
369 370 more = False
370 371
371 372 # run a non-empty no-op, so that we don't get a prompt until
372 373 # we know the kernel is ready. This keeps the connection
373 374 # message above the first prompt.
374 375 if not self.wait_for_kernel(3):
375 376 error("Kernel did not respond\n")
376 377 return
377 378
378 379 if self.has_readline:
379 380 self.readline_startup_hook(self.pre_readline)
380 381 hlen_b4_cell = self.readline.get_current_history_length()
381 382 else:
382 383 hlen_b4_cell = 0
383 384 # exit_now is set by a call to %Exit or %Quit, through the
384 385 # ask_exit callback.
385 386
386 387 while not self.exit_now:
387 388 if not self.km.is_alive:
388 389 # kernel died, prompt for action or exit
389 390 action = "restart" if self.km.has_kernel else "wait for restart"
390 391 ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
391 392 if ans:
392 393 if self.km.has_kernel:
393 394 self.km.restart_kernel(True)
394 395 self.wait_for_kernel(3)
395 396 else:
396 397 self.exit_now = True
397 398 continue
398 399 try:
399 400 # protect prompt block from KeyboardInterrupt
400 401 # when sitting on ctrl-C
401 402 self.hooks.pre_prompt_hook()
402 403 if more:
403 404 try:
404 405 prompt = self.prompt_manager.render('in2')
405 406 except Exception:
406 407 self.showtraceback()
407 408 if self.autoindent:
408 409 self.rl_do_indent = True
409 410
410 411 else:
411 412 try:
412 413 prompt = self.separate_in + self.prompt_manager.render('in')
413 414 except Exception:
414 415 self.showtraceback()
415 416
416 417 line = self.raw_input(prompt)
417 418 if self.exit_now:
418 419 # quick exit on sys.std[in|out] close
419 420 break
420 421 if self.autoindent:
421 422 self.rl_do_indent = False
422 423
423 424 except KeyboardInterrupt:
424 425 #double-guard against keyboardinterrupts during kbdint handling
425 426 try:
426 427 self.write('\nKeyboardInterrupt\n')
427 428 source_raw = self.input_splitter.source_raw_reset()[1]
428 429 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
429 430 more = False
430 431 except KeyboardInterrupt:
431 432 pass
432 433 except EOFError:
433 434 if self.autoindent:
434 435 self.rl_do_indent = False
435 436 if self.has_readline:
436 437 self.readline_startup_hook(None)
437 438 self.write('\n')
438 439 self.exit()
439 440 except bdb.BdbQuit:
440 441 warn('The Python debugger has exited with a BdbQuit exception.\n'
441 442 'Because of how pdb handles the stack, it is impossible\n'
442 443 'for IPython to properly format this particular exception.\n'
443 444 'IPython will resume normal operation.')
444 445 except:
445 446 # exceptions here are VERY RARE, but they can be triggered
446 447 # asynchronously by signal handlers, for example.
447 448 self.showtraceback()
448 449 else:
449 450 self.input_splitter.push(line)
450 451 more = self.input_splitter.push_accepts_more()
451 452 if (self.SyntaxTB.last_syntax_error and
452 453 self.autoedit_syntax):
453 454 self.edit_syntax_error()
454 455 if not more:
455 456 source_raw = self.input_splitter.source_raw_reset()[1]
456 457 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
457 458 self.run_cell(source_raw)
458 459
459 460
460 461 # Turn off the exit flag, so the mainloop can be restarted if desired
461 462 self.exit_now = False
General Comments 0
You need to be logged in to leave comments. Login now