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.
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.
- 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
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)
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) {