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
This commit is contained in:
Eric Snow 2023-01-12 13:42:03 -07:00 committed by GitHub
parent 005e69403d
commit b511d3512b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 33 deletions

View File

@ -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[] = {
};
/* initialization function */
static int
module_exec(PyObject *module)
{
if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
return 1;
}
return 0;
}
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 = {
PyModuleDef_HEAD_INIT,
"_testinternalcapi",
NULL,
-1,
TestMethods,
NULL,
NULL,
NULL,
NULL
.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)
{
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 module;
error:
Py_DECREF(module);
return NULL;
return PyModuleDef_Init(&_testcapimodule);
}

View File

@ -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 -

Can't render this file because it has a wrong number of fields in line 4.

View File

@ -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 -

Can't render this file because it has a wrong number of fields in line 4.