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