bpo-26407: Do not mask errors in csv. (GH-20536)

Unexpected errors in calling the __iter__ method are no longer
masked by TypeError in csv.reader(), csv.writer.writerow() and
csv.writer.writerows().
This commit is contained in:
Serhiy Storchaka 2020-06-22 11:21:59 +03:00 committed by GitHub
parent cafe1b6e9d
commit c88239f864
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 9 deletions

View File

@ -14,6 +14,12 @@ from itertools import permutations
from textwrap import dedent
from collections import OrderedDict
class BadIterable:
def __iter__(self):
raise OSError
class Test_Csv(unittest.TestCase):
"""
Test the underlying C csv parser in ways that are not appropriate
@ -40,9 +46,15 @@ class Test_Csv(unittest.TestCase):
def test_reader_arg_valid(self):
self._test_arg_valid(csv.reader, [])
self.assertRaises(OSError, csv.reader, BadIterable())
def test_writer_arg_valid(self):
self._test_arg_valid(csv.writer, StringIO())
class BadWriter:
@property
def write(self):
raise OSError
self.assertRaises(OSError, csv.writer, BadWriter())
def _test_default_attrs(self, ctor, *args):
obj = ctor(*args)
@ -141,6 +153,7 @@ class Test_Csv(unittest.TestCase):
self._write_test([None], '""')
self._write_error_test(csv.Error, [None], quoting = csv.QUOTE_NONE)
# Check that exceptions are passed up the chain
self._write_error_test(OSError, BadIterable())
class BadList:
def __len__(self):
return 10;
@ -230,6 +243,12 @@ class Test_Csv(unittest.TestCase):
fileobj.seek(0)
self.assertEqual(fileobj.read(), 'a\r\n""\r\n')
def test_writerows_errors(self):
with TemporaryFile("w+", newline='') as fileobj:
writer = csv.writer(fileobj)
self.assertRaises(TypeError, writer.writerows, None)
self.assertRaises(OSError, writer.writerows, BadIterable())
@support.cpython_only
def test_writerows_legacy_strings(self):
import _testcapi
@ -334,7 +353,6 @@ class Test_Csv(unittest.TestCase):
def test_roundtrip_quoteed_newlines(self):
with TemporaryFile("w+", newline='') as fileobj:
writer = csv.writer(fileobj)
self.assertRaises(TypeError, writer.writerows, None)
rows = [['a\nb','b'],['c','x\r\nd']]
writer.writerows(rows)
fileobj.seek(0)

View File

@ -0,0 +1,3 @@
Unexpected errors in calling the ``__iter__`` method are no longer masked
by ``TypeError`` in :func:`csv.reader`, :func:`csv.writer.writerow` and
:meth:`csv.writer.writerows`.

View File

@ -956,8 +956,6 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
}
self->input_iter = PyObject_GetIter(iterator);
if (self->input_iter == NULL) {
PyErr_SetString(PyExc_TypeError,
"argument 1 must be an iterator");
Py_DECREF(self);
return NULL;
}
@ -1163,10 +1161,14 @@ csv_writerow(WriterObj *self, PyObject *seq)
PyObject *iter, *field, *line, *result;
iter = PyObject_GetIter(seq);
if (iter == NULL)
return PyErr_Format(_csvstate_global->error_obj,
if (iter == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
PyErr_Format(_csvstate_global->error_obj,
"iterable expected, not %.200s",
Py_TYPE(seq)->tp_name);
}
return NULL;
}
/* Join all fields in internal buffer.
*/
@ -1256,8 +1258,6 @@ csv_writerows(WriterObj *self, PyObject *seqseq)
row_iter = PyObject_GetIter(seqseq);
if (row_iter == NULL) {
PyErr_SetString(PyExc_TypeError,
"writerows() argument must be iterable");
return NULL;
}
while ((row_obj = PyIter_Next(row_iter))) {