]> granicus.if.org Git - python/commitdiff
Issue #6241: Better type checking for the arguments of io.StringIO.
authorAlexandre Vassalotti <alexandre@peadrop.com>
Wed, 22 Jul 2009 03:07:33 +0000 (03:07 +0000)
committerAlexandre Vassalotti <alexandre@peadrop.com>
Wed, 22 Jul 2009 03:07:33 +0000 (03:07 +0000)
Lib/_pyio.py
Lib/test/test_memoryio.py
Modules/_io/stringio.c

index bbf65bc0b184076a4f17429562dddfe6ddc43dac..5458f990b7a26ae63e7ae2354cb42a488c3980c0 100644 (file)
@@ -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)
index 0b25283a55ddd36604fcc22ac9b4eb7661611173..670dab9db5c30bb009846b731543f88699a24742 100644 (file)
@@ -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
index d773723a49d602d760e2eb73fa0f6a4e2845364e..bfb099c3f6a200b434de23c91c082d49e09d8e60 100644 (file)
@@ -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)