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