[3.9] bpo-41194: Convert _ast extension to PEP 489 (GH-21807)
* bpo-41194: Convert _ast extension to PEP 489 (GH-21293)
Convert the _ast extension module to PEP 489 "Multiphase
initialization". Replace the global _ast state with a module state.
(cherry picked from commit b1cc6ba73a51d5cc3aeb113b5e7378fb50a0e20a)
* bpo-41204: Fix compiler warning in ast_type_init() (GH-21307)
(cherry picked from commit 1f76453173267887ed05bb3783e862cb22365ae8)
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index f029ca6..6fe44b9 100755
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -688,10 +688,14 @@
static int
ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
{
+ astmodulestate *state = get_global_ast_state();
+ if (state == NULL) {
+ return -1;
+ }
+
Py_ssize_t i, numfields = 0;
int res = -1;
PyObject *key, *value, *fields;
- astmodulestate *state = get_global_ast_state();
if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) {
goto cleanup;
}
@@ -761,6 +765,10 @@
ast_type_reduce(PyObject *self, PyObject *unused)
{
astmodulestate *state = get_global_ast_state();
+ if (state == NULL) {
+ return NULL;
+ }
+
PyObject *dict;
if (_PyObject_LookupAttr(self, state->__dict__, &dict) < 0) {
return NULL;
@@ -969,9 +977,8 @@
""", 0, reflow=False)
- self.emit("static int init_types(void)",0)
+ self.emit("static int init_types(astmodulestate *state)",0)
self.emit("{", 0)
- self.emit("astmodulestate *state = get_global_ast_state();", 1)
self.emit("if (state->initialized) return 1;", 1)
self.emit("if (init_identifiers(state) < 0) return 0;", 1)
self.emit("state->AST_type = PyType_FromSpec(&AST_type_spec);", 1)
@@ -1046,40 +1053,55 @@
class ASTModuleVisitor(PickleVisitor):
def visitModule(self, mod):
- self.emit("PyMODINIT_FUNC", 0)
- self.emit("PyInit__ast(void)", 0)
+ self.emit("static int", 0)
+ self.emit("astmodule_exec(PyObject *m)", 0)
self.emit("{", 0)
- self.emit("PyObject *m = PyModule_Create(&_astmodule);", 1)
- self.emit("if (!m) {", 1)
- self.emit("return NULL;", 2)
- self.emit("}", 1)
self.emit('astmodulestate *state = get_ast_state(m);', 1)
- self.emit('', 1)
+ self.emit("", 0)
- self.emit("if (!init_types()) {", 1)
- self.emit("goto error;", 2)
+ self.emit("if (!init_types(state)) {", 1)
+ self.emit("return -1;", 2)
self.emit("}", 1)
self.emit('if (PyModule_AddObject(m, "AST", state->AST_type) < 0) {', 1)
- self.emit('goto error;', 2)
+ self.emit('return -1;', 2)
self.emit('}', 1)
self.emit('Py_INCREF(state->AST_type);', 1)
self.emit('if (PyModule_AddIntMacro(m, PyCF_ALLOW_TOP_LEVEL_AWAIT) < 0) {', 1)
- self.emit("goto error;", 2)
+ self.emit("return -1;", 2)
self.emit('}', 1)
self.emit('if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0) {', 1)
- self.emit("goto error;", 2)
+ self.emit("return -1;", 2)
self.emit('}', 1)
self.emit('if (PyModule_AddIntMacro(m, PyCF_TYPE_COMMENTS) < 0) {', 1)
- self.emit("goto error;", 2)
+ self.emit("return -1;", 2)
self.emit('}', 1)
for dfn in mod.dfns:
self.visit(dfn)
- self.emit("return m;", 1)
- self.emit("", 0)
- self.emit("error:", 0)
- self.emit("Py_DECREF(m);", 1)
- self.emit("return NULL;", 1)
+ self.emit("return 0;", 1)
self.emit("}", 0)
+ self.emit("", 0)
+ self.emit("""
+static PyModuleDef_Slot astmodule_slots[] = {
+ {Py_mod_exec, astmodule_exec},
+ {0, NULL}
+};
+
+static struct PyModuleDef _astmodule = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_ast",
+ .m_size = sizeof(astmodulestate),
+ .m_slots = astmodule_slots,
+ .m_traverse = astmodule_traverse,
+ .m_clear = astmodule_clear,
+ .m_free = astmodule_free,
+};
+
+PyMODINIT_FUNC
+PyInit__ast(void)
+{
+ return PyModuleDef_Init(&_astmodule);
+}
+""".strip(), 0, reflow=False)
def visitProduct(self, prod, name):
self.addObj(name)
@@ -1095,7 +1117,7 @@
def addObj(self, name):
self.emit("if (PyModule_AddObject(m, \"%s\", "
"state->%s_type) < 0) {" % (name, name), 1)
- self.emit("goto error;", 2)
+ self.emit("return -1;", 2)
self.emit('}', 1)
self.emit("Py_INCREF(state->%s_type);" % name, 1)
@@ -1255,11 +1277,10 @@
CODE = """
PyObject* PyAST_mod2obj(mod_ty t)
{
- if (!init_types()) {
+ astmodulestate *state = get_global_ast_state();
+ if (state == NULL) {
return NULL;
}
-
- astmodulestate *state = get_global_ast_state();
return ast2obj_mod(state, t);
}
@@ -1281,10 +1302,6 @@
assert(0 <= mode && mode <= 2);
- if (!init_types()) {
- return NULL;
- }
-
isinstance = PyObject_IsInstance(ast, req_type[mode]);
if (isinstance == -1)
return NULL;
@@ -1303,11 +1320,10 @@
int PyAST_Check(PyObject* obj)
{
- if (!init_types()) {
+ astmodulestate *state = get_global_ast_state();
+ if (state == NULL) {
return -1;
}
-
- astmodulestate *state = get_global_ast_state();
return PyObject_IsInstance(obj, state->AST_type);
}
"""
@@ -1358,12 +1374,35 @@
f.write(' PyObject *' + s + ';\n')
f.write('} astmodulestate;\n\n')
f.write("""
-static astmodulestate global_ast_state;
-
-static astmodulestate *
-get_ast_state(PyObject *Py_UNUSED(module))
+static astmodulestate*
+get_ast_state(PyObject *module)
{
- return &global_ast_state;
+ void *state = PyModule_GetState(module);
+ assert(state != NULL);
+ return (astmodulestate*)state;
+}
+
+static astmodulestate*
+get_global_ast_state(void)
+{
+ _Py_IDENTIFIER(_ast);
+ PyObject *name = _PyUnicode_FromId(&PyId__ast); // borrowed reference
+ if (name == NULL) {
+ return NULL;
+ }
+ PyObject *module = PyImport_GetModule(name);
+ if (module == NULL) {
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ module = PyImport_Import(name);
+ if (module == NULL) {
+ return NULL;
+ }
+ }
+ astmodulestate *state = get_ast_state(module);
+ Py_DECREF(module);
+ return state;
}
static int astmodule_clear(PyObject *module)
@@ -1390,17 +1429,6 @@
astmodule_clear((PyObject*)module);
}
-static struct PyModuleDef _astmodule = {
- PyModuleDef_HEAD_INIT,
- .m_name = "_ast",
- .m_size = -1,
- .m_traverse = astmodule_traverse,
- .m_clear = astmodule_clear,
- .m_free = astmodule_free,
-};
-
-#define get_global_ast_state() (&global_ast_state)
-
""")
f.write('static int init_identifiers(astmodulestate *state)\n')
f.write('{\n')