8000 gh-121332: Make AST node constructor check _attributes instead of har… · python/cpython@58e8cf2 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 58e8cf2

Browse files
gh-121332: Make AST node constructor check _attributes instead of hardcoding attributes (#121334)
1 parent 44937d1 commit 58e8cf2

File tree

4 files changed

+67
-37
lines changed

4 files changed

+67
-37
lines changed

Lib/test/test_ast.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,15 +1386,7 @@ class MyNode(ast.AST):
13861386
self.assertEqual(node.y, 1)
13871387

13881388
y = object()
1389-
# custom attributes are currently not supported and raise a warning
1390-
# because the allowed attributes are hard-coded !
1391-
msg = (
1392-
"MyNode.__init__ got an unexpected keyword argument 'y'. "
1393-
"Support for arbitrary keyword arguments is deprecated and "
1394-
"will be removed in Python 3.15"
1395-
)
1396-
with self.assertWarnsRegex(DeprecationWarning, re.escape(msg)):
1397-
repl = copy.replace(node, y=y)
1389+
repl = copy.replace(node, y=y)
13981390
# assert that there is no side-effect
13991391
self.assertEqual(node.x, 0)
14001392
self.assertEqual(node.y, 1)
@@ -3250,6 +3242,18 @@ class FieldsAndTypes(ast.AST):
32503242
obj = FieldsAndTypes(a=1)
32513243
self.assertEqual(obj.a, 1)
32523244

3245+
def test_custom_attributes(self):
3246+
class MyAttrs(ast.AST):
3247+
_attributes = ("a", "b")
3248+
3249+
obj = MyAttrs(a=1, b=2)
3250+
self.assertEqual(obj.a, 1)
3251+
self.assertEqual(obj.b, 2)
3252+
3253+
with self.assertWarnsRegex(DeprecationWarning,
3254+
r"MyAttrs.__init__ got an unexpected keyword argument 'c'."):
3255+
obj = MyAttrs(c=3)
3256+
32533257
def test_fields_and_types_no_default(self):
32543258
class FieldsAndTypesNoDefault(ast.AST):
32553259
_fields = ('a',)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix constructor of :mod:`ast` nodes with custom ``_attributes``. Previously,
2+
passing custom attributes would raise a :py:exc:`DeprecationWarning`. Passing
3+
arguments to the constructor that are not in ``_fields`` or ``_attributes``
4+
remains deprecated. Patch by Jelle Zijlstra.

Parser/asdl_c.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ def visitModule(self, mod):
880880
881881
Py_ssize_t i, numfields = 0;
882882
int res = -1;
883-
PyObject *key, *value, *fields, *remaining_fields = NULL;
883+
PyObject *key, *value, *fields, *attributes = NULL, *remaining_fields = NULL;
884884
if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) {
885885
goto cleanup;
886886
}
@@ -947,22 +947,32 @@ def visitModule(self, mod):
947947
goto cleanup;
948948
}
949949
}
950-
else if (
951-
PyUnicode_CompareWithASCIIString(key, "lineno") != 0 &&
952-
PyUnicode_CompareWithASCIIString(key, "col_offset") != 0 &&
953-
PyUnicode_CompareWithASCIIString(key, "end_lineno") != 0 &&
954-
PyUnicode_CompareWithASCIIString(key, "end_col_offset") != 0
955-
) {
956-
if (PyErr_WarnFormat(
957-
PyExc_DeprecationWarning, 1,
958-
"%.400s.__init__ got an unexpected keyword argument '%U'. "
959-
"Support for arbitrary keyword arguments is deprecated "
960-
"and will be removed in Python 3.15.",
961-
Py_TYPE(self)->tp_name, key
962-
) < 0) {
950+
else {
951+
// Lazily initialize "attributes"
952+
if (attributes == NULL) {
953+
attributes = PyObject_GetAttr((PyObject*)Py_TYPE(self), state->_attributes);
954+
if (attributes == NULL) {
955+
res = -1;
956+
goto cleanup;
957+
}
958+
}
959+
int contains = PySequence_Contains(attributes, key);
960+
if (contains == -1) {
963961
res = -1;
964962
goto cleanup;
965963
}
964+
else if (contains == 0) {
965+
if (PyErr_WarnFormat(
966+
PyExc_DeprecationWarning, 1,
967+
"%.400s.__init__ got an unexpected keyword argument '%U'. "
968+
"Support for arbitrary keyword arguments is deprecated "
969+
"and will be removed in Python 3.15.",
970+
Py_TYPE(self)->tp_name, key
971+
) < 0) {
972+
res = -1;
973+
goto cleanup;
974+
}
975+
}
966976
}
967977
res = PyObject_SetAttr(self, key, value);
968978
if (res < 0) {
@@ -1045,6 +1055,7 @@ def visitModule(self, mod):
10451055
Py_DECREF(field_types);
10461056
}
10471057
cleanup: 57AE
1058+
Py_XDECREF(attributes);
10481059
Py_XDECREF(fields);
10491060
Py_XDECREF(remaining_fields);
10501061
return res;

Python/Python-ast.c

Lines changed: 25 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0