#!/usr/bin/env python3 """Keep _PyType_GetSubclasses's index in opening C89 locals.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nPyObject\*\n_PyType_GetSubclasses\(PyTypeObject \*self\)\n\{(.*?)\n\}", source, re.S, ) assert match, "_PyType_GetSubclasses definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) assert re.match( r"\s*PyObject \*subclasses;\s*Py_ssize_t i;\s*" r"PyObject \*list = PyList_New\(0\);", body, ), "_PyType_GetSubclasses: i must be declared in the opening declaration block (C89)" assert len(re.findall(r"\bPy_ssize_t\s+i\b", body)) == 1, ( "_PyType_GetSubclasses: declare i exactly once" ) expected = """ PyObject *subclasses; Py_ssize_t i; PyObject *list = PyList_New(0); PyObject *ref; PyObject *obj; if (list == NULL) { return NULL; } subclasses = self->tp_subclasses; if (subclasses == NULL) { return list; } assert(PyDict_CheckExact(subclasses)); i = 0; while (PyDict_Next(subclasses, &i, NULL, &ref)) { assert(PyWeakref_CheckRef(ref)); obj = PyWeakref_GET_OBJECT(ref); if (obj == Py_None) { continue; } assert(PyType_Check(obj)); if (PyList_Append(list, obj) < 0) { Py_DECREF(list); return NULL; } } return list; """ assert body.split() == expected.split(), ( "_PyType_GetSubclasses: preserve index initialization timing, guards, loop, " "and ref/obj uses" ) print("_PyType_GetSubclasses C89 index declaration and preserved initialization timing: PASS")