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