##// END OF EJS Templates
Remove opening/at-exit closing of devnull....
Matthias Bussonnier -
Show More
@@ -1,156 +1,151 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 from pathlib import Path
15 from pathlib import Path
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
20
21 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
22 devnull = open(os.devnull, "w", encoding="utf-8")
23 atexit.register(devnull.close)
24
25
26 class Tee(object):
21 class Tee(object):
27 """A class to duplicate an output stream to stdout/err.
22 """A class to duplicate an output stream to stdout/err.
28
23
29 This works in a manner very similar to the Unix 'tee' command.
24 This works in a manner very similar to the Unix 'tee' command.
30
25
31 When the object is closed or deleted, it closes the original file given to
26 When the object is closed or deleted, it closes the original file given to
32 it for duplication.
27 it for duplication.
33 """
28 """
34 # Inspired by:
29 # Inspired by:
35 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
30 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
36
31
37 def __init__(self, file_or_name, mode="w", channel='stdout'):
32 def __init__(self, file_or_name, mode="w", channel='stdout'):
38 """Construct a new Tee object.
33 """Construct a new Tee object.
39
34
40 Parameters
35 Parameters
41 ----------
36 ----------
42 file_or_name : filename or open filehandle (writable)
37 file_or_name : filename or open filehandle (writable)
43 File that will be duplicated
38 File that will be duplicated
44 mode : optional, valid mode for open().
39 mode : optional, valid mode for open().
45 If a filename was give, open with this mode.
40 If a filename was give, open with this mode.
46 channel : str, one of ['stdout', 'stderr']
41 channel : str, one of ['stdout', 'stderr']
47 """
42 """
48 if channel not in ['stdout', 'stderr']:
43 if channel not in ['stdout', 'stderr']:
49 raise ValueError('Invalid channel spec %s' % channel)
44 raise ValueError('Invalid channel spec %s' % channel)
50
45
51 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
46 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
52 self.file = file_or_name
47 self.file = file_or_name
53 else:
48 else:
54 encoding = None if "b" in mode else "utf-8"
49 encoding = None if "b" in mode else "utf-8"
55 self.file = open(file_or_name, mode, encoding=encoding)
50 self.file = open(file_or_name, mode, encoding=encoding)
56 self.channel = channel
51 self.channel = channel
57 self.ostream = getattr(sys, channel)
52 self.ostream = getattr(sys, channel)
58 setattr(sys, channel, self)
53 setattr(sys, channel, self)
59 self._closed = False
54 self._closed = False
60
55
61 def close(self):
56 def close(self):
62 """Close the file and restore the channel."""
57 """Close the file and restore the channel."""
63 self.flush()
58 self.flush()
64 setattr(sys, self.channel, self.ostream)
59 setattr(sys, self.channel, self.ostream)
65 self.file.close()
60 self.file.close()
66 self._closed = True
61 self._closed = True
67
62
68 def write(self, data):
63 def write(self, data):
69 """Write data to both channels."""
64 """Write data to both channels."""
70 self.file.write(data)
65 self.file.write(data)
71 self.ostream.write(data)
66 self.ostream.write(data)
72 self.ostream.flush()
67 self.ostream.flush()
73
68
74 def flush(self):
69 def flush(self):
75 """Flush both channels."""
70 """Flush both channels."""
76 self.file.flush()
71 self.file.flush()
77 self.ostream.flush()
72 self.ostream.flush()
78
73
79 def __del__(self):
74 def __del__(self):
80 if not self._closed:
75 if not self._closed:
81 self.close()
76 self.close()
82
77
83
78
84 def ask_yes_no(prompt, default=None, interrupt=None):
79 def ask_yes_no(prompt, default=None, interrupt=None):
85 """Asks a question and returns a boolean (y/n) answer.
80 """Asks a question and returns a boolean (y/n) answer.
86
81
87 If default is given (one of 'y','n'), it is used if the user input is
82 If default is given (one of 'y','n'), it is used if the user input is
88 empty. If interrupt is given (one of 'y','n'), it is used if the user
83 empty. If interrupt is given (one of 'y','n'), it is used if the user
89 presses Ctrl-C. Otherwise the question is repeated until an answer is
84 presses Ctrl-C. Otherwise the question is repeated until an answer is
90 given.
85 given.
91
86
92 An EOF is treated as the default answer. If there is no default, an
87 An EOF is treated as the default answer. If there is no default, an
93 exception is raised to prevent infinite loops.
88 exception is raised to prevent infinite loops.
94
89
95 Valid answers are: y/yes/n/no (match is not case sensitive)."""
90 Valid answers are: y/yes/n/no (match is not case sensitive)."""
96
91
97 answers = {'y':True,'n':False,'yes':True,'no':False}
92 answers = {'y':True,'n':False,'yes':True,'no':False}
98 ans = None
93 ans = None
99 while ans not in answers.keys():
94 while ans not in answers.keys():
100 try:
95 try:
101 ans = input(prompt+' ').lower()
96 ans = input(prompt+' ').lower()
102 if not ans: # response was an empty string
97 if not ans: # response was an empty string
103 ans = default
98 ans = default
104 except KeyboardInterrupt:
99 except KeyboardInterrupt:
105 if interrupt:
100 if interrupt:
106 ans = interrupt
101 ans = interrupt
107 print("\r")
102 print("\r")
108 except EOFError:
103 except EOFError:
109 if default in answers.keys():
104 if default in answers.keys():
110 ans = default
105 ans = default
111 print()
106 print()
112 else:
107 else:
113 raise
108 raise
114
109
115 return answers[ans]
110 return answers[ans]
116
111
117
112
118 def temp_pyfile(src, ext='.py'):
113 def temp_pyfile(src, ext='.py'):
119 """Make a temporary python file, return filename and filehandle.
114 """Make a temporary python file, return filename and filehandle.
120
115
121 Parameters
116 Parameters
122 ----------
117 ----------
123 src : string or list of strings (no need for ending newlines if list)
118 src : string or list of strings (no need for ending newlines if list)
124 Source code to be written to the file.
119 Source code to be written to the file.
125 ext : optional, string
120 ext : optional, string
126 Extension for the generated file.
121 Extension for the generated file.
127
122
128 Returns
123 Returns
129 -------
124 -------
130 (filename, open filehandle)
125 (filename, open filehandle)
131 It is the caller's responsibility to close the open file and unlink it.
126 It is the caller's responsibility to close the open file and unlink it.
132 """
127 """
133 fname = tempfile.mkstemp(ext)[1]
128 fname = tempfile.mkstemp(ext)[1]
134 with open(Path(fname), "w", encoding="utf-8") as f:
129 with open(Path(fname), "w", encoding="utf-8") as f:
135 f.write(src)
130 f.write(src)
136 f.flush()
131 f.flush()
137 return fname
132 return fname
138
133
139
134
140 @undoc
135 @undoc
141 def raw_print(*args, **kw):
136 def raw_print(*args, **kw):
142 """DEPRECATED: Raw print to sys.__stdout__, otherwise identical interface to print()."""
137 """DEPRECATED: Raw print to sys.__stdout__, otherwise identical interface to print()."""
143 warn("IPython.utils.io.raw_print has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
138 warn("IPython.utils.io.raw_print has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
144
139
145 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
140 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
146 file=sys.__stdout__)
141 file=sys.__stdout__)
147 sys.__stdout__.flush()
142 sys.__stdout__.flush()
148
143
149 @undoc
144 @undoc
150 def raw_print_err(*args, **kw):
145 def raw_print_err(*args, **kw):
151 """DEPRECATED: Raw print to sys.__stderr__, otherwise identical interface to print()."""
146 """DEPRECATED: Raw print to sys.__stderr__, otherwise identical interface to print()."""
152 warn("IPython.utils.io.raw_print_err has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
147 warn("IPython.utils.io.raw_print_err has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
153
148
154 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
149 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
155 file=sys.__stderr__)
150 file=sys.__stderr__)
156 sys.__stderr__.flush()
151 sys.__stderr__.flush()
General Comments 0
You need to be logged in to leave comments. Login now