]> granicus.if.org Git - python/commitdiff
bpo-34421: Improve distutils logging for non-ASCII strings. (GH-9126)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 23 Sep 2018 06:12:59 +0000 (09:12 +0300)
committerGitHub <noreply@github.com>
Sun, 23 Sep 2018 06:12:59 +0000 (09:12 +0300)
Use "backslashreplace" instead of "unicode-escape".  It is not
implementation depended and escapes only non-encodable characters.

Also simplify the code.

Lib/distutils/log.py
Lib/distutils/tests/test_log.py

index 3a6602bc8b8ef6c10954bcdc17b064c6daa51908..8ef6b28ea2ec097ae6ab5d9ac9b2e0d3fc8f4809 100644 (file)
@@ -27,14 +27,13 @@ class Log:
                 stream = sys.stderr
             else:
                 stream = sys.stdout
-            if stream.errors == 'strict':
+            try:
+                stream.write('%s\n' % msg)
+            except UnicodeEncodeError:
                 # emulate backslashreplace error handler
                 encoding = stream.encoding
                 msg = msg.encode(encoding, "backslashreplace").decode(encoding)
-            try:
                 stream.write('%s\n' % msg)
-            except UnicodeEncodeError:
-                stream.write('%s\n' % msg.encode('unicode-escape').decode('ascii'))
             stream.flush()
 
     def log(self, level, msg, *args):
index 0c2ad7a4268d49ab958dff5e312df800f9e8605d..22c26246ca9d8242611c74147f5961f05deb0f39 100644 (file)
@@ -3,33 +3,39 @@
 import sys
 import unittest
 from tempfile import NamedTemporaryFile
-from test.support import run_unittest
+from test.support import swap_attr, run_unittest
 
 from distutils import log
 
 class TestLog(unittest.TestCase):
     def test_non_ascii(self):
-        # Issue #8663: test that non-ASCII text is escaped with
-        # backslashreplace error handler (stream use ASCII encoding and strict
-        # error handler)
-        old_stdout = sys.stdout
-        old_stderr = sys.stderr
-        old_threshold = log.set_threshold(log.DEBUG)
-        try:
-            with NamedTemporaryFile(mode="w+", encoding='ascii') as stdout, \
-                 NamedTemporaryFile(mode="w+", encoding='ascii') as stderr:
-                sys.stdout = stdout
-                sys.stderr = stderr
-                log.debug("debug:\xe9")
-                log.fatal("fatal:\xe9")
+        # Issues #8663, #34421: test that non-encodable text is escaped with
+        # backslashreplace error handler and encodable non-ASCII text is
+        # output as is.
+        for errors in ('strict', 'backslashreplace', 'surrogateescape',
+                       'replace', 'ignore'):
+            with self.subTest(errors=errors), \
+                 NamedTemporaryFile("w+", encoding='cp437', errors=errors) as stdout, \
+                 NamedTemporaryFile("w+", encoding='cp437', errors=errors) as stderr:
+                old_threshold = log.set_threshold(log.DEBUG)
+                try:
+                    with swap_attr(sys, 'stdout', stdout), \
+                         swap_attr(sys, 'stderr', stderr):
+                        log.debug('Dεbug\tMėssãge')
+                        log.fatal('Fαtal\tÈrrōr')
+                finally:
+                    log.set_threshold(old_threshold)
+
                 stdout.seek(0)
-                self.assertEqual(stdout.read().rstrip(), "debug:\\xe9")
+                self.assertEqual(stdout.read().rstrip(),
+                        'Dεbug\tM?ss?ge' if errors == 'replace' else
+                        'Dεbug\tMssge' if errors == 'ignore' else
+                        'Dεbug\tM\\u0117ss\\xe3ge')
                 stderr.seek(0)
-                self.assertEqual(stderr.read().rstrip(), "fatal:\\xe9")
-        finally:
-            log.set_threshold(old_threshold)
-            sys.stdout = old_stdout
-            sys.stderr = old_stderr
+                self.assertEqual(stderr.read().rstrip(),
+                        'Fαtal\t?rr?r' if errors == 'replace' else
+                        'Fαtal\trrr' if errors == 'ignore' else
+                        'Fαtal\t\\xc8rr\\u014dr')
 
 def test_suite():
     return unittest.makeSuite(TestLog)