From 5606d555b6e797625be9b0368472a86d8ad5252e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 Jun 2020 01:40:54 -0700 Subject: [PATCH] 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(). (cherry picked from commit c88239f864a27f673c0f0a9e62d2488563f9d081) Co-authored-by: Serhiy Storchaka --- Lib/test/test_csv.py | 20 ++++++++++++++++++- .../2020-05-30-14-19-47.bpo-26407.MjWLO1.rst | 3 +++ Modules/_csv.c | 16 +++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-30-14-19-47.bpo-26407.MjWLO1.rst diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index a16d14019f3..d421be075ca 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -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) diff --git a/Misc/NEWS.d/next/Library/2020-05-30-14-19-47.bpo-26407.MjWLO1.rst b/Misc/NEWS.d/next/Library/2020-05-30-14-19-47.bpo-26407.MjWLO1.rst new file mode 100644 index 00000000000..d0e45cf1b1f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-30-14-19-47.bpo-26407.MjWLO1.rst @@ -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`. diff --git a/Modules/_csv.c b/Modules/_csv.c index 3a52632ccfd..59109b018e7 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -964,8 +964,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; } @@ -1171,10 +1169,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, - "iterable expected, not %.200s", - Py_TYPE(seq)->tp_name); + 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. */ @@ -1264,8 +1266,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))) {