Issue #6241: Better type checking for the arguments of io.StringIO.
This commit is contained in:
parent
e671fd206b
commit
d2bb18b281
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue