gh-91051: allow setting a callback hook on PyType_Modified (GH-97875)

This commit is contained in:
Carl Meyer 2022-10-21 07:41:51 -06:00 committed by GitHub
parent 8367ca136e
commit 82ccbf69a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 462 additions and 5 deletions

View file

@ -5695,6 +5695,128 @@ function_get_module(PyObject *self, PyObject *func)
}
// type watchers
static PyObject *g_type_modified_events;
static int g_type_watchers_installed;
static int
type_modified_callback(PyTypeObject *type)
{
assert(PyList_Check(g_type_modified_events));
if(PyList_Append(g_type_modified_events, (PyObject *)type) < 0) {
return -1;
}
return 0;
}
static int
type_modified_callback_wrap(PyTypeObject *type)
{
assert(PyList_Check(g_type_modified_events));
PyObject *list = PyList_New(0);
if (!list) {
return -1;
}
if (PyList_Append(list, (PyObject *)type) < 0) {
Py_DECREF(list);
return -1;
}
if (PyList_Append(g_type_modified_events, list) < 0) {
Py_DECREF(list);
return -1;
}
Py_DECREF(list);
return 0;
}
static int
type_modified_callback_error(PyTypeObject *type)
{
PyErr_SetString(PyExc_RuntimeError, "boom!");
return -1;
}
static PyObject *
add_type_watcher(PyObject *self, PyObject *kind)
{
int watcher_id;
assert(PyLong_Check(kind));
long kind_l = PyLong_AsLong(kind);
if (kind_l == 2) {
watcher_id = PyType_AddWatcher(type_modified_callback_wrap);
} else if (kind_l == 1) {
watcher_id = PyType_AddWatcher(type_modified_callback_error);
} else {
watcher_id = PyType_AddWatcher(type_modified_callback);
}
if (watcher_id < 0) {
return NULL;
}
if (!g_type_watchers_installed) {
assert(!g_type_modified_events);
if (!(g_type_modified_events = PyList_New(0))) {
return NULL;
}
}
g_type_watchers_installed++;
return PyLong_FromLong(watcher_id);
}
static PyObject *
clear_type_watcher(PyObject *self, PyObject *watcher_id)
{
if (PyType_ClearWatcher(PyLong_AsLong(watcher_id))) {
return NULL;
}
g_type_watchers_installed--;
if (!g_type_watchers_installed) {
assert(g_type_modified_events);
Py_CLEAR(g_type_modified_events);
}
Py_RETURN_NONE;
}
static PyObject *
get_type_modified_events(PyObject *self, PyObject *Py_UNUSED(args))
{
if (!g_type_modified_events) {
PyErr_SetString(PyExc_RuntimeError, "no watchers active");
return NULL;
}
Py_INCREF(g_type_modified_events);
return g_type_modified_events;
}
static PyObject *
watch_type(PyObject *self, PyObject *args)
{
PyObject *type;
int watcher_id;
if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) {
return NULL;
}
if (PyType_Watch(watcher_id, type)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
unwatch_type(PyObject *self, PyObject *args)
{
PyObject *type;
int watcher_id;
if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) {
return NULL;
}
if (PyType_Unwatch(watcher_id, type)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*);
static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*);
@ -5981,6 +6103,11 @@ static PyMethodDef TestMethods[] = {
{"function_get_code", function_get_code, METH_O, NULL},
{"function_get_globals", function_get_globals, METH_O, NULL},
{"function_get_module", function_get_module, METH_O, NULL},
{"add_type_watcher", add_type_watcher, METH_O, NULL},
{"clear_type_watcher", clear_type_watcher, METH_O, NULL},
{"watch_type", watch_type, METH_VARARGS, NULL},
{"unwatch_type", unwatch_type, METH_VARARGS, NULL},
{"get_type_modified_events", get_type_modified_events, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};