50 lines
1.7 KiB
Python
50 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Check type_set_annotations's C89 local and unchanged executable body."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
source = Path("cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nstatic int\ntype_set_annotations\(PyTypeObject \*type, PyObject \*value, void \*context\)\n\{(.*?)\n\}",
|
|
source,
|
|
re.S,
|
|
)
|
|
assert match, "type_set_annotations definition missing"
|
|
body = match.group(1)
|
|
assert re.match(r"\s*int result;\s*if\b", body), (
|
|
"type_set_annotations: result must be declared before the immutable-type guard"
|
|
)
|
|
assert len(re.findall(r"\bint\s+result\b", body)) == 1, (
|
|
"type_set_annotations: declare result exactly once"
|
|
)
|
|
expected = """
|
|
int result;
|
|
if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"cannot set '__annotations__' attribute of immutable type '%s'",
|
|
type->tp_name);
|
|
return -1;
|
|
}
|
|
|
|
if (value != NULL) {
|
|
/* set */
|
|
result = PyDict_SetItem(type->tp_dict, &_Py_ID(__annotations__), value);
|
|
} else {
|
|
/* delete */
|
|
result = PyDict_DelItem(type->tp_dict, &_Py_ID(__annotations__));
|
|
if (result < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
|
|
PyErr_SetString(PyExc_AttributeError, "__annotations__");
|
|
}
|
|
}
|
|
|
|
if (result == 0) {
|
|
PyType_Modified(type);
|
|
}
|
|
return result;
|
|
"""
|
|
assert body.split() == expected.split(), (
|
|
"type_set_annotations: preserve guard, assignments, set/delete branches, "
|
|
"error handling, invalidation, and return in their original order"
|
|
)
|
|
print("type_set_annotations result C89 declaration and unchanged executable body: PASS")
|