##// END OF EJS Templates
Add unicode_std_stream function to write UTF-8 to stdout/stderr
Thomas Kluyver -
Show More
@@ -10,15 +10,17 b' IO related utilities.'
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 from __future__ import absolute_import
13
14
14 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
15 # Imports
16 # Imports
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 import codecs
17 import os
19 import os
18 import sys
20 import sys
19 import tempfile
21 import tempfile
20 from .capture import CapturedIO, capture_output
22 from .capture import CapturedIO, capture_output
21 from .py3compat import string_types, input
23 from .py3compat import string_types, input, PY3
22
24
23 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
24 # Code
26 # Code
@@ -227,3 +229,26 b' def raw_print_err(*args, **kw):'
227 # Short aliases for quick debugging, do NOT use these in production code.
229 # Short aliases for quick debugging, do NOT use these in production code.
228 rprint = raw_print
230 rprint = raw_print
229 rprinte = raw_print_err
231 rprinte = raw_print_err
232
233 def unicode_std_stream(stream='stdout'):
234 """Get a wrapper to write unicode to stdout/stderr as UTF-8.
235
236 This ignores environment variables and default encodings, to reliably write
237 unicode to stdout or stderr.
238
239 ::
240
241 unicode_std_stream().write(u'ł@e¶ŧ←')
242 """
243 assert stream in ('stdout', 'stderr')
244 stream = getattr(sys, stream)
245 if PY3:
246 try:
247 stream_b = stream.buffer
248 except AttributeError:
249 # sys.stdout has been replaced - use it directly
250 return stream
251 else:
252 stream_b = stream
253
254 return codecs.getwriter('utf-8')(stream_b)
@@ -12,7 +12,9 b''
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15 from __future__ import absolute_import
15
16
17 import io as stdlib_io
16 import sys
18 import sys
17
19
18 from subprocess import Popen, PIPE
20 from subprocess import Popen, PIPE
@@ -20,7 +22,8 b' import unittest'
20
22
21 import nose.tools as nt
23 import nose.tools as nt
22
24
23 from IPython.utils.io import Tee, capture_output
25 from IPython.testing.decorators import skipif
26 from IPython.utils.io import Tee, capture_output, unicode_std_stream
24 from IPython.utils.py3compat import doctest_refactor_print, PY3
27 from IPython.utils.py3compat import doctest_refactor_print, PY3
25
28
26 if PY3:
29 if PY3:
@@ -88,3 +91,34 b' def test_capture_output():'
88
91
89 nt.assert_equal(io.stdout, 'hi, stdout\n')
92 nt.assert_equal(io.stdout, 'hi, stdout\n')
90 nt.assert_equal(io.stderr, 'hi, stderr\n')
93 nt.assert_equal(io.stderr, 'hi, stderr\n')
94
95 def test_UnicodeStdStream():
96 # Test wrapping a bytes-level stdout
97 if PY3:
98 stdoutb = stdlib_io.BytesIO()
99 stdout = stdlib_io.TextIOWrapper(stdoutb, encoding='ascii')
100 else:
101 stdout = stdoutb = stdlib_io.BytesIO()
102
103 orig_stdout = sys.stdout
104 sys.stdout = stdout
105 try:
106 sample = u"@łe¶ŧ←"
107 unicode_std_stream().write(sample)
108
109 output = stdoutb.getvalue().decode('utf-8')
110 nt.assert_equal(output, sample)
111 assert not stdout.closed
112 finally:
113 sys.stdout = orig_stdout
114
115 @skipif(not PY3, "Not applicable on Python 2")
116 def test_UnicodeStdStream_nowrap():
117 # If we replace stdout with a StringIO, it shouldn't get wrapped.
118 orig_stdout = sys.stdout
119 sys.stdout = StringIO()
120 try:
121 nt.assert_is(unicode_std_stream(), sys.stdout)
122 assert not sys.stdout.closed
123 finally:
124 sys.stdout = orig_stdout No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now