[Python-checkins] r84621 - in python/branches/release27-maint: Lib/test/test_file2k.py Misc/NEWS Objects/fileobject.c

victor.stinner python-checkins at python.org
Wed Sep 8 12:51:01 CEST 2010


Author: victor.stinner
Date: Wed Sep  8 12:51:01 2010
New Revision: 84621

Log:
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.


Modified:
   python/branches/release27-maint/Lib/test/test_file2k.py
   python/branches/release27-maint/Misc/NEWS
   python/branches/release27-maint/Objects/fileobject.c

Modified: python/branches/release27-maint/Lib/test/test_file2k.py
==============================================================================
--- python/branches/release27-maint/Lib/test/test_file2k.py	(original)
+++ python/branches/release27-maint/Lib/test/test_file2k.py	Wed Sep  8 12:51:01 2010
@@ -619,6 +619,39 @@
         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.

Modified: python/branches/release27-maint/Misc/NEWS
==============================================================================
--- python/branches/release27-maint/Misc/NEWS	(original)
+++ python/branches/release27-maint/Misc/NEWS	Wed Sep  8 12:51:01 2010
@@ -12,6 +12,10 @@
 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 @@
 - 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

Modified: python/branches/release27-maint/Objects/fileobject.c
==============================================================================
--- python/branches/release27-maint/Objects/fileobject.c	(original)
+++ python/branches/release27-maint/Objects/fileobject.c	Wed Sep  8 12:51:01 2010
@@ -1735,8 +1735,10 @@
 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 @@
             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) {


More information about the Python-checkins mailing list