##// END OF EJS Templates
Insert a new line after catching KeyboardException in ask_yes_no...
sachet-mittal -
Show More
@@ -1,239 +1,240 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9
9
10
10
11 import atexit
11 import atexit
12 import os
12 import os
13 import sys
13 import sys
14 import tempfile
14 import tempfile
15 import warnings
15 import warnings
16 from warnings import warn
16 from warnings import warn
17
17
18 from IPython.utils.decorators import undoc
18 from IPython.utils.decorators import undoc
19 from .capture import CapturedIO, capture_output
19 from .capture import CapturedIO, capture_output
20 from .py3compat import string_types, input, PY3
20 from .py3compat import string_types, input, PY3
21
21
22 @undoc
22 @undoc
23 class IOStream:
23 class IOStream:
24
24
25 def __init__(self, stream, fallback=None):
25 def __init__(self, stream, fallback=None):
26 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
26 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
27 DeprecationWarning, stacklevel=2)
27 DeprecationWarning, stacklevel=2)
28 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
28 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
29 if fallback is not None:
29 if fallback is not None:
30 stream = fallback
30 stream = fallback
31 else:
31 else:
32 raise ValueError("fallback required, but not specified")
32 raise ValueError("fallback required, but not specified")
33 self.stream = stream
33 self.stream = stream
34 self._swrite = stream.write
34 self._swrite = stream.write
35
35
36 # clone all methods not overridden:
36 # clone all methods not overridden:
37 def clone(meth):
37 def clone(meth):
38 return not hasattr(self, meth) and not meth.startswith('_')
38 return not hasattr(self, meth) and not meth.startswith('_')
39 for meth in filter(clone, dir(stream)):
39 for meth in filter(clone, dir(stream)):
40 setattr(self, meth, getattr(stream, meth))
40 setattr(self, meth, getattr(stream, meth))
41
41
42 def __repr__(self):
42 def __repr__(self):
43 cls = self.__class__
43 cls = self.__class__
44 tpl = '{mod}.{cls}({args})'
44 tpl = '{mod}.{cls}({args})'
45 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
45 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
46
46
47 def write(self,data):
47 def write(self,data):
48 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
48 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
49 DeprecationWarning, stacklevel=2)
49 DeprecationWarning, stacklevel=2)
50 try:
50 try:
51 self._swrite(data)
51 self._swrite(data)
52 except:
52 except:
53 try:
53 try:
54 # print handles some unicode issues which may trip a plain
54 # print handles some unicode issues which may trip a plain
55 # write() call. Emulate write() by using an empty end
55 # write() call. Emulate write() by using an empty end
56 # argument.
56 # argument.
57 print(data, end='', file=self.stream)
57 print(data, end='', file=self.stream)
58 except:
58 except:
59 # if we get here, something is seriously broken.
59 # if we get here, something is seriously broken.
60 print('ERROR - failed to write data to stream:', self.stream,
60 print('ERROR - failed to write data to stream:', self.stream,
61 file=sys.stderr)
61 file=sys.stderr)
62
62
63 def writelines(self, lines):
63 def writelines(self, lines):
64 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
64 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
65 DeprecationWarning, stacklevel=2)
65 DeprecationWarning, stacklevel=2)
66 if isinstance(lines, string_types):
66 if isinstance(lines, string_types):
67 lines = [lines]
67 lines = [lines]
68 for line in lines:
68 for line in lines:
69 self.write(line)
69 self.write(line)
70
70
71 # This class used to have a writeln method, but regular files and streams
71 # This class used to have a writeln method, but regular files and streams
72 # in Python don't have this method. We need to keep this completely
72 # in Python don't have this method. We need to keep this completely
73 # compatible so we removed it.
73 # compatible so we removed it.
74
74
75 @property
75 @property
76 def closed(self):
76 def closed(self):
77 return self.stream.closed
77 return self.stream.closed
78
78
79 def close(self):
79 def close(self):
80 pass
80 pass
81
81
82 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
82 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
83 devnull = open(os.devnull, 'w')
83 devnull = open(os.devnull, 'w')
84 atexit.register(devnull.close)
84 atexit.register(devnull.close)
85
85
86 # io.std* are deprecated, but don't show our own deprecation warnings
86 # io.std* are deprecated, but don't show our own deprecation warnings
87 # during initialization of the deprecated API.
87 # during initialization of the deprecated API.
88 with warnings.catch_warnings():
88 with warnings.catch_warnings():
89 warnings.simplefilter('ignore', DeprecationWarning)
89 warnings.simplefilter('ignore', DeprecationWarning)
90 stdin = IOStream(sys.stdin, fallback=devnull)
90 stdin = IOStream(sys.stdin, fallback=devnull)
91 stdout = IOStream(sys.stdout, fallback=devnull)
91 stdout = IOStream(sys.stdout, fallback=devnull)
92 stderr = IOStream(sys.stderr, fallback=devnull)
92 stderr = IOStream(sys.stderr, fallback=devnull)
93
93
94 class Tee(object):
94 class Tee(object):
95 """A class to duplicate an output stream to stdout/err.
95 """A class to duplicate an output stream to stdout/err.
96
96
97 This works in a manner very similar to the Unix 'tee' command.
97 This works in a manner very similar to the Unix 'tee' command.
98
98
99 When the object is closed or deleted, it closes the original file given to
99 When the object is closed or deleted, it closes the original file given to
100 it for duplication.
100 it for duplication.
101 """
101 """
102 # Inspired by:
102 # Inspired by:
103 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
103 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
104
104
105 def __init__(self, file_or_name, mode="w", channel='stdout'):
105 def __init__(self, file_or_name, mode="w", channel='stdout'):
106 """Construct a new Tee object.
106 """Construct a new Tee object.
107
107
108 Parameters
108 Parameters
109 ----------
109 ----------
110 file_or_name : filename or open filehandle (writable)
110 file_or_name : filename or open filehandle (writable)
111 File that will be duplicated
111 File that will be duplicated
112
112
113 mode : optional, valid mode for open().
113 mode : optional, valid mode for open().
114 If a filename was give, open with this mode.
114 If a filename was give, open with this mode.
115
115
116 channel : str, one of ['stdout', 'stderr']
116 channel : str, one of ['stdout', 'stderr']
117 """
117 """
118 if channel not in ['stdout', 'stderr']:
118 if channel not in ['stdout', 'stderr']:
119 raise ValueError('Invalid channel spec %s' % channel)
119 raise ValueError('Invalid channel spec %s' % channel)
120
120
121 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
121 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
122 self.file = file_or_name
122 self.file = file_or_name
123 else:
123 else:
124 self.file = open(file_or_name, mode)
124 self.file = open(file_or_name, mode)
125 self.channel = channel
125 self.channel = channel
126 self.ostream = getattr(sys, channel)
126 self.ostream = getattr(sys, channel)
127 setattr(sys, channel, self)
127 setattr(sys, channel, self)
128 self._closed = False
128 self._closed = False
129
129
130 def close(self):
130 def close(self):
131 """Close the file and restore the channel."""
131 """Close the file and restore the channel."""
132 self.flush()
132 self.flush()
133 setattr(sys, self.channel, self.ostream)
133 setattr(sys, self.channel, self.ostream)
134 self.file.close()
134 self.file.close()
135 self._closed = True
135 self._closed = True
136
136
137 def write(self, data):
137 def write(self, data):
138 """Write data to both channels."""
138 """Write data to both channels."""
139 self.file.write(data)
139 self.file.write(data)
140 self.ostream.write(data)
140 self.ostream.write(data)
141 self.ostream.flush()
141 self.ostream.flush()
142
142
143 def flush(self):
143 def flush(self):
144 """Flush both channels."""
144 """Flush both channels."""
145 self.file.flush()
145 self.file.flush()
146 self.ostream.flush()
146 self.ostream.flush()
147
147
148 def __del__(self):
148 def __del__(self):
149 if not self._closed:
149 if not self._closed:
150 self.close()
150 self.close()
151
151
152
152
153 def ask_yes_no(prompt, default=None, interrupt=None):
153 def ask_yes_no(prompt, default=None, interrupt=None):
154 """Asks a question and returns a boolean (y/n) answer.
154 """Asks a question and returns a boolean (y/n) answer.
155
155
156 If default is given (one of 'y','n'), it is used if the user input is
156 If default is given (one of 'y','n'), it is used if the user input is
157 empty. If interrupt is given (one of 'y','n'), it is used if the user
157 empty. If interrupt is given (one of 'y','n'), it is used if the user
158 presses Ctrl-C. Otherwise the question is repeated until an answer is
158 presses Ctrl-C. Otherwise the question is repeated until an answer is
159 given.
159 given.
160
160
161 An EOF is treated as the default answer. If there is no default, an
161 An EOF is treated as the default answer. If there is no default, an
162 exception is raised to prevent infinite loops.
162 exception is raised to prevent infinite loops.
163
163
164 Valid answers are: y/yes/n/no (match is not case sensitive)."""
164 Valid answers are: y/yes/n/no (match is not case sensitive)."""
165
165
166 answers = {'y':True,'n':False,'yes':True,'no':False}
166 answers = {'y':True,'n':False,'yes':True,'no':False}
167 ans = None
167 ans = None
168 while ans not in answers.keys():
168 while ans not in answers.keys():
169 try:
169 try:
170 ans = input(prompt+' ').lower()
170 ans = input(prompt+' ').lower()
171 if not ans: # response was an empty string
171 if not ans: # response was an empty string
172 ans = default
172 ans = default
173 except KeyboardInterrupt:
173 except KeyboardInterrupt:
174 if interrupt:
174 if interrupt:
175 ans = interrupt
175 ans = interrupt
176 print("\r")
176 except EOFError:
177 except EOFError:
177 if default in answers.keys():
178 if default in answers.keys():
178 ans = default
179 ans = default
179 print()
180 print()
180 else:
181 else:
181 raise
182 raise
182
183
183 return answers[ans]
184 return answers[ans]
184
185
185
186
186 def temp_pyfile(src, ext='.py'):
187 def temp_pyfile(src, ext='.py'):
187 """Make a temporary python file, return filename and filehandle.
188 """Make a temporary python file, return filename and filehandle.
188
189
189 Parameters
190 Parameters
190 ----------
191 ----------
191 src : string or list of strings (no need for ending newlines if list)
192 src : string or list of strings (no need for ending newlines if list)
192 Source code to be written to the file.
193 Source code to be written to the file.
193
194
194 ext : optional, string
195 ext : optional, string
195 Extension for the generated file.
196 Extension for the generated file.
196
197
197 Returns
198 Returns
198 -------
199 -------
199 (filename, open filehandle)
200 (filename, open filehandle)
200 It is the caller's responsibility to close the open file and unlink it.
201 It is the caller's responsibility to close the open file and unlink it.
201 """
202 """
202 fname = tempfile.mkstemp(ext)[1]
203 fname = tempfile.mkstemp(ext)[1]
203 f = open(fname,'w')
204 f = open(fname,'w')
204 f.write(src)
205 f.write(src)
205 f.flush()
206 f.flush()
206 return fname, f
207 return fname, f
207
208
208 def atomic_writing(*args, **kwargs):
209 def atomic_writing(*args, **kwargs):
209 """DEPRECATED: moved to notebook.services.contents.fileio"""
210 """DEPRECATED: moved to notebook.services.contents.fileio"""
210 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
211 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
211 from notebook.services.contents.fileio import atomic_writing
212 from notebook.services.contents.fileio import atomic_writing
212 return atomic_writing(*args, **kwargs)
213 return atomic_writing(*args, **kwargs)
213
214
214 def raw_print(*args, **kw):
215 def raw_print(*args, **kw):
215 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
216 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
216
217
217 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
218 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
218 file=sys.__stdout__)
219 file=sys.__stdout__)
219 sys.__stdout__.flush()
220 sys.__stdout__.flush()
220
221
221
222
222 def raw_print_err(*args, **kw):
223 def raw_print_err(*args, **kw):
223 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
224 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
224
225
225 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
226 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
226 file=sys.__stderr__)
227 file=sys.__stderr__)
227 sys.__stderr__.flush()
228 sys.__stderr__.flush()
228
229
229
230
230 # Short aliases for quick debugging, do NOT use these in production code.
231 # Short aliases for quick debugging, do NOT use these in production code.
231 rprint = raw_print
232 rprint = raw_print
232 rprinte = raw_print_err
233 rprinte = raw_print_err
233
234
234
235
235 def unicode_std_stream(stream='stdout'):
236 def unicode_std_stream(stream='stdout'):
236 """DEPRECATED, moved to nbconvert.utils.io"""
237 """DEPRECATED, moved to nbconvert.utils.io"""
237 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
238 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
238 from nbconvert.utils.io import unicode_std_stream
239 from nbconvert.utils.io import unicode_std_stream
239 return unicode_std_stream(stream)
240 return unicode_std_stream(stream)
General Comments 0
You need to be logged in to leave comments. Login now