[3.8] bpo-26407: Do not mask errors in csv. (GH-20536) (GH-24021)
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 c88239f864
)
This commit is contained in:
parent
b863607d30
commit
6dffa67b98
|
@ -14,6 +14,12 @@ from itertools import permutations
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
|
||||||
|
class BadIterable:
|
||||||
|
def __iter__(self):
|
||||||
|
raise OSError
|
||||||
|
|
||||||
|
|
||||||
class Test_Csv(unittest.TestCase):
|
class Test_Csv(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Test the underlying C csv parser in ways that are not appropriate
|
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):
|
def test_reader_arg_valid(self):
|
||||||
self._test_arg_valid(csv.reader, [])
|
self._test_arg_valid(csv.reader, [])
|
||||||
|
self.assertRaises(OSError, csv.reader, BadIterable())
|
||||||
|
|
||||||
def test_writer_arg_valid(self):
|
def test_writer_arg_valid(self):
|
||||||
self._test_arg_valid(csv.writer, StringIO())
|
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):
|
def _test_default_attrs(self, ctor, *args):
|
||||||
obj = ctor(*args)
|
obj = ctor(*args)
|
||||||
|
@ -141,6 +153,7 @@ class Test_Csv(unittest.TestCase):
|
||||||
self._write_test([None], '""')
|
self._write_test([None], '""')
|
||||||
self._write_error_test(csv.Error, [None], quoting = csv.QUOTE_NONE)
|
self._write_error_test(csv.Error, [None], quoting = csv.QUOTE_NONE)
|
||||||
# Check that exceptions are passed up the chain
|
# Check that exceptions are passed up the chain
|
||||||
|
self._write_error_test(OSError, BadIterable())
|
||||||
class BadList:
|
class BadList:
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return 10;
|
return 10;
|
||||||
|
@ -230,6 +243,12 @@ class Test_Csv(unittest.TestCase):
|
||||||
fileobj.seek(0)
|
fileobj.seek(0)
|
||||||
self.assertEqual(fileobj.read(), 'a\r\n""\r\n')
|
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
|
@support.cpython_only
|
||||||
def test_writerows_legacy_strings(self):
|
def test_writerows_legacy_strings(self):
|
||||||
import _testcapi
|
import _testcapi
|
||||||
|
@ -334,7 +353,6 @@ class Test_Csv(unittest.TestCase):
|
||||||
def test_roundtrip_quoteed_newlines(self):
|
def test_roundtrip_quoteed_newlines(self):
|
||||||
with TemporaryFile("w+", newline='') as fileobj:
|
with TemporaryFile("w+", newline='') as fileobj:
|
||||||
writer = csv.writer(fileobj)
|
writer = csv.writer(fileobj)
|
||||||
self.assertRaises(TypeError, writer.writerows, None)
|
|
||||||
rows = [['a\nb','b'],['c','x\r\nd']]
|
rows = [['a\nb','b'],['c','x\r\nd']]
|
||||||
writer.writerows(rows)
|
writer.writerows(rows)
|
||||||
fileobj.seek(0)
|
fileobj.seek(0)
|
||||||
|
|
|
@ -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`.
|
|
@ -958,8 +958,6 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
|
||||||
}
|
}
|
||||||
self->input_iter = PyObject_GetIter(iterator);
|
self->input_iter = PyObject_GetIter(iterator);
|
||||||
if (self->input_iter == NULL) {
|
if (self->input_iter == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"argument 1 must be an iterator");
|
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1165,10 +1163,14 @@ csv_writerow(WriterObj *self, PyObject *seq)
|
||||||
PyObject *iter, *field, *line, *result;
|
PyObject *iter, *field, *line, *result;
|
||||||
|
|
||||||
iter = PyObject_GetIter(seq);
|
iter = PyObject_GetIter(seq);
|
||||||
if (iter == NULL)
|
if (iter == NULL) {
|
||||||
return PyErr_Format(_csvstate_global->error_obj,
|
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||||
"iterable expected, not %.200s",
|
PyErr_Format(_csvstate_global->error_obj,
|
||||||
seq->ob_type->tp_name);
|
"iterable expected, not %.200s",
|
||||||
|
Py_TYPE(seq)->tp_name);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Join all fields in internal buffer.
|
/* Join all fields in internal buffer.
|
||||||
*/
|
*/
|
||||||
|
@ -1258,8 +1260,6 @@ csv_writerows(WriterObj *self, PyObject *seqseq)
|
||||||
|
|
||||||
row_iter = PyObject_GetIter(seqseq);
|
row_iter = PyObject_GetIter(seqseq);
|
||||||
if (row_iter == NULL) {
|
if (row_iter == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"writerows() argument must be iterable");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
while ((row_obj = PyIter_Next(row_iter))) {
|
while ((row_obj = PyIter_Next(row_iter))) {
|
||||||
|
|
Loading…
Reference in New Issue