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