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:
Victor Stinner 2010-09-08 10:51:01 +00:00
parent 7738e4b758
commit caafd77060
3 changed files with 71 additions and 5 deletions

View File

@ -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.

View File

@ -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.
@ -63,7 +67,7 @@ Library
- Issue #8750: Fixed MutableSet's methods to correctly handle
reflexive operations, namely x -= x and x ^= x.
- Issue #9129: smtpd.py is vulnerable to DoS attacks deriving from missing
- Issue #9129: smtpd.py is vulnerable to DoS attacks deriving from missing
error handling when accepting a new connection.
- Issue #658749: asyncore's connect() method now correctly interprets winsock

View File

@ -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))
return NULL;
}
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) {