#!/usr/bin/env python3 """Statically check type_new ctx declaration and post-parse initialization.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() function = re.search( r"\ntype_new\(PyTypeObject \*metatype, PyObject \*args, PyObject \*kwds\)\n\{(.*?)\n\}", source, re.S, ) assert function, "type_new definition must exist" body = function.group(1) opening = re.match( r"\s*PyObject \*name, \*bases, \*orig_dict;\s*type_new_ctx ctx;\s*" r"PyObject \*type;\s*int res;\s*(?=assert\()", body, ) assert opening, "type_new: type_new_ctx ctx must be in the opening declaration block" assert len(re.findall(r"\btype_new_ctx\s+ctx\b", body)) == 1 expected_setup = """ memset(&ctx, 0, sizeof(ctx)); ctx.metatype = metatype; ctx.args = args; ctx.kwds = kwds; ctx.orig_dict = orig_dict; ctx.name = name; ctx.bases = bases; """ expected_parse = """ assert(args != NULL && PyTuple_Check(args)); assert(kwds == NULL || PyDict_Check(kwds)); /* Parse arguments: (name, bases, dict) */ if (!PyArg_ParseTuple(args, "UO!O!:type.__new__", &name, &PyTuple_Type, &bases, &PyDict_Type, &orig_dict)) { return NULL; } """ prefix, separator, tail = body[opening.end():].partition("type = NULL;") assert separator, "base-resolution frontier must remain" assert prefix.split() == (expected_parse + expected_setup).split(), ( "preserve parsing and failure return, then zero all ctx fields and assign inputs" ) assert tail.lstrip().startswith("res = type_new_get_bases(&ctx, &type);"), ( "base resolution must still follow ctx setup" ) assert "(type_new_ctx)" not in body, "no C99 compound literal" assert "# include " in Path("cpython/Include/Python.h").read_text() print("type_new ctx opening declaration and post-parse zero/field setup: PASS (static only)")