#!/usr/bin/env python3 """Check winner's C89 declaration and preserve get-bases evaluation order.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nstatic int\ntype_new_get_bases\(type_new_ctx \*ctx, PyObject \*\*type\)\n\{(.*?)\n\}", source, re.S, ) assert match, "type_new_get_bases definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) assert re.match( r"\s*Py_ssize_t nbases = PyTuple_GET_SIZE\(ctx->bases\);" r"\s*Py_ssize_t i;\s*PyTypeObject \*winner;\s*PyTypeObject \*base;" r"\s*if \(nbases == 0\)", body, ), "type_new_get_bases: winner must be declared before statements (C89)" assert len(re.findall(r"\bPyTypeObject\s*\*\s*winner\b", body)) == 1, ( "declare winner exactly once" ) expected = """ Py_ssize_t nbases = PyTuple_GET_SIZE(ctx->bases); Py_ssize_t i; PyTypeObject *base; if (nbases == 0) { PyObject *new_bases; ctx->base = &PyBaseObject_Type; new_bases = PyTuple_Pack(1, ctx->base); if (new_bases == NULL) { return -1; } ctx->bases = new_bases; return 0; } for (i = 0; i < nbases; i++) { PyObject *base = PyTuple_GET_ITEM(ctx->bases, i); PyObject *mro_entries; if (PyType_Check(base)) { continue; } if (_PyObject_LookupAttr(base, &_Py_ID(__mro_entries__), &mro_entries) < 0) { return -1; } if (mro_entries != NULL) { PyErr_SetString(PyExc_TypeError, "type() doesn't support MRO entry resolution; " "use types.new_class()"); Py_DECREF(mro_entries); return -1; } } winner = _PyType_CalculateMetaclass(ctx->metatype, ctx->bases); if (winner == NULL) { return -1; } if (winner != ctx->metatype) { if (winner->tp_new != type_new) { *type = winner->tp_new(winner, ctx->args, ctx->kwds); if (*type == NULL) { return -1; } return 1; } ctx->metatype = winner; } base = best_base(ctx->bases); if (base == NULL) { return -1; } ctx->base = base; ctx->bases = Py_NewRef(ctx->bases); return 0; """ without_winner_declaration = re.sub(r"\bPyTypeObject\s*\*\s*winner;", "", body) assert without_winner_declaration.split() == expected.split(), ( "preserve base validation, metaclass calculation, winner dispatch, best-base " "calculation, reference updates, and returns at their original evaluation points" ) print("type_new_get_bases winner C89 declaration and evaluation ordering: PASS")