mirror of https://github.com/python/cpython
gh-117266: Fix crashes on user-created AST subclasses (GH-117276)
Fix crashes on user-created AST subclasses
This commit is contained in:
parent
8cb7d7ff86
commit
4c71d51a4b
|
@ -2916,6 +2916,47 @@ class ASTConstructorTests(unittest.TestCase):
|
||||||
self.assertEqual(node.name, 'foo')
|
self.assertEqual(node.name, 'foo')
|
||||||
self.assertEqual(node.decorator_list, [])
|
self.assertEqual(node.decorator_list, [])
|
||||||
|
|
||||||
|
def test_custom_subclass(self):
|
||||||
|
class NoInit(ast.AST):
|
||||||
|
pass
|
||||||
|
|
||||||
|
obj = NoInit()
|
||||||
|
self.assertIsInstance(obj, NoInit)
|
||||||
|
self.assertEqual(obj.__dict__, {})
|
||||||
|
|
||||||
|
class Fields(ast.AST):
|
||||||
|
_fields = ('a',)
|
||||||
|
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning,
|
||||||
|
r"Fields provides _fields but not _field_types."):
|
||||||
|
obj = Fields()
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
obj.a
|
||||||
|
obj = Fields(a=1)
|
||||||
|
self.assertEqual(obj.a, 1)
|
||||||
|
|
||||||
|
class FieldsAndTypes(ast.AST):
|
||||||
|
_fields = ('a',)
|
||||||
|
_field_types = {'a': int | None}
|
||||||
|
a: int | None = None
|
||||||
|
|
||||||
|
obj = FieldsAndTypes()
|
||||||
|
self.assertIs(obj.a, None)
|
||||||
|
obj = FieldsAndTypes(a=1)
|
||||||
|
self.assertEqual(obj.a, 1)
|
||||||
|
|
||||||
|
class FieldsAndTypesNoDefault(ast.AST):
|
||||||
|
_fields = ('a',)
|
||||||
|
_field_types = {'a': int}
|
||||||
|
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning,
|
||||||
|
r"FieldsAndTypesNoDefault\.__init__ missing 1 required positional argument: 'a'\."):
|
||||||
|
obj = FieldsAndTypesNoDefault()
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
obj.a
|
||||||
|
obj = FieldsAndTypesNoDefault(a=1)
|
||||||
|
self.assertEqual(obj.a, 1)
|
||||||
|
|
||||||
|
|
||||||
@support.cpython_only
|
@support.cpython_only
|
||||||
class ModuleStateTests(unittest.TestCase):
|
class ModuleStateTests(unittest.TestCase):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix crashes for certain user-created subclasses of :class:`ast.AST`. Such
|
||||||
|
classes are now expected to set the ``_field_types`` attribute.
|
|
@ -973,11 +973,22 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
|
||||||
Py_ssize_t size = PySet_Size(remaining_fields);
|
Py_ssize_t size = PySet_Size(remaining_fields);
|
||||||
PyObject *field_types = NULL, *remaining_list = NULL;
|
PyObject *field_types = NULL, *remaining_list = NULL;
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
if (!PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), &_Py_ID(_field_types),
|
if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), &_Py_ID(_field_types),
|
||||||
&field_types)) {
|
&field_types) < 0) {
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
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;
|
||||||
|
}
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
remaining_list = PySequence_List(remaining_fields);
|
remaining_list = PySequence_List(remaining_fields);
|
||||||
if (!remaining_list) {
|
if (!remaining_list) {
|
||||||
goto set_remaining_cleanup;
|
goto set_remaining_cleanup;
|
||||||
|
|
|
@ -5119,11 +5119,22 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
|
||||||
Py_ssize_t size = PySet_Size(remaining_fields);
|
Py_ssize_t size = PySet_Size(remaining_fields);
|
||||||
PyObject *field_types = NULL, *remaining_list = NULL;
|
PyObject *field_types = NULL, *remaining_list = NULL;
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
if (!PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), &_Py_ID(_field_types),
|
if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), &_Py_ID(_field_types),
|
||||||
&field_types)) {
|
&field_types) < 0) {
|
||||||
res = -1;
|
res = -1;
|
||||||
goto cleanup;
|
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;
|
||||||
|
}
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
remaining_list = PySequence_List(remaining_fields);
|
remaining_list = PySequence_List(remaining_fields);
|
||||||
if (!remaining_list) {
|
if (!remaining_list) {
|
||||||
goto set_remaining_cleanup;
|
goto set_remaining_cleanup;
|
||||||
|
|
Loading…
Reference in New Issue