##// END OF EJS Templates
Provide cleaner names for raw print utilities.
Fernando Perez -
Show More
@@ -1,294 +1,299 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-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 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 sys
17 import sys
18 import tempfile
18 import tempfile
19
19
20 from IPython.external.Itpl import itpl, printpl
20 from IPython.external.Itpl import itpl, printpl
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Code
23 # Code
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 class IOStream:
27 class IOStream:
28
28
29 def __init__(self,stream,fallback):
29 def __init__(self,stream,fallback):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 stream = fallback
31 stream = fallback
32 self.stream = stream
32 self.stream = stream
33 self._swrite = stream.write
33 self._swrite = stream.write
34 self.flush = stream.flush
34 self.flush = stream.flush
35
35
36 def write(self,data):
36 def write(self,data):
37 try:
37 try:
38 self._swrite(data)
38 self._swrite(data)
39 except:
39 except:
40 try:
40 try:
41 # print handles some unicode issues which may trip a plain
41 # print handles some unicode issues which may trip a plain
42 # write() call. Emulate write() by using an empty end
42 # write() call. Emulate write() by using an empty end
43 # argument.
43 # argument.
44 print(data, end='', file=self.stream)
44 print(data, end='', file=self.stream)
45 except:
45 except:
46 # if we get here, something is seriously broken.
46 # if we get here, something is seriously broken.
47 print('ERROR - failed to write data to stream:', self.stream,
47 print('ERROR - failed to write data to stream:', self.stream,
48 file=sys.stderr)
48 file=sys.stderr)
49
49
50 # This class used to have a writeln method, but regular files and streams
50 # This class used to have a writeln method, but regular files and streams
51 # in Python don't have this method. We need to keep this completely
51 # in Python don't have this method. We need to keep this completely
52 # compatible so we removed it.
52 # compatible so we removed it.
53
53
54 def close(self):
54 def close(self):
55 pass
55 pass
56
56
57
57
58 class IOTerm:
58 class IOTerm:
59 """ Term holds the file or file-like objects for handling I/O operations.
59 """ Term holds the file or file-like objects for handling I/O operations.
60
60
61 These are normally just sys.stdin, sys.stdout and sys.stderr but for
61 These are normally just sys.stdin, sys.stdout and sys.stderr but for
62 Windows they can can replaced to allow editing the strings before they are
62 Windows they can can replaced to allow editing the strings before they are
63 displayed."""
63 displayed."""
64
64
65 # In the future, having IPython channel all its I/O operations through
65 # In the future, having IPython channel all its I/O operations through
66 # this class will make it easier to embed it into other environments which
66 # this class will make it easier to embed it into other environments which
67 # are not a normal terminal (such as a GUI-based shell)
67 # are not a normal terminal (such as a GUI-based shell)
68 def __init__(self, cin=None, cout=None, cerr=None):
68 def __init__(self, cin=None, cout=None, cerr=None):
69 self.cin = IOStream(cin, sys.stdin)
69 self.cin = IOStream(cin, sys.stdin)
70 self.cout = IOStream(cout, sys.stdout)
70 self.cout = IOStream(cout, sys.stdout)
71 self.cerr = IOStream(cerr, sys.stderr)
71 self.cerr = IOStream(cerr, sys.stderr)
72
72
73
73
74 class Tee(object):
74 class Tee(object):
75 """A class to duplicate an output stream to stdout/err.
75 """A class to duplicate an output stream to stdout/err.
76
76
77 This works in a manner very similar to the Unix 'tee' command.
77 This works in a manner very similar to the Unix 'tee' command.
78
78
79 When the object is closed or deleted, it closes the original file given to
79 When the object is closed or deleted, it closes the original file given to
80 it for duplication.
80 it for duplication.
81 """
81 """
82 # Inspired by:
82 # Inspired by:
83 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
83 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
84
84
85 def __init__(self, file_or_name, mode=None, channel='stdout'):
85 def __init__(self, file_or_name, mode=None, channel='stdout'):
86 """Construct a new Tee object.
86 """Construct a new Tee object.
87
87
88 Parameters
88 Parameters
89 ----------
89 ----------
90 file_or_name : filename or open filehandle (writable)
90 file_or_name : filename or open filehandle (writable)
91 File that will be duplicated
91 File that will be duplicated
92
92
93 mode : optional, valid mode for open().
93 mode : optional, valid mode for open().
94 If a filename was give, open with this mode.
94 If a filename was give, open with this mode.
95
95
96 channel : str, one of ['stdout', 'stderr']
96 channel : str, one of ['stdout', 'stderr']
97 """
97 """
98 if channel not in ['stdout', 'stderr']:
98 if channel not in ['stdout', 'stderr']:
99 raise ValueError('Invalid channel spec %s' % channel)
99 raise ValueError('Invalid channel spec %s' % channel)
100
100
101 if hasattr(file, 'write') and hasattr(file, 'seek'):
101 if hasattr(file, 'write') and hasattr(file, 'seek'):
102 self.file = file_or_name
102 self.file = file_or_name
103 else:
103 else:
104 self.file = open(file_or_name, mode)
104 self.file = open(file_or_name, mode)
105 self.channel = channel
105 self.channel = channel
106 self.ostream = getattr(sys, channel)
106 self.ostream = getattr(sys, channel)
107 setattr(sys, channel, self)
107 setattr(sys, channel, self)
108 self._closed = False
108 self._closed = False
109
109
110 def close(self):
110 def close(self):
111 """Close the file and restore the channel."""
111 """Close the file and restore the channel."""
112 self.flush()
112 self.flush()
113 setattr(sys, self.channel, self.ostream)
113 setattr(sys, self.channel, self.ostream)
114 self.file.close()
114 self.file.close()
115 self._closed = True
115 self._closed = True
116
116
117 def write(self, data):
117 def write(self, data):
118 """Write data to both channels."""
118 """Write data to both channels."""
119 self.file.write(data)
119 self.file.write(data)
120 self.ostream.write(data)
120 self.ostream.write(data)
121 self.ostream.flush()
121 self.ostream.flush()
122
122
123 def flush(self):
123 def flush(self):
124 """Flush both channels."""
124 """Flush both channels."""
125 self.file.flush()
125 self.file.flush()
126 self.ostream.flush()
126 self.ostream.flush()
127
127
128 def __del__(self):
128 def __del__(self):
129 if not self._closed:
129 if not self._closed:
130 self.close()
130 self.close()
131
131
132
132
133 def file_read(filename):
133 def file_read(filename):
134 """Read a file and close it. Returns the file source."""
134 """Read a file and close it. Returns the file source."""
135 fobj = open(filename,'r');
135 fobj = open(filename,'r');
136 source = fobj.read();
136 source = fobj.read();
137 fobj.close()
137 fobj.close()
138 return source
138 return source
139
139
140
140
141 def file_readlines(filename):
141 def file_readlines(filename):
142 """Read a file and close it. Returns the file source using readlines()."""
142 """Read a file and close it. Returns the file source using readlines()."""
143 fobj = open(filename,'r');
143 fobj = open(filename,'r');
144 lines = fobj.readlines();
144 lines = fobj.readlines();
145 fobj.close()
145 fobj.close()
146 return lines
146 return lines
147
147
148
148
149 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
149 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
150 """Take multiple lines of input.
150 """Take multiple lines of input.
151
151
152 A list with each line of input as a separate element is returned when a
152 A list with each line of input as a separate element is returned when a
153 termination string is entered (defaults to a single '.'). Input can also
153 termination string is entered (defaults to a single '.'). Input can also
154 terminate via EOF (^D in Unix, ^Z-RET in Windows).
154 terminate via EOF (^D in Unix, ^Z-RET in Windows).
155
155
156 Lines of input which end in \\ are joined into single entries (and a
156 Lines of input which end in \\ are joined into single entries (and a
157 secondary continuation prompt is issued as long as the user terminates
157 secondary continuation prompt is issued as long as the user terminates
158 lines with \\). This allows entering very long strings which are still
158 lines with \\). This allows entering very long strings which are still
159 meant to be treated as single entities.
159 meant to be treated as single entities.
160 """
160 """
161
161
162 try:
162 try:
163 if header:
163 if header:
164 header += '\n'
164 header += '\n'
165 lines = [raw_input(header + ps1)]
165 lines = [raw_input(header + ps1)]
166 except EOFError:
166 except EOFError:
167 return []
167 return []
168 terminate = [terminate_str]
168 terminate = [terminate_str]
169 try:
169 try:
170 while lines[-1:] != terminate:
170 while lines[-1:] != terminate:
171 new_line = raw_input(ps1)
171 new_line = raw_input(ps1)
172 while new_line.endswith('\\'):
172 while new_line.endswith('\\'):
173 new_line = new_line[:-1] + raw_input(ps2)
173 new_line = new_line[:-1] + raw_input(ps2)
174 lines.append(new_line)
174 lines.append(new_line)
175
175
176 return lines[:-1] # don't return the termination command
176 return lines[:-1] # don't return the termination command
177 except EOFError:
177 except EOFError:
178 print
178 print
179 return lines
179 return lines
180
180
181
181
182 def raw_input_ext(prompt='', ps2='... '):
182 def raw_input_ext(prompt='', ps2='... '):
183 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
183 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
184
184
185 line = raw_input(prompt)
185 line = raw_input(prompt)
186 while line.endswith('\\'):
186 while line.endswith('\\'):
187 line = line[:-1] + raw_input(ps2)
187 line = line[:-1] + raw_input(ps2)
188 return line
188 return line
189
189
190
190
191 def ask_yes_no(prompt,default=None):
191 def ask_yes_no(prompt,default=None):
192 """Asks a question and returns a boolean (y/n) answer.
192 """Asks a question and returns a boolean (y/n) answer.
193
193
194 If default is given (one of 'y','n'), it is used if the user input is
194 If default is given (one of 'y','n'), it is used if the user input is
195 empty. Otherwise the question is repeated until an answer is given.
195 empty. Otherwise the question is repeated until an answer is given.
196
196
197 An EOF is treated as the default answer. If there is no default, an
197 An EOF is treated as the default answer. If there is no default, an
198 exception is raised to prevent infinite loops.
198 exception is raised to prevent infinite loops.
199
199
200 Valid answers are: y/yes/n/no (match is not case sensitive)."""
200 Valid answers are: y/yes/n/no (match is not case sensitive)."""
201
201
202 answers = {'y':True,'n':False,'yes':True,'no':False}
202 answers = {'y':True,'n':False,'yes':True,'no':False}
203 ans = None
203 ans = None
204 while ans not in answers.keys():
204 while ans not in answers.keys():
205 try:
205 try:
206 ans = raw_input(prompt+' ').lower()
206 ans = raw_input(prompt+' ').lower()
207 if not ans: # response was an empty string
207 if not ans: # response was an empty string
208 ans = default
208 ans = default
209 except KeyboardInterrupt:
209 except KeyboardInterrupt:
210 pass
210 pass
211 except EOFError:
211 except EOFError:
212 if default in answers.keys():
212 if default in answers.keys():
213 ans = default
213 ans = default
214 print
214 print
215 else:
215 else:
216 raise
216 raise
217
217
218 return answers[ans]
218 return answers[ans]
219
219
220
220
221 class NLprinter:
221 class NLprinter:
222 """Print an arbitrarily nested list, indicating index numbers.
222 """Print an arbitrarily nested list, indicating index numbers.
223
223
224 An instance of this class called nlprint is available and callable as a
224 An instance of this class called nlprint is available and callable as a
225 function.
225 function.
226
226
227 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
227 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
228 and using 'sep' to separate the index from the value. """
228 and using 'sep' to separate the index from the value. """
229
229
230 def __init__(self):
230 def __init__(self):
231 self.depth = 0
231 self.depth = 0
232
232
233 def __call__(self,lst,pos='',**kw):
233 def __call__(self,lst,pos='',**kw):
234 """Prints the nested list numbering levels."""
234 """Prints the nested list numbering levels."""
235 kw.setdefault('indent',' ')
235 kw.setdefault('indent',' ')
236 kw.setdefault('sep',': ')
236 kw.setdefault('sep',': ')
237 kw.setdefault('start',0)
237 kw.setdefault('start',0)
238 kw.setdefault('stop',len(lst))
238 kw.setdefault('stop',len(lst))
239 # we need to remove start and stop from kw so they don't propagate
239 # we need to remove start and stop from kw so they don't propagate
240 # into a recursive call for a nested list.
240 # into a recursive call for a nested list.
241 start = kw['start']; del kw['start']
241 start = kw['start']; del kw['start']
242 stop = kw['stop']; del kw['stop']
242 stop = kw['stop']; del kw['stop']
243 if self.depth == 0 and 'header' in kw.keys():
243 if self.depth == 0 and 'header' in kw.keys():
244 print(kw['header'])
244 print(kw['header'])
245
245
246 for idx in range(start,stop):
246 for idx in range(start,stop):
247 elem = lst[idx]
247 elem = lst[idx]
248 if type(elem)==type([]):
248 if type(elem)==type([]):
249 self.depth += 1
249 self.depth += 1
250 self.__call__(elem,itpl('$pos$idx,'),**kw)
250 self.__call__(elem,itpl('$pos$idx,'),**kw)
251 self.depth -= 1
251 self.depth -= 1
252 else:
252 else:
253 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
253 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
254
254
255 nlprint = NLprinter()
255 nlprint = NLprinter()
256
256
257
257
258 def temp_pyfile(src, ext='.py'):
258 def temp_pyfile(src, ext='.py'):
259 """Make a temporary python file, return filename and filehandle.
259 """Make a temporary python file, return filename and filehandle.
260
260
261 Parameters
261 Parameters
262 ----------
262 ----------
263 src : string or list of strings (no need for ending newlines if list)
263 src : string or list of strings (no need for ending newlines if list)
264 Source code to be written to the file.
264 Source code to be written to the file.
265
265
266 ext : optional, string
266 ext : optional, string
267 Extension for the generated file.
267 Extension for the generated file.
268
268
269 Returns
269 Returns
270 -------
270 -------
271 (filename, open filehandle)
271 (filename, open filehandle)
272 It is the caller's responsibility to close the open file and unlink it.
272 It is the caller's responsibility to close the open file and unlink it.
273 """
273 """
274 fname = tempfile.mkstemp(ext)[1]
274 fname = tempfile.mkstemp(ext)[1]
275 f = open(fname,'w')
275 f = open(fname,'w')
276 f.write(src)
276 f.write(src)
277 f.flush()
277 f.flush()
278 return fname, f
278 return fname, f
279
279
280
280
281 def rprint(*args, **kw):
281 def raw_print(*args, **kw):
282 """Raw print to sys.__stdout__"""
282 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
283
283
284 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
284 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
285 file=sys.__stdout__)
285 file=sys.__stdout__)
286 sys.__stdout__.flush()
286 sys.__stdout__.flush()
287
287
288
288
289 def rprinte(*args, **kw):
289 def raw_print_err(*args, **kw):
290 """Raw print to sys.__stderr__"""
290 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
291
291
292 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
292 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
293 file=sys.__stderr__)
293 file=sys.__stderr__)
294 sys.__stderr__.flush()
294 sys.__stderr__.flush()
295
296
297 # Short aliases for quick debugging, do NOT use these in production code.
298 rprint = raw_print
299 rprinte = raw_print_err
General Comments 0
You need to be logged in to leave comments. Login now