gh-117486: Improve behavior for user-defined AST subclasses (#118212)

Now, such classes will no longer require changes in Python 3.13 in the normal case.
The test suite for robotframework passes with no DeprecationWarnings under this PR.

I also added a new DeprecationWarning for the case where `_field_types` exists
but is incomplete, since that seems likely to indicate a user mistake.
This commit is contained in:
Jelle Zijlstra 2024-05-06 15:57:27 -07:00 committed by GitHub
parent 040571f258
commit e0422198fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 94 additions and 33 deletions

31
Python/Python-ast.c generated
View file

@ -5178,14 +5178,9 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
goto cleanup;
}
if (field_types == NULL) {
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"%.400s provides _fields but not _field_types. "
"This will become an error in Python 3.15.",
Py_TYPE(self)->tp_name
) < 0) {
res = -1;
}
// Probably a user-defined subclass of AST that lacks _field_types.
// This will continue to work as it did before 3.13; i.e., attributes
// that are not passed in simply do not exist on the instance.
goto cleanup;
}
remaining_list = PySequence_List(remaining_fields);
@ -5196,12 +5191,21 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
PyObject *name = PyList_GET_ITEM(remaining_list, i);
PyObject *type = PyDict_GetItemWithError(field_types, name);
if (!type) {
if (!PyErr_Occurred()) {
PyErr_SetObject(PyExc_KeyError, name);
if (PyErr_Occurred()) {
goto set_remaining_cleanup;
}
else {
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"Field '%U' is missing from %.400s._field_types. "
"This will become an error in Python 3.15.",
name, Py_TYPE(self)->tp_name
) < 0) {
goto set_remaining_cleanup;
}
}
goto set_remaining_cleanup;
}
if (_PyUnion_Check(type)) {
else if (_PyUnion_Check(type)) {
// optional field
// do nothing, we'll have set a None default on the class
}
@ -5225,8 +5229,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
"This will become an error in Python 3.15.",
Py_TYPE(self)->tp_name, name
) < 0) {
res = -1;
goto cleanup;
goto set_remaining_cleanup;
}
}
}