summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_print.py35
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/bltinmodule.c92
3 files changed, 106 insertions, 24 deletions
diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py
index 5ed2cc0..394a2f1 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 4870c6a..0347cc3 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 4d7dec1..015e16b 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 == 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)