summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/_pyio.py4
-rw-r--r--Lib/test/test_memoryio.py8
-rw-r--r--Modules/_io/stringio.c31
3 files changed, 38 insertions, 5 deletions
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index bbf65bc..5458f99 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -1924,8 +1924,10 @@ class StringIO(TextIOWrapper):
# C version, even under Windows.
if newline is None:
self._writetranslate = False
- if initial_value:
+ if initial_value is not None:
if not isinstance(initial_value, str):
+ raise TypeError("initial_value must be str or None, not {0}"
+ .format(type(initial_value).__name__))
initial_value = str(initial_value)
self.write(initial_value)
self.seek(0)
diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py
index 0b25283..670dab9 100644
--- a/Lib/test/test_memoryio.py
+++ b/Lib/test/test_memoryio.py
@@ -140,6 +140,7 @@ class MemoryTestMixin:
self.assertEqual(memio.getvalue(), buf * 2)
memio.__init__(buf)
self.assertEqual(memio.getvalue(), buf)
+ self.assertRaises(TypeError, memio.__init__, [])
def test_read(self):
buf = self.buftype("1234567890")
@@ -530,6 +531,13 @@ class PyStringIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
memio = self.ioclass("a\r\nb\r\n", newline=None)
self.assertEqual(memio.read(5), "a\nb\n")
+ def test_newline_argument(self):
+ self.assertRaises(TypeError, self.ioclass, newline=b"\n")
+ self.assertRaises(ValueError, self.ioclass, newline="error")
+ # These should not raise an error
+ for newline in (None, "", "\n", "\r", "\r\n"):
+ self.ioclass(newline=newline)
+
class CBytesIOTest(PyBytesIOTest):
ioclass = io.BytesIO
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
index d773723..bfb099c 100644
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -550,22 +550,42 @@ stringio_init(stringio *self, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {"initial_value", "newline", NULL};
PyObject *value = NULL;
+ PyObject *newline_obj = NULL;
char *newline = "\n";
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
- &value, &newline))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:__init__", kwlist,
+ &value, &newline_obj))
return -1;
+ /* Parse the newline argument. This used to be done with the 'z'
+ specifier, however this allowed any object with the buffer interface to
+ be converted. Thus we have to parse it manually since we only want to
+ allow unicode objects or None. */
+ if (newline_obj == Py_None) {
+ newline = NULL;
+ }
+ else if (newline_obj) {
+ if (!PyUnicode_Check(newline_obj)) {
+ PyErr_Format(PyExc_TypeError,
+ "newline must be str or None, not %.200s",
+ Py_TYPE(newline_obj)->tp_name);
+ return -1;
+ }
+ newline = _PyUnicode_AsString(newline_obj);
+ if (newline == NULL)
+ return -1;
+ }
+
if (newline && newline[0] != '\0'
&& !(newline[0] == '\n' && newline[1] == '\0')
&& !(newline[0] == '\r' && newline[1] == '\0')
&& !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
PyErr_Format(PyExc_ValueError,
- "illegal newline value: %s", newline);
+ "illegal newline value: %R", newline_obj);
return -1;
}
if (value && value != Py_None && !PyUnicode_Check(value)) {
- PyErr_Format(PyExc_ValueError,
+ PyErr_Format(PyExc_TypeError,
"initial_value must be str or None, not %.200s",
Py_TYPE(value)->tp_name);
return -1;
@@ -577,6 +597,9 @@ stringio_init(stringio *self, PyObject *args, PyObject *kwds)
Py_CLEAR(self->writenl);
Py_CLEAR(self->decoder);
+ assert((newline != NULL && newline_obj != Py_None) ||
+ (newline == NULL && newline_obj == Py_None));
+
if (newline) {
self->readnl = PyUnicode_FromString(newline);
if (self->readnl == NULL)