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