https://github.com/python/cpython/commit/dc24b8a6d42231ebc821baeda662e1168b52aa26 commit: dc24b8a6d42231ebc821baeda662e1168b52aa26 branch: main author: Ramin Farajpour Cami <[email protected]> committer: encukou <[email protected]> date: 2026-03-17T16:08:53+01:00 summary:
gh-145966: Fix _csv DIALECT_GETATTR macro silently masking non-AttributeError exceptions (GH-145974) The DIALECT_GETATTR macro in dialect_new() unconditionally called PyErr_Clear() when PyObject_GetAttrString() failed, which suppressed all exceptions including MemoryError, KeyboardInterrupt, and RuntimeError. Now only AttributeError is cleared; other exceptions propagate via the existing error handling path. Co-authored-by: Bénédikt Tran <[email protected]> files: A Misc/NEWS.d/next/Library/2026-03-15-00-00-00.gh-issue-145966.tCI0uD4I.rst M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index df79840088abc3..2e5b72742c3f41 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -1280,6 +1280,19 @@ class mydialect(csv.Dialect): 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 = """\ diff --git a/Misc/NEWS.d/next/Library/2026-03-15-00-00-00.gh-issue-145966.tCI0uD4I.rst b/Misc/NEWS.d/next/Library/2026-03-15-00-00-00.gh-issue-145966.tCI0uD4I.rst new file mode 100644 index 00000000000000..c0d4907ada073c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-15-00-00-00.gh-issue-145966.tCI0uD4I.rst @@ -0,0 +1,2 @@ +Non-:exc:`AttributeError` exceptions raised during dialect attribute lookup +in :mod:`csv` are no longer silently suppressed. diff --git a/Modules/_csv.c b/Modules/_csv.c index 1f41976e95fdb1..c48f44c0f07867 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -497,13 +497,13 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) 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"); _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
