#!/usr/bin/env python3 """Focused Visual C++ 6.0 C89 regression checks for moduleobject.c.""" import re import sys from pathlib import Path source = Path(sys.argv[1]).read_text() def function_body(name): match = re.search( re.escape(name) + r"\s*\([^;]*\)\s*\{(?P.*?)\n\}", source, re.S, ) assert match, name + " definition not found" return match.group("body") def ordered(body, tokens, message): positions = [body.find(token) for token in tokens] assert all(position >= 0 for position in positions) and positions == sorted(positions), message body = function_body("_PyModule_IsExtension") ordered(body, ( "PyModuleObject *module;", "PyModuleDef *def;", "if (!PyModule_Check(obj))", "module = (PyModuleObject*)obj;", "def = module->md_def;", ), "_PyModule_IsExtension must declare its locals before validation and preserve lookup order") assert "PyModuleObject *module =" not in body and "PyModuleDef *def =" not in body print("moduleobject _PyModule_IsExtension C89 locals and lookup order: PASS") body = function_body("_PyModuleSpec_IsUninitializedSubmodule") ordered(body, ( "PyObject *value;", "int is_uninitialized;", "if (spec == NULL)", "value = PyObject_GetAttr(spec, &_Py_ID(_uninitialized_submodules));", "is_uninitialized = PySequence_Contains(value, name);", "Py_DECREF(value);", ), "_PyModuleSpec_IsUninitializedSubmodule must hoist declarations while preserving reference order") assert "PyObject *value =" not in body and "int is_uninitialized =" not in body print("moduleobject uninitialized-submodule C89 locals and reference order: PASS") body = function_body("module_getattro") ordered(body, ( "PyObject *attr, *mod_name, *getattr, *spec;", "attr = PyObject_GenericGetAttr((PyObject *)m, name);", "Py_INCREF(mod_name);", "spec = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__spec__));", ), "module_getattro must hoist spec without changing lookup timing") assert "PyObject *spec =" not in body print("moduleobject module_getattro C89 local and lookup order: PASS") body = function_body("module_get_annotations") ordered(body, ( "PyObject *dict;", "PyObject *annotations;", "int result;", "dict = PyObject_GetAttr((PyObject *)m, &_Py_ID(__dict__));", "annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__));", "result = PyDict_SetItem(", ), "module_get_annotations must hoist locals and preserve dictionary/error order") assert "PyObject *annotations =" not in body and "int result =" not in body print("moduleobject module_get_annotations C89 locals and dictionary order: PASS")