]> granicus.if.org Git - python/commitdiff
when print() gets unicode arguments, sep and end should be unicode by default #4618
authorBenjamin Peterson <benjamin@python.org>
Thu, 2 Jul 2009 18:16:45 +0000 (18:16 +0000)
committerBenjamin Peterson <benjamin@python.org>
Thu, 2 Jul 2009 18:16:45 +0000 (18:16 +0000)
Lib/test/test_print.py
Misc/NEWS
Python/bltinmodule.c

index 5ed2cc02071df6ff0f45bb4a10d87f6b0bb48b7e..394a2f19b6d3abd1ce495e46923e0db3e49e42bc 100644 (file)
@@ -9,12 +9,7 @@ import unittest
 from test import test_support
 
 import sys
-if sys.version_info[0] == 3:
-    # 3.x
-    from io import StringIO
-else:
-    # 2.x
-    from StringIO import StringIO
+from StringIO import StringIO
 
 NotDefined = object()
 
@@ -112,6 +107,34 @@ class TestPrint(unittest.TestCase):
         self.assertRaises(TypeError, print, '', end=3)
         self.assertRaises(AttributeError, print, '', file='')
 
+    def test_mixed_args(self):
+        # If an unicode arg is passed, sep and end should be unicode, too.
+        class Recorder(object):
+
+            def __init__(self, must_be_unicode):
+                self.buf = []
+                self.force_unicode = must_be_unicode
+
+            def write(self, what):
+                if self.force_unicode and not isinstance(what, unicode):
+                    raise AssertionError("{0!r} is not unicode".format(what))
+                self.buf.append(what)
+
+        buf = Recorder(True)
+        print(u'hi', file=buf)
+        self.assertEqual(u''.join(buf.buf), 'hi\n')
+        del buf.buf[:]
+        print(u'hi', u'nothing', file=buf)
+        self.assertEqual(u''.join(buf.buf), 'hi nothing\n')
+        buf = Recorder(False)
+        print('hi', 'bye', end=u'\n', file=buf)
+        self.assertTrue(isinstance(buf.buf[1], unicode))
+        self.assertTrue(isinstance(buf.buf[3], unicode))
+        del buf.buf[:]
+        print(sep=u'x', file=buf)
+        self.assertTrue(isinstance(buf.buf[-1], unicode))
+
+
 def test_main():
     test_support.run_unittest(TestPrint)
 
index b5c716a0d1c3be31b562dc8eaae70b964be87e17..88739ffb824df2f5faa0b080b6603575cdef1103 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 1
 Core and Builtins
 -----------------
 
+- Issue #4618: When unicode arguments are passed to print(), the default
+  separator and end should be unicode also.
+
 - Issue #6119: Fixed a incorrect Py3k warning about order comparisons of builtin
   functions and methods.
 
index c1e934edadd496a1bf2305e739cf80ad2c8a83da..1f25d5d2087a301739b5b38fd50020742e550592 100644 (file)
@@ -1556,14 +1556,40 @@ static PyObject *
 builtin_print(PyObject *self, PyObject *args, PyObject *kwds)
 {
        static char *kwlist[] = {"sep", "end", "file", 0};
-       static PyObject *dummy_args;
+       static PyObject *dummy_args = NULL;
+       static PyObject *unicode_newline = NULL, *unicode_space = NULL;
+       static PyObject *str_newline = NULL, *str_space = NULL;
+       PyObject *newline, *space;
        PyObject *sep = NULL, *end = NULL, *file = NULL;
-       int i, err;
+       int i, err, use_unicode = 0;
 
        if (dummy_args == NULL) {
                if (!(dummy_args = PyTuple_New(0)))
                        return NULL;
        }
+       if (str_newline == NULL) {
+               str_newline = PyString_FromString("\n");
+               if (str_newline == NULL)
+                       return NULL;
+               str_space = PyString_FromString(" ");
+               if (str_space == NULL) {
+                       Py_CLEAR(str_newline);
+                       return NULL;
+               }
+               unicode_newline = PyUnicode_FromString("\n");
+               if (unicode_newline == NULL) {
+                       Py_CLEAR(str_newline);
+                       Py_CLEAR(str_space);
+                       return NULL;
+               }
+               unicode_space = PyUnicode_FromString(" ");
+               if (unicode_space == NULL) {
+                       Py_CLEAR(str_newline);
+                       Py_CLEAR(str_space);
+                       Py_CLEAR(unicode_space);
+                       return NULL;
+               }
+       }
        if (!PyArg_ParseTupleAndKeywords(dummy_args, kwds, "|OOO:print",
                                         kwlist, &sep, &end, &file))
                return NULL;
@@ -1573,26 +1599,56 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds)
                if (file == Py_None)
                        Py_RETURN_NONE;
        }
+       if (sep == Py_None) {
+               sep = NULL;
+       }
+       else if (sep) {
+               if (PyUnicode_Check(sep)) {
+                       use_unicode = 1;
+               }
+               else if (!PyString_Check(sep)) {
+                       PyErr_Format(PyExc_TypeError,
+                                    "sep must be None, str or unicode, not %.200s",
+                                    sep->ob_type->tp_name);
+                       return NULL;
+               }
+       }
+       if (end == Py_None)
+               end = NULL;
+       else if (end) {
+               if (PyUnicode_Check(end)) {
+                       use_unicode = 1;
+               }
+               else if (!PyString_Check(end)) {
+                       PyErr_Format(PyExc_TypeError,
+                                    "end must be None, str or unicode, not %.200s",
+                                    end->ob_type->tp_name);
+                       return NULL;
+               }
+       }
 
-       if (sep && sep != Py_None && !PyString_Check(sep) &&
-            !PyUnicode_Check(sep)) {
-               PyErr_Format(PyExc_TypeError,
-                            "sep must be None, str or unicode, not %.200s",
-                            sep->ob_type->tp_name);
-               return NULL;
+       if (!use_unicode) {
+               for (i = 0; i < PyTuple_Size(args); i++) {
+                       if (PyUnicode_Check(PyTuple_GET_ITEM(args, i))) {
+                               use_unicode = 1;
+                               break;
+                       }
+               }
        }
-       if (end && end != Py_None && !PyString_Check(end) &&
-           !PyUnicode_Check(end)) {
-               PyErr_Format(PyExc_TypeError,
-                            "end must be None, str or unicode, not %.200s",
-                            end->ob_type->tp_name);
-               return NULL;
+       if (use_unicode) {
+               newline = unicode_newline;
+               space = unicode_space;
+       }
+       else {
+               newline = str_newline;
+               space = str_space;
        }
 
        for (i = 0; i < PyTuple_Size(args); i++) {
                if (i > 0) {
-                       if (sep == NULL || sep == Py_None)
-                               err = PyFile_WriteString(" ", file);
+                       if (sep == NULL)
+                               err = PyFile_WriteObject(space, file,
+                                                        Py_PRINT_RAW);
                        else
                                err = PyFile_WriteObject(sep, file,
                                                         Py_PRINT_RAW);
@@ -1605,8 +1661,8 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds)
                        return NULL;
        }
 
-       if (end == NULL || end == Py_None)
-               err = PyFile_WriteString("\n", file);
+       if (end == NULL)
+               err = PyFile_WriteObject(newline, file, Py_PRINT_RAW);
        else
                err = PyFile_WriteObject(end, file, Py_PRINT_RAW);
        if (err)