[Python-checkins] GH-100997: Implement Multi-Phase Init for the _testinternalcapi Module (gh-100998)

ericsnowcurrently webhook-mailer at python.org
Thu Jan 12 15:42:21 EST 2023


https://github.com/python/cpython/commit/b511d3512ba334475201baf4d9db7c4d28f0a9ad
commit: b511d3512ba334475201baf4d9db7c4d28f0a9ad
branch: main
author: Eric Snow <ericsnowcurrently at gmail.com>
committer: ericsnowcurrently <ericsnowcurrently at gmail.com>
date: 2023-01-12T13:42:03-07:00
summary:

GH-100997: Implement Multi-Phase Init for the _testinternalcapi Module (gh-100998)

_testinternalcapi is an internal module used for testing.

https://github.com/python/cpython/issues/100997

files:
M Modules/_testinternalcapi.c
M Tools/c-analyzer/cpython/globals-to-fix.tsv
M Tools/c-analyzer/cpython/ignored.tsv

diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index b14b8ac3c740..f53929f80f8a 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -28,6 +28,60 @@
 
 #include "clinic/_testinternalcapi.c.h"
 
+
+#define MODULE_NAME "_testinternalcapi"
+
+
+static PyObject *
+_get_current_module(void)
+{
+    // We ensured it was imported in _run_script().
+    PyObject *name = PyUnicode_FromString(MODULE_NAME);
+    if (name == NULL) {
+        return NULL;
+    }
+    PyObject *mod = PyImport_GetModule(name);
+    Py_DECREF(name);
+    if (mod == NULL) {
+        return NULL;
+    }
+    assert(mod != Py_None);
+    return mod;
+}
+
+
+/* module state *************************************************************/
+
+typedef struct {
+    PyObject *record_list;
+} module_state;
+
+static inline module_state *
+get_module_state(PyObject *mod)
+{
+    assert(mod != NULL);
+    module_state *state = PyModule_GetState(mod);
+    assert(state != NULL);
+    return state;
+}
+
+static int
+traverse_module_state(module_state *state, visitproc visit, void *arg)
+{
+    Py_VISIT(state->record_list);
+    return 0;
+}
+
+static int
+clear_module_state(module_state *state)
+{
+    Py_CLEAR(state->record_list);
+    return 0;
+}
+
+
+/* module functions *********************************************************/
+
 /*[clinic input]
 module _testinternalcapi
 [clinic start generated code]*/
@@ -496,13 +550,12 @@ decode_locale_ex(PyObject *self, PyObject *args)
     return res;
 }
 
-static PyObject *record_list = NULL;
-
 static PyObject *
 set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args))
 {
+    module_state *state = get_module_state(self);
     _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), _PyEval_EvalFrameDefault);
-    Py_CLEAR(record_list);
+    Py_CLEAR(state->record_list);
     Py_RETURN_NONE;
 }
 
@@ -510,7 +563,10 @@ static PyObject *
 record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
 {
     if (PyFunction_Check(f->f_funcobj)) {
-        PyList_Append(record_list, ((PyFunctionObject *)f->f_funcobj)->func_name);
+        PyObject *module = _get_current_module();
+        assert(module != NULL);
+        module_state *state = get_module_state(module);
+        PyList_Append(state->record_list, ((PyFunctionObject *)f->f_funcobj)->func_name);
     }
     return _PyEval_EvalFrameDefault(tstate, f, exc);
 }
@@ -519,11 +575,12 @@ record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
 static PyObject *
 set_eval_frame_record(PyObject *self, PyObject *list)
 {
+    module_state *state = get_module_state(self);
     if (!PyList_Check(list)) {
         PyErr_SetString(PyExc_TypeError, "argument must be a list");
         return NULL;
     }
-    Py_XSETREF(record_list, Py_NewRef(list));
+    Py_XSETREF(state->record_list, Py_NewRef(list));
     _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), record_eval);
     Py_RETURN_NONE;
 }
@@ -613,7 +670,7 @@ get_interp_settings(PyObject *self, PyObject *args)
 }
 
 
-static PyMethodDef TestMethods[] = {
+static PyMethodDef module_functions[] = {
     {"get_configs", get_configs, METH_NOARGS},
     {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
     {"test_bswap", test_bswap, METH_NOARGS},
@@ -638,35 +695,65 @@ static PyMethodDef TestMethods[] = {
 };
 
 
-static struct PyModuleDef _testcapimodule = {
-    PyModuleDef_HEAD_INIT,
-    "_testinternalcapi",
-    NULL,
-    -1,
-    TestMethods,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
-
+/* initialization function */
 
-PyMODINIT_FUNC
-PyInit__testinternalcapi(void)
+static int
+module_exec(PyObject *module)
 {
-    PyObject *module = PyModule_Create(&_testcapimodule);
-    if (module == NULL) {
-        return NULL;
-    }
-
     if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
                            PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
-        goto error;
+        return 1;
     }
 
-    return module;
+    return 0;
+}
 
-error:
-    Py_DECREF(module);
-    return NULL;
+static struct PyModuleDef_Slot module_slots[] = {
+    {Py_mod_exec, module_exec},
+    {0, NULL},
+};
+
+static int
+module_traverse(PyObject *module, visitproc visit, void *arg)
+{
+    module_state *state = get_module_state(module);
+    assert(state != NULL);
+    traverse_module_state(state, visit, arg);
+    return 0;
+}
+
+static int
+module_clear(PyObject *module)
+{
+    module_state *state = get_module_state(module);
+    assert(state != NULL);
+    (void)clear_module_state(state);
+    return 0;
+}
+
+static void
+module_free(void *module)
+{
+    module_state *state = get_module_state(module);
+    assert(state != NULL);
+    (void)clear_module_state(state);
+}
+
+static struct PyModuleDef _testcapimodule = {
+    .m_base = PyModuleDef_HEAD_INIT,
+    .m_name = MODULE_NAME,
+    .m_doc = NULL,
+    .m_size = sizeof(module_state),
+    .m_methods = module_functions,
+    .m_slots = module_slots,
+    .m_traverse = module_traverse,
+    .m_clear = module_clear,
+    .m_free = (freefunc)module_free,
+};
+
+
+PyMODINIT_FUNC
+PyInit__testinternalcapi(void)
+{
+    return PyModuleDef_Init(&_testcapimodule);
 }
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index 479221cbd4b6..cd08782edce4 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -523,7 +523,6 @@ Modules/_asynciomodule.c	-	all_tasks	-
 Modules/_asynciomodule.c	-	current_tasks	-
 Modules/_asynciomodule.c	-	iscoroutine_typecache	-
 Modules/_ctypes/_ctypes.c	-	_ctypes_ptrtype_cache	-
-Modules/_testinternalcapi.c	-	record_list	-
 Modules/_tkinter.c	-	tcl_lock	-
 Modules/_tkinter.c	-	excInCmd	-
 Modules/_tkinter.c	-	valInCmd	-
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index 02531692a884..849e20a1b0f4 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -483,8 +483,6 @@ Modules/_testcapimodule.c	-	g_type_watchers_installed	-
 Modules/_testimportmultiple.c	-	_barmodule	-
 Modules/_testimportmultiple.c	-	_foomodule	-
 Modules/_testimportmultiple.c	-	_testimportmultiple	-
-Modules/_testinternalcapi.c	-	TestMethods	-
-Modules/_testinternalcapi.c	-	_testcapimodule	-
 Modules/_testmultiphase.c	-	Example_Type_slots	-
 Modules/_testmultiphase.c	-	Example_Type_spec	-
 Modules/_testmultiphase.c	-	Example_methods	-



More information about the Python-checkins mailing list