##// END OF EJS Templates
make an ascii docstring...
MinRK -
Show More
@@ -1,311 +1,311 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import codecs
17 import codecs
18 import os
18 import os
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 from StringIO import StringIO
21 from StringIO import StringIO
22 from .py3compat import PY3
22 from .py3compat import PY3
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Code
25 # Code
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 class IOStream:
29 class IOStream:
30
30
31 def __init__(self,stream, fallback=None):
31 def __init__(self,stream, fallback=None):
32 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
32 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
33 if fallback is not None:
33 if fallback is not None:
34 stream = fallback
34 stream = fallback
35 else:
35 else:
36 raise ValueError("fallback required, but not specified")
36 raise ValueError("fallback required, but not specified")
37 self.stream = stream
37 self.stream = stream
38 self._swrite = stream.write
38 self._swrite = stream.write
39
39
40 # clone all methods not overridden:
40 # clone all methods not overridden:
41 def clone(meth):
41 def clone(meth):
42 return not hasattr(self, meth) and not meth.startswith('_')
42 return not hasattr(self, meth) and not meth.startswith('_')
43 for meth in filter(clone, dir(stream)):
43 for meth in filter(clone, dir(stream)):
44 setattr(self, meth, getattr(stream, meth))
44 setattr(self, meth, getattr(stream, meth))
45
45
46 def write(self,data):
46 def write(self,data):
47 try:
47 try:
48 self._swrite(data)
48 self._swrite(data)
49 except:
49 except:
50 try:
50 try:
51 # print handles some unicode issues which may trip a plain
51 # print handles some unicode issues which may trip a plain
52 # write() call. Emulate write() by using an empty end
52 # write() call. Emulate write() by using an empty end
53 # argument.
53 # argument.
54 print(data, end='', file=self.stream)
54 print(data, end='', file=self.stream)
55 except:
55 except:
56 # if we get here, something is seriously broken.
56 # if we get here, something is seriously broken.
57 print('ERROR - failed to write data to stream:', self.stream,
57 print('ERROR - failed to write data to stream:', self.stream,
58 file=sys.stderr)
58 file=sys.stderr)
59
59
60 def writelines(self, lines):
60 def writelines(self, lines):
61 if isinstance(lines, basestring):
61 if isinstance(lines, basestring):
62 lines = [lines]
62 lines = [lines]
63 for line in lines:
63 for line in lines:
64 self.write(line)
64 self.write(line)
65
65
66 # This class used to have a writeln method, but regular files and streams
66 # This class used to have a writeln method, but regular files and streams
67 # in Python don't have this method. We need to keep this completely
67 # in Python don't have this method. We need to keep this completely
68 # compatible so we removed it.
68 # compatible so we removed it.
69
69
70 @property
70 @property
71 def closed(self):
71 def closed(self):
72 return self.stream.closed
72 return self.stream.closed
73
73
74 def close(self):
74 def close(self):
75 pass
75 pass
76
76
77 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
77 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
78 devnull = open(os.devnull, 'a')
78 devnull = open(os.devnull, 'a')
79 stdin = IOStream(sys.stdin, fallback=devnull)
79 stdin = IOStream(sys.stdin, fallback=devnull)
80 stdout = IOStream(sys.stdout, fallback=devnull)
80 stdout = IOStream(sys.stdout, fallback=devnull)
81 stderr = IOStream(sys.stderr, fallback=devnull)
81 stderr = IOStream(sys.stderr, fallback=devnull)
82
82
83 class IOTerm:
83 class IOTerm:
84 """ Term holds the file or file-like objects for handling I/O operations.
84 """ Term holds the file or file-like objects for handling I/O operations.
85
85
86 These are normally just sys.stdin, sys.stdout and sys.stderr but for
86 These are normally just sys.stdin, sys.stdout and sys.stderr but for
87 Windows they can can replaced to allow editing the strings before they are
87 Windows they can can replaced to allow editing the strings before they are
88 displayed."""
88 displayed."""
89
89
90 # In the future, having IPython channel all its I/O operations through
90 # In the future, having IPython channel all its I/O operations through
91 # this class will make it easier to embed it into other environments which
91 # this class will make it easier to embed it into other environments which
92 # are not a normal terminal (such as a GUI-based shell)
92 # are not a normal terminal (such as a GUI-based shell)
93 def __init__(self, stdin=None, stdout=None, stderr=None):
93 def __init__(self, stdin=None, stdout=None, stderr=None):
94 mymodule = sys.modules[__name__]
94 mymodule = sys.modules[__name__]
95 self.stdin = IOStream(stdin, mymodule.stdin)
95 self.stdin = IOStream(stdin, mymodule.stdin)
96 self.stdout = IOStream(stdout, mymodule.stdout)
96 self.stdout = IOStream(stdout, mymodule.stdout)
97 self.stderr = IOStream(stderr, mymodule.stderr)
97 self.stderr = IOStream(stderr, mymodule.stderr)
98
98
99
99
100 class Tee(object):
100 class Tee(object):
101 """A class to duplicate an output stream to stdout/err.
101 """A class to duplicate an output stream to stdout/err.
102
102
103 This works in a manner very similar to the Unix 'tee' command.
103 This works in a manner very similar to the Unix 'tee' command.
104
104
105 When the object is closed or deleted, it closes the original file given to
105 When the object is closed or deleted, it closes the original file given to
106 it for duplication.
106 it for duplication.
107 """
107 """
108 # Inspired by:
108 # Inspired by:
109 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
109 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
110
110
111 def __init__(self, file_or_name, mode="w", channel='stdout'):
111 def __init__(self, file_or_name, mode="w", channel='stdout'):
112 """Construct a new Tee object.
112 """Construct a new Tee object.
113
113
114 Parameters
114 Parameters
115 ----------
115 ----------
116 file_or_name : filename or open filehandle (writable)
116 file_or_name : filename or open filehandle (writable)
117 File that will be duplicated
117 File that will be duplicated
118
118
119 mode : optional, valid mode for open().
119 mode : optional, valid mode for open().
120 If a filename was give, open with this mode.
120 If a filename was give, open with this mode.
121
121
122 channel : str, one of ['stdout', 'stderr']
122 channel : str, one of ['stdout', 'stderr']
123 """
123 """
124 if channel not in ['stdout', 'stderr']:
124 if channel not in ['stdout', 'stderr']:
125 raise ValueError('Invalid channel spec %s' % channel)
125 raise ValueError('Invalid channel spec %s' % channel)
126
126
127 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
127 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
128 self.file = file_or_name
128 self.file = file_or_name
129 else:
129 else:
130 self.file = open(file_or_name, mode)
130 self.file = open(file_or_name, mode)
131 self.channel = channel
131 self.channel = channel
132 self.ostream = getattr(sys, channel)
132 self.ostream = getattr(sys, channel)
133 setattr(sys, channel, self)
133 setattr(sys, channel, self)
134 self._closed = False
134 self._closed = False
135
135
136 def close(self):
136 def close(self):
137 """Close the file and restore the channel."""
137 """Close the file and restore the channel."""
138 self.flush()
138 self.flush()
139 setattr(sys, self.channel, self.ostream)
139 setattr(sys, self.channel, self.ostream)
140 self.file.close()
140 self.file.close()
141 self._closed = True
141 self._closed = True
142
142
143 def write(self, data):
143 def write(self, data):
144 """Write data to both channels."""
144 """Write data to both channels."""
145 self.file.write(data)
145 self.file.write(data)
146 self.ostream.write(data)
146 self.ostream.write(data)
147 self.ostream.flush()
147 self.ostream.flush()
148
148
149 def flush(self):
149 def flush(self):
150 """Flush both channels."""
150 """Flush both channels."""
151 self.file.flush()
151 self.file.flush()
152 self.ostream.flush()
152 self.ostream.flush()
153
153
154 def __del__(self):
154 def __del__(self):
155 if not self._closed:
155 if not self._closed:
156 self.close()
156 self.close()
157
157
158
158
159 def ask_yes_no(prompt,default=None):
159 def ask_yes_no(prompt,default=None):
160 """Asks a question and returns a boolean (y/n) answer.
160 """Asks a question and returns a boolean (y/n) answer.
161
161
162 If default is given (one of 'y','n'), it is used if the user input is
162 If default is given (one of 'y','n'), it is used if the user input is
163 empty. Otherwise the question is repeated until an answer is given.
163 empty. Otherwise the question is repeated until an answer is given.
164
164
165 An EOF is treated as the default answer. If there is no default, an
165 An EOF is treated as the default answer. If there is no default, an
166 exception is raised to prevent infinite loops.
166 exception is raised to prevent infinite loops.
167
167
168 Valid answers are: y/yes/n/no (match is not case sensitive)."""
168 Valid answers are: y/yes/n/no (match is not case sensitive)."""
169
169
170 answers = {'y':True,'n':False,'yes':True,'no':False}
170 answers = {'y':True,'n':False,'yes':True,'no':False}
171 ans = None
171 ans = None
172 while ans not in answers.keys():
172 while ans not in answers.keys():
173 try:
173 try:
174 ans = raw_input(prompt+' ').lower()
174 ans = raw_input(prompt+' ').lower()
175 if not ans: # response was an empty string
175 if not ans: # response was an empty string
176 ans = default
176 ans = default
177 except KeyboardInterrupt:
177 except KeyboardInterrupt:
178 pass
178 pass
179 except EOFError:
179 except EOFError:
180 if default in answers.keys():
180 if default in answers.keys():
181 ans = default
181 ans = default
182 print()
182 print()
183 else:
183 else:
184 raise
184 raise
185
185
186 return answers[ans]
186 return answers[ans]
187
187
188
188
189 def temp_pyfile(src, ext='.py'):
189 def temp_pyfile(src, ext='.py'):
190 """Make a temporary python file, return filename and filehandle.
190 """Make a temporary python file, return filename and filehandle.
191
191
192 Parameters
192 Parameters
193 ----------
193 ----------
194 src : string or list of strings (no need for ending newlines if list)
194 src : string or list of strings (no need for ending newlines if list)
195 Source code to be written to the file.
195 Source code to be written to the file.
196
196
197 ext : optional, string
197 ext : optional, string
198 Extension for the generated file.
198 Extension for the generated file.
199
199
200 Returns
200 Returns
201 -------
201 -------
202 (filename, open filehandle)
202 (filename, open filehandle)
203 It is the caller's responsibility to close the open file and unlink it.
203 It is the caller's responsibility to close the open file and unlink it.
204 """
204 """
205 fname = tempfile.mkstemp(ext)[1]
205 fname = tempfile.mkstemp(ext)[1]
206 f = open(fname,'w')
206 f = open(fname,'w')
207 f.write(src)
207 f.write(src)
208 f.flush()
208 f.flush()
209 return fname, f
209 return fname, f
210
210
211
211
212 def raw_print(*args, **kw):
212 def raw_print(*args, **kw):
213 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
213 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
214
214
215 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
215 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
216 file=sys.__stdout__)
216 file=sys.__stdout__)
217 sys.__stdout__.flush()
217 sys.__stdout__.flush()
218
218
219
219
220 def raw_print_err(*args, **kw):
220 def raw_print_err(*args, **kw):
221 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
221 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
222
222
223 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
223 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
224 file=sys.__stderr__)
224 file=sys.__stderr__)
225 sys.__stderr__.flush()
225 sys.__stderr__.flush()
226
226
227
227
228 # Short aliases for quick debugging, do NOT use these in production code.
228 # Short aliases for quick debugging, do NOT use these in production code.
229 rprint = raw_print
229 rprint = raw_print
230 rprinte = raw_print_err
230 rprinte = raw_print_err
231
231
232
232
233 class CapturedIO(object):
233 class CapturedIO(object):
234 """Simple object for containing captured stdout/err StringIO objects"""
234 """Simple object for containing captured stdout/err StringIO objects"""
235
235
236 def __init__(self, stdout, stderr):
236 def __init__(self, stdout, stderr):
237 self._stdout = stdout
237 self._stdout = stdout
238 self._stderr = stderr
238 self._stderr = stderr
239
239
240 def __str__(self):
240 def __str__(self):
241 return self.stdout
241 return self.stdout
242
242
243 @property
243 @property
244 def stdout(self):
244 def stdout(self):
245 if not self._stdout:
245 if not self._stdout:
246 return ''
246 return ''
247 return self._stdout.getvalue()
247 return self._stdout.getvalue()
248
248
249 @property
249 @property
250 def stderr(self):
250 def stderr(self):
251 if not self._stderr:
251 if not self._stderr:
252 return ''
252 return ''
253 return self._stderr.getvalue()
253 return self._stderr.getvalue()
254
254
255 def show(self):
255 def show(self):
256 """write my output to sys.stdout/err as appropriate"""
256 """write my output to sys.stdout/err as appropriate"""
257 sys.stdout.write(self.stdout)
257 sys.stdout.write(self.stdout)
258 sys.stderr.write(self.stderr)
258 sys.stderr.write(self.stderr)
259 sys.stdout.flush()
259 sys.stdout.flush()
260 sys.stderr.flush()
260 sys.stderr.flush()
261
261
262 __call__ = show
262 __call__ = show
263
263
264
264
265 class capture_output(object):
265 class capture_output(object):
266 """context manager for capturing stdout/err"""
266 """context manager for capturing stdout/err"""
267 stdout = True
267 stdout = True
268 stderr = True
268 stderr = True
269
269
270 def __init__(self, stdout=True, stderr=True):
270 def __init__(self, stdout=True, stderr=True):
271 self.stdout = stdout
271 self.stdout = stdout
272 self.stderr = stderr
272 self.stderr = stderr
273
273
274 def __enter__(self):
274 def __enter__(self):
275 self.sys_stdout = sys.stdout
275 self.sys_stdout = sys.stdout
276 self.sys_stderr = sys.stderr
276 self.sys_stderr = sys.stderr
277
277
278 stdout = stderr = False
278 stdout = stderr = False
279 if self.stdout:
279 if self.stdout:
280 stdout = sys.stdout = StringIO()
280 stdout = sys.stdout = StringIO()
281 if self.stderr:
281 if self.stderr:
282 stderr = sys.stderr = StringIO()
282 stderr = sys.stderr = StringIO()
283
283
284 return CapturedIO(stdout, stderr)
284 return CapturedIO(stdout, stderr)
285
285
286 def __exit__(self, exc_type, exc_value, traceback):
286 def __exit__(self, exc_type, exc_value, traceback):
287 sys.stdout = self.sys_stdout
287 sys.stdout = self.sys_stdout
288 sys.stderr = self.sys_stderr
288 sys.stderr = self.sys_stderr
289
289
290 def unicode_std_stream(stream='stdout'):
290 def unicode_std_stream(stream='stdout'):
291 u"""Get a wrapper to write unicode to stdout/stderr as UTF-8.
291 r"""Get a wrapper to write unicode to stdout/stderr as UTF-8.
292
292
293 This ignores environment variables and default encodings, to reliably write
293 This ignores environment variables and default encodings, to reliably write
294 unicode to stdout or stderr.
294 unicode to stdout or stderr.
295
295
296 ::
296 ::
297
297
298 unicode_std_stream().write(u'ł@e¶ŧ←')
298 unicode_std_stream().write(u'\u0142@e\xb6\u0167\u2190')
299 """
299 """
300 assert stream in ('stdout', 'stderr')
300 assert stream in ('stdout', 'stderr')
301 stream = getattr(sys, stream)
301 stream = getattr(sys, stream)
302 if PY3:
302 if PY3:
303 try:
303 try:
304 stream_b = stream.buffer
304 stream_b = stream.buffer
305 except AttributeError:
305 except AttributeError:
306 # sys.stdout has been replaced - use it directly
306 # sys.stdout has been replaced - use it directly
307 return stream
307 return stream
308 else:
308 else:
309 stream_b = stream
309 stream_b = stream
310
310
311 return codecs.getwriter('utf-8')(stream_b)
311 return codecs.getwriter('utf-8')(stream_b)
General Comments 0
You need to be logged in to leave comments. Login now