47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Check the mro_entries declaration and preserve base lookup ordering."""
|
|
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.search(
|
|
r"for \(i = 0; i < nbases; i\+\+\) \{\s*"
|
|
r"PyObject \*base = PyTuple_GET_ITEM\(ctx->bases, i\);\s*"
|
|
r"PyObject \*mro_entries;\s*if \(PyType_Check\(base\)\)",
|
|
body,
|
|
), "type_new_get_bases: mro_entries must precede loop statements (C89)"
|
|
assert len(re.findall(r"\bPyObject\s*\*\s*mro_entries\b", body)) == 1, (
|
|
"declare mro_entries exactly once"
|
|
)
|
|
loop = body[body.index(" for ("):body.index(" winner = _PyType_CalculateMetaclass(")]
|
|
expected = """
|
|
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;
|
|
}
|
|
}
|
|
"""
|
|
assert loop.split() == expected.split(), (
|
|
"preserve base lookup, type skip, attribute lookup, error handling, and decref order"
|
|
)
|
|
print("type_new_get_bases mro_entries C89 declaration and lookup ordering: PASS")
|