Skip to content

Commit c88239f

Browse files
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().
1 parent cafe1b6 commit c88239f

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

Lib/test/test_csv.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
from textwrap import dedent
1515
from collections import OrderedDict
1616

17+
18+
class BadIterable:
19+
def __iter__(self):
20+
raise OSError
21+
22+
1723
class Test_Csv(unittest.TestCase):
1824
"""
1925
Test the underlying C csv parser in ways that are not appropriate
@@ -40,9 +46,15 @@ def _test_arg_valid(self, ctor, arg):
4046

4147
def test_reader_arg_valid(self):
4248
self._test_arg_valid(csv.reader, [])
49+
self.assertRaises(OSError, csv.reader, BadIterable())
4350

4451
def test_writer_arg_valid(self):
4552
self._test_arg_valid(csv.writer, StringIO())
53+
class BadWriter:
54+
@property
55+
def write(self):
56+
raise OSError
57+
self.assertRaises(OSError, csv.writer, BadWriter())
4658

4759
def _test_default_attrs(self, ctor, *args):
4860
obj = ctor(*args)
@@ -141,6 +153,7 @@ def test_write_arg_valid(self):
141153
self._write_test([None], '""')
142154
self._write_error_test(csv.Error, [None], quoting = csv.QUOTE_NONE)
143155
# Check that exceptions are passed up the chain
156+
self._write_error_test(OSError, BadIterable())
144157
class BadList:
145158
def __len__(self):
146159
return 10;
@@ -230,6 +243,12 @@ def test_writerows_with_none(self):
230243
fileobj.seek(0)
231244
self.assertEqual(fileobj.read(), 'a\r\n""\r\n')
232245

246+
def test_writerows_errors(self):
247+
with TemporaryFile("w+", newline='') as fileobj:
248+
writer = csv.writer(fileobj)
249+
self.assertRaises(TypeError, writer.writerows, None)
250+
self.assertRaises(OSError, writer.writerows, BadIterable())
251+
233252
@support.cpython_only
234253
def test_writerows_legacy_strings(self):
235254
import _testcapi
@@ -334,7 +353,6 @@ def test_read_linenum(self):
334353
def test_roundtrip_quoteed_newlines(self):
335354
with TemporaryFile("w+", newline='') as fileobj:
336355
writer = csv.writer(fileobj)
337-
self.assertRaises(TypeError, writer.writerows, None)
338356
rows = [['a\nb','b'],['c','x\r\nd']]
339357
writer.writerows(rows)
340358
fileobj.seek(0)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Unexpected errors in calling the ``__iter__`` method are no longer masked
2+
by ``TypeError`` in :func:`csv.reader`, :func:`csv.writer.writerow` and
3+
:meth:`csv.writer.writerows`.

Modules/_csv.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -956,8 +956,6 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
956956
}
957957
self->input_iter = PyObject_GetIter(iterator);
958958
if (self->input_iter == NULL) {
959-
PyErr_SetString(PyExc_TypeError,
960-
"argument 1 must be an iterator");
961959
Py_DECREF(self);
962960
return NULL;
963961
}
@@ -1163,10 +1161,14 @@ csv_writerow(WriterObj *self, PyObject *seq)
11631161
PyObject *iter, *field, *line, *result;
11641162

11651163
iter = PyObject_GetIter(seq);
1166-
if (iter == NULL)
1167-
return PyErr_Format(_csvstate_global->error_obj,
1168-
"iterable expected, not %.200s",
1169-
Py_TYPE(seq)->tp_name);
1164+
if (iter == NULL) {
1165+
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
1166+
PyErr_Format(_csvstate_global->error_obj,
1167+
"iterable expected, not %.200s",
1168+
Py_TYPE(seq)->tp_name);
1169+
}
1170+
return NULL;
1171+
}
11701172

11711173
/* Join all fields in internal buffer.
11721174
*/
@@ -1256,8 +1258,6 @@ csv_writerows(WriterObj *self, PyObject *seqseq)
12561258

12571259
row_iter = PyObject_GetIter(seqseq);
12581260
if (row_iter == NULL) {
1259-
PyErr_SetString(PyExc_TypeError,
1260-
"writerows() argument must be iterable");
12611261
return NULL;
12621262
}
12631263
while ((row_obj = PyIter_Next(row_iter))) {

0 commit comments

Comments
 (0)