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