]> granicus.if.org Git - python/commitdiff
Issue #4947: The write() method of sys.stdout and sys.stderr uses their
authorVictor Stinner <victor.stinner@haypocalc.com>
Wed, 8 Sep 2010 10:51:01 +0000 (10:51 +0000)
committerVictor Stinner <victor.stinner@haypocalc.com>
Wed, 8 Sep 2010 10:51:01 +0000 (10:51 +0000)
encoding and errors attributes instead of using utf-8 in strict mode, to get
the same behaviour than the print statement.

Lib/test/test_file2k.py
Misc/NEWS
Objects/fileobject.c

index da2ab6745099d7a2965464905153ea0c6a7f5926..7b9f9de61c913c32bb1038f939b5cb831ff48dcf 100644 (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.
index 16304995e2b0043dc2e873b1fb4f1bac3746b74b..9d7ec181468a363804bd1ffcf4dcda3a3021d99d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
index d83c054cf3e0ebc9bf6163ff8820cba1e6b07e93..b7de6a10cd7a6f4add3cf84b2a71e06121cc2c04 100644 (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) {