From f93b57848ef4bd6f1f6292bf9a0ebbd528e7b5f8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 23 Jan 2026 06:43:32 -0800 Subject: [PATCH 1/2] gh-144169: Fix three crashes in AST objects with non-str kwargs --- Lib/test/test_ast/test_ast.py | 26 +++++++++++++++++++ ...-01-23-06-43-21.gh-issue-144169.LFy9yi.rst | 2 ++ Parser/asdl_c.py | 6 ++--- Python/Python-ast.c | 6 ++--- 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-23-06-43-21.gh-issue-144169.LFy9yi.rst diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 3917407fb37d9e..7a78aa7466222e 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -1443,6 +1443,12 @@ def test_replace_reject_unknown_instance_fields(self): self.assertIs(node.ctx, context) self.assertRaises(AttributeError, getattr, node, 'unknown') + def test_replace_non_str_kwarg(self): + node = ast.Name(id="x") + with self.assertRaisesRegex(TypeError, "got an unexpected keyword argument tp_name, key); res = -1; goto cleanup; @@ -965,7 +965,7 @@ def visitModule(self, mod): else if (contains == 0) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "%.400s.__init__ got an unexpected keyword argument '%U'. " + "%.400s.__init__ got an unexpected keyword argument %R. " "Support for arbitrary keyword arguments is deprecated " "and will be removed in Python 3.15.", Py_TYPE(self)->tp_name, key @@ -1207,7 +1207,7 @@ def visitModule(self, mod): if (rc == 0) { PyErr_Format(PyExc_TypeError, "%.400s.__replace__ got an unexpected keyword " - "argument '%U'.", Py_TYPE(self)->tp_name, key); + "argument %R.", Py_TYPE(self)->tp_name, key); Py_DECREF(expecting); return -1; } diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 79608dee9bfac2..1cc88dc179e120 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5226,7 +5226,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) } if (p == 0) { PyErr_Format(PyExc_TypeError, - "%.400s got multiple values for argument '%U'", + "%.400s got multiple values for argument %R", Py_TYPE(self)->tp_name, key); res = -1; goto cleanup; @@ -5249,7 +5249,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) else if (contains == 0) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "%.400s.__init__ got an unexpected keyword argument '%U'. " + "%.400s.__init__ got an unexpected keyword argument %R. " "Support for arbitrary keyword arguments is deprecated " "and will be removed in Python 3.15.", Py_TYPE(self)->tp_name, key @@ -5491,7 +5491,7 @@ ast_type_replace_check(PyObject *self, if (rc == 0) { PyErr_Format(PyExc_TypeError, "%.400s.__replace__ got an unexpected keyword " - "argument '%U'.", Py_TYPE(self)->tp_name, key); + "argument %R.", Py_TYPE(self)->tp_name, key); Py_DECREF(expecting); return -1; } From ae7668b2fd9e3fd7ccb8bb0ec75a6fea4e577a69 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 23 Jan 2026 20:06:18 -0800 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Victor Stinner --- Lib/test/test_ast/test_ast.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 7a78aa7466222e..c5f42cb7888c08 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -1445,7 +1445,8 @@ def test_replace_reject_unknown_instance_fields(self): def test_replace_non_str_kwarg(self): node = ast.Name(id="x") - with self.assertRaisesRegex(TypeError, "got an unexpected keyword argument