From 7d6b01417f5e97e122c4fe2237ebd24ea3437d52 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Thu, 2 Jul 2009 18:19:47 +0000 Subject: [PATCH] Merged revisions 73776 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r73776 | benjamin.peterson | 2009-07-02 13:16:45 -0500 (Thu, 02 Jul 2009) | 1 line when print() gets unicode arguments, sep and end should be unicode by default #4618 ........ --- Lib/test/test_print.py | 35 +++++++++++++--- Misc/NEWS | 3 ++ Python/bltinmodule.c | 94 +++++++++++++++++++++++++++++++++--------- 3 files changed, 107 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index 5ed2cc02071..394a2f19b6d 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -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) diff --git a/Misc/NEWS b/Misc/NEWS index 4870c6a2237..0347cc315ea 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,9 @@ Core and Builtins - Issue #4547: When debugging a very large function, it was not always possible to update the lineno attribute of the current frame. +- 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. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 4d7dec1c3f1..015e16bbb87 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -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 && 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 (sep == Py_None) { + sep = NULL; } - 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; + 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 (!use_unicode) { + for (i = 0; i < PyTuple_Size(args); i++) { + if (PyUnicode_Check(PyTuple_GET_ITEM(args, i))) { + use_unicode = 1; + break; + } + } + } + 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)