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