self.assertRaises(ValueError, create_invalid, field_name, " ",
skipinitialspace=True)
+ def test_dialect_getattr_non_attribute_error_propagates(self):
+ # gh-145966: non-AttributeError exceptions raised by __getattr__
+ # during dialect attribute lookup must propagate, not be silenced.
+ class BadDialect:
+ def __getattr__(self, name):
+ raise RuntimeError("boom")
+
+ with self.assertRaises(RuntimeError):
+ csv.reader([], dialect=BadDialect())
+
+ with self.assertRaises(RuntimeError):
+ csv.writer(StringIO(), dialect=BadDialect())
+
class TestSniffer(unittest.TestCase):
sample1 = """\
Py_XINCREF(skipinitialspace);
Py_XINCREF(strict);
if (dialect != NULL) {
-#define DIALECT_GETATTR(v, n) \
- do { \
- if (v == NULL) { \
- v = PyObject_GetAttrString(dialect, n); \
- if (v == NULL) \
- PyErr_Clear(); \
- } \
+#define DIALECT_GETATTR(v, n) \
+ do { \
+ if (v == NULL) { \
+ if (PyObject_GetOptionalAttrString(dialect, n, &v) < 0) { \
+ goto err; \
+ } \
+ } \
} while (0)
DIALECT_GETATTR(delimiter, "delimiter");
DIALECT_GETATTR(doublequote, "doublequote");