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