diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -828,8 +828,8 @@ def _translate_newlines(self, data, encoding): - data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n") - return data.decode(encoding) + data = data.decode(encoding) + return data.replace("\r\n", "\n").replace("\r", "\n") def __enter__(self): return self diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -4,6 +4,7 @@ import sys import signal import io +import locale import os import errno import tempfile @@ -635,6 +636,28 @@ (stdout, stderr) = p.communicate("line1\nline3\n") self.assertEqual(p.returncode, 0) + def test_universal_newlines_communicate_encoding_utf16(self): + # Check that universal newlines mode works when the preferred + # encoding is UTF-16. See issue #15595. + old_getpreferredencoding = locale.getpreferredencoding + code = ("import sys; " + r"sys.stdout.buffer.write('a\r\nb'.encode('utf-16'))") + args = [sys.executable, '-c', code] + try: + # Popen() defaults to locale.getpreferredencoding(False). + locale.getpreferredencoding = lambda do_setlocale: 'utf-16' + # We set stdin to be non-None because, as of this writing, + # a different code path is used when the number of pipes is + # zero or one. + popen = subprocess.Popen(args, universal_newlines=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout, stderr = popen.communicate(input='') + finally: + locale.getpreferredencoding = old_getpreferredencoding + + self.assertEquals(stdout, 'a\nb') + def test_no_leaking(self): # Make sure we leak no resources if not mswindows: