Issue #4947: The write() method of sys.stdout and sys.stderr uses their
encoding and errors attributes instead of using utf-8 in strict mode, to get the same behaviour than the print statement.
This commit is contained in:
parent
7738e4b758
commit
caafd77060
|
@ -619,6 +619,39 @@ class StdoutTests(unittest.TestCase):
|
|||
finally:
|
||||
sys.stdout = save_stdout
|
||||
|
||||
def test_unicode(self):
|
||||
import subprocess
|
||||
|
||||
def get_message(encoding, *code):
|
||||
code = '\n'.join(code)
|
||||
env = os.environ.copy()
|
||||
env['PYTHONIOENCODING'] = encoding
|
||||
process = subprocess.Popen([sys.executable, "-c", code],
|
||||
stdout=subprocess.PIPE, env=env)
|
||||
stdout, stderr = process.communicate()
|
||||
self.assertEqual(process.returncode, 0)
|
||||
return stdout
|
||||
|
||||
def check_message(text, encoding, expected):
|
||||
stdout = get_message(encoding,
|
||||
"import sys",
|
||||
"sys.stdout.write(%r)" % text,
|
||||
"sys.stdout.flush()")
|
||||
self.assertEqual(stdout, expected)
|
||||
|
||||
check_message(u'\u20ac\n', "iso-8859-15", "\xa4\n")
|
||||
check_message(u'\u20ac\n', "utf-16-le", '\xac\x20\n\x00')
|
||||
check_message(u'15\u20ac\n', "iso-8859-1:ignore", "15\n")
|
||||
check_message(u'15\u20ac\n', "iso-8859-1:replace", "15?\n")
|
||||
check_message(u'15\u20ac\n', "iso-8859-1:backslashreplace",
|
||||
"15\\u20ac\n")
|
||||
|
||||
for objtype in ('buffer', 'bytearray'):
|
||||
stdout = get_message('ascii',
|
||||
'import sys',
|
||||
r'sys.stdout.write(%s("\xe9\n"))' % objtype)
|
||||
self.assertEqual(stdout, "\xe9\n")
|
||||
|
||||
|
||||
def test_main():
|
||||
# Historically, these tests have been sloppy about removing TESTFN.
|
||||
|
|
|
@ -12,6 +12,10 @@ What's New in Python 2.7.1?
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #4947: The write() method of sys.stdout and sys.stderr uses their
|
||||
encoding and errors attributes instead of using utf-8 in strict mode, to get
|
||||
the same behaviour than the print statement.
|
||||
|
||||
- Issue #9737: Fix a crash when trying to delete a slice or an item from
|
||||
a memoryview object.
|
||||
|
||||
|
|
|
@ -1735,8 +1735,10 @@ static PyObject *
|
|||
file_write(PyFileObject *f, PyObject *args)
|
||||
{
|
||||
Py_buffer pbuf;
|
||||
char *s;
|
||||
const char *s;
|
||||
Py_ssize_t n, n2;
|
||||
PyObject *encoded = NULL;
|
||||
|
||||
if (f->f_fp == NULL)
|
||||
return err_closed();
|
||||
if (!f->writable)
|
||||
|
@ -1746,14 +1748,41 @@ file_write(PyFileObject *f, PyObject *args)
|
|||
return NULL;
|
||||
s = pbuf.buf;
|
||||
n = pbuf.len;
|
||||
} else
|
||||
if (!PyArg_ParseTuple(args, "t#", &s, &n))
|
||||
}
|
||||
else {
|
||||
const char *encoding, *errors;
|
||||
PyObject *text;
|
||||
if (!PyArg_ParseTuple(args, "O", &text))
|
||||
return NULL;
|
||||
|
||||
if (PyString_Check(text)) {
|
||||
s = PyString_AS_STRING(text);
|
||||
n = PyString_GET_SIZE(text);
|
||||
} else if (PyUnicode_Check(text)) {
|
||||
if (f->f_encoding != Py_None)
|
||||
encoding = PyString_AS_STRING(f->f_encoding);
|
||||
else
|
||||
encoding = PyUnicode_GetDefaultEncoding();
|
||||
if (f->f_errors != Py_None)
|
||||
errors = PyString_AS_STRING(f->f_errors);
|
||||
else
|
||||
errors = "strict";
|
||||
encoded = PyUnicode_AsEncodedString(text, encoding, errors);
|
||||
if (encoded == NULL)
|
||||
return NULL;
|
||||
s = PyString_AS_STRING(encoded);
|
||||
n = PyString_GET_SIZE(encoded);
|
||||
} else {
|
||||
if (PyObject_AsCharBuffer(text, &s, &n))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
f->f_softspace = 0;
|
||||
FILE_BEGIN_ALLOW_THREADS(f)
|
||||
errno = 0;
|
||||
n2 = fwrite(s, 1, n, f->f_fp);
|
||||
FILE_END_ALLOW_THREADS(f)
|
||||
Py_XDECREF(encoded);
|
||||
if (f->f_binary)
|
||||
PyBuffer_Release(&pbuf);
|
||||
if (n2 != n) {
|
||||
|
|
Loading…
Reference in New Issue