#!/usr/bin/env python3 """Keep _PyType_GetSubclasses's obj 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\);\s*PyObject \*ref;\s*" r"PyObject \*obj;", body, ), "_PyType_GetSubclasses: obj must be in the opening declaration block (C89)" assert len(re.findall(r"\bPyObject\s*\*\s*obj\b", body)) == 1, ( "_PyType_GetSubclasses: declare obj exactly once without initialization" ) assert body.count("PyWeakref_GET_OBJECT(ref)") == 1, ( "_PyType_GetSubclasses: preserve the single weakref object read" ) assert re.search( r"while \(PyDict_Next\(subclasses, &i, NULL, &ref\)\) \{\s*" r"assert\(PyWeakref_CheckRef\(ref\)\);\s*" r"obj = PyWeakref_GET_OBJECT\(ref\);\s*" r"if \(obj == Py_None\) \{\s*continue;\s*\}\s*" r"assert\(PyType_Check\(obj\)\);\s*" r"if \(PyList_Append\(list, obj\) < 0\) \{\s*" r"Py_DECREF\(list\);\s*return NULL;\s*\}\s*\}\s*return list;\s*$", body, ), "_PyType_GetSubclasses: preserve obj assignment timing and loop control flow" print("_PyType_GetSubclasses obj C89 declaration and preserved assignment timing: PASS")