(root)/
Python-3.12.0/
Modules/
_testcapi/
watchers.c
       1  #include "parts.h"
       2  
       3  #include "clinic/watchers.c.h"
       4  
       5  #define Py_BUILD_CORE
       6  #include "pycore_function.h"  // FUNC_MAX_WATCHERS
       7  #include "pycore_code.h"  // CODE_MAX_WATCHERS
       8  
       9  /*[clinic input]
      10  module _testcapi
      11  [clinic start generated code]*/
      12  /*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/
      13  
      14  // Test dict watching
      15  static PyObject *g_dict_watch_events;
      16  static int g_dict_watchers_installed;
      17  
      18  static int
      19  dict_watch_callback(PyDict_WatchEvent event,
      20                      PyObject *dict,
      21                      PyObject *key,
      22                      PyObject *new_value)
      23  {
      24      PyObject *msg;
      25      switch (event) {
      26          case PyDict_EVENT_CLEARED:
      27              msg = PyUnicode_FromString("clear");
      28              break;
      29          case PyDict_EVENT_DEALLOCATED:
      30              msg = PyUnicode_FromString("dealloc");
      31              break;
      32          case PyDict_EVENT_CLONED:
      33              msg = PyUnicode_FromString("clone");
      34              break;
      35          case PyDict_EVENT_ADDED:
      36              msg = PyUnicode_FromFormat("new:%S:%S", key, new_value);
      37              break;
      38          case PyDict_EVENT_MODIFIED:
      39              msg = PyUnicode_FromFormat("mod:%S:%S", key, new_value);
      40              break;
      41          case PyDict_EVENT_DELETED:
      42              msg = PyUnicode_FromFormat("del:%S", key);
      43              break;
      44          default:
      45              msg = PyUnicode_FromString("unknown");
      46      }
      47      if (msg == NULL) {
      48          return -1;
      49      }
      50      assert(PyList_Check(g_dict_watch_events));
      51      if (PyList_Append(g_dict_watch_events, msg) < 0) {
      52          Py_DECREF(msg);
      53          return -1;
      54      }
      55      Py_DECREF(msg);
      56      return 0;
      57  }
      58  
      59  static int
      60  dict_watch_callback_second(PyDict_WatchEvent event,
      61                             PyObject *dict,
      62                             PyObject *key,
      63                             PyObject *new_value)
      64  {
      65      PyObject *msg = PyUnicode_FromString("second");
      66      if (msg == NULL) {
      67          return -1;
      68      }
      69      int rc = PyList_Append(g_dict_watch_events, msg);
      70      Py_DECREF(msg);
      71      if (rc < 0) {
      72          return -1;
      73      }
      74      return 0;
      75  }
      76  
      77  static int
      78  dict_watch_callback_error(PyDict_WatchEvent event,
      79                            PyObject *dict,
      80                            PyObject *key,
      81                            PyObject *new_value)
      82  {
      83      PyErr_SetString(PyExc_RuntimeError, "boom!");
      84      return -1;
      85  }
      86  
      87  static PyObject *
      88  add_dict_watcher(PyObject *self, PyObject *kind)
      89  {
      90      int watcher_id;
      91      assert(PyLong_Check(kind));
      92      long kind_l = PyLong_AsLong(kind);
      93      if (kind_l == 2) {
      94          watcher_id = PyDict_AddWatcher(dict_watch_callback_second);
      95      }
      96      else if (kind_l == 1) {
      97          watcher_id = PyDict_AddWatcher(dict_watch_callback_error);
      98      }
      99      else {
     100          watcher_id = PyDict_AddWatcher(dict_watch_callback);
     101      }
     102      if (watcher_id < 0) {
     103          return NULL;
     104      }
     105      if (!g_dict_watchers_installed) {
     106          assert(!g_dict_watch_events);
     107          if (!(g_dict_watch_events = PyList_New(0))) {
     108              return NULL;
     109          }
     110      }
     111      g_dict_watchers_installed++;
     112      return PyLong_FromLong(watcher_id);
     113  }
     114  
     115  static PyObject *
     116  clear_dict_watcher(PyObject *self, PyObject *watcher_id)
     117  {
     118      if (PyDict_ClearWatcher(PyLong_AsLong(watcher_id))) {
     119          return NULL;
     120      }
     121      g_dict_watchers_installed--;
     122      if (!g_dict_watchers_installed) {
     123          assert(g_dict_watch_events);
     124          Py_CLEAR(g_dict_watch_events);
     125      }
     126      Py_RETURN_NONE;
     127  }
     128  
     129  /*[clinic input]
     130  _testcapi.watch_dict
     131      watcher_id: int
     132      dict: object
     133      /
     134  [clinic start generated code]*/
     135  
     136  static PyObject *
     137  _testcapi_watch_dict_impl(PyObject *module, int watcher_id, PyObject *dict)
     138  /*[clinic end generated code: output=1426e0273cebe2d8 input=269b006d60c358bd]*/
     139  {
     140      if (PyDict_Watch(watcher_id, dict)) {
     141          return NULL;
     142      }
     143      Py_RETURN_NONE;
     144  }
     145  
     146  /*[clinic input]
     147  _testcapi.unwatch_dict = _testcapi.watch_dict
     148  [clinic start generated code]*/
     149  
     150  static PyObject *
     151  _testcapi_unwatch_dict_impl(PyObject *module, int watcher_id, PyObject *dict)
     152  /*[clinic end generated code: output=512b1a71ae33c351 input=cae7dc1b6f7713b8]*/
     153  {
     154      if (PyDict_Unwatch(watcher_id, dict)) {
     155          return NULL;
     156      }
     157      Py_RETURN_NONE;
     158  }
     159  
     160  static PyObject *
     161  get_dict_watcher_events(PyObject *self, PyObject *Py_UNUSED(args))
     162  {
     163      if (!g_dict_watch_events) {
     164          PyErr_SetString(PyExc_RuntimeError, "no watchers active");
     165          return NULL;
     166      }
     167      return Py_NewRef(g_dict_watch_events);
     168  }
     169  
     170  // Test type watchers
     171  static PyObject *g_type_modified_events;
     172  static int g_type_watchers_installed;
     173  
     174  static int
     175  type_modified_callback(PyTypeObject *type)
     176  {
     177      assert(PyList_Check(g_type_modified_events));
     178      if(PyList_Append(g_type_modified_events, (PyObject *)type) < 0) {
     179          return -1;
     180      }
     181      return 0;
     182  }
     183  
     184  static int
     185  type_modified_callback_wrap(PyTypeObject *type)
     186  {
     187      assert(PyList_Check(g_type_modified_events));
     188      PyObject *list = PyList_New(0);
     189      if (list == NULL) {
     190          return -1;
     191      }
     192      if (PyList_Append(list, (PyObject *)type) < 0) {
     193          Py_DECREF(list);
     194          return -1;
     195      }
     196      if (PyList_Append(g_type_modified_events, list) < 0) {
     197          Py_DECREF(list);
     198          return -1;
     199      }
     200      Py_DECREF(list);
     201      return 0;
     202  }
     203  
     204  static int
     205  type_modified_callback_error(PyTypeObject *type)
     206  {
     207      PyErr_SetString(PyExc_RuntimeError, "boom!");
     208      return -1;
     209  }
     210  
     211  static PyObject *
     212  add_type_watcher(PyObject *self, PyObject *kind)
     213  {
     214      int watcher_id;
     215      assert(PyLong_Check(kind));
     216      long kind_l = PyLong_AsLong(kind);
     217      if (kind_l == 2) {
     218          watcher_id = PyType_AddWatcher(type_modified_callback_wrap);
     219      }
     220      else if (kind_l == 1) {
     221          watcher_id = PyType_AddWatcher(type_modified_callback_error);
     222      }
     223      else {
     224          watcher_id = PyType_AddWatcher(type_modified_callback);
     225      }
     226      if (watcher_id < 0) {
     227          return NULL;
     228      }
     229      if (!g_type_watchers_installed) {
     230          assert(!g_type_modified_events);
     231          if (!(g_type_modified_events = PyList_New(0))) {
     232              return NULL;
     233          }
     234      }
     235      g_type_watchers_installed++;
     236      return PyLong_FromLong(watcher_id);
     237  }
     238  
     239  static PyObject *
     240  clear_type_watcher(PyObject *self, PyObject *watcher_id)
     241  {
     242      if (PyType_ClearWatcher(PyLong_AsLong(watcher_id))) {
     243          return NULL;
     244      }
     245      g_type_watchers_installed--;
     246      if (!g_type_watchers_installed) {
     247          assert(g_type_modified_events);
     248          Py_CLEAR(g_type_modified_events);
     249      }
     250      Py_RETURN_NONE;
     251  }
     252  
     253  static PyObject *
     254  get_type_modified_events(PyObject *self, PyObject *Py_UNUSED(args))
     255  {
     256      if (!g_type_modified_events) {
     257          PyErr_SetString(PyExc_RuntimeError, "no watchers active");
     258          return NULL;
     259      }
     260      return Py_NewRef(g_type_modified_events);
     261  }
     262  
     263  /*[clinic input]
     264  _testcapi.watch_type
     265      watcher_id: int
     266      type: object
     267      /
     268  [clinic start generated code]*/
     269  
     270  static PyObject *
     271  _testcapi_watch_type_impl(PyObject *module, int watcher_id, PyObject *type)
     272  /*[clinic end generated code: output=fdf4777126724fc4 input=5a808bf12be7e3ed]*/
     273  {
     274      if (PyType_Watch(watcher_id, type)) {
     275          return NULL;
     276      }
     277      Py_RETURN_NONE;
     278  }
     279  
     280  /*[clinic input]
     281  _testcapi.unwatch_type = _testcapi.watch_type
     282  [clinic start generated code]*/
     283  
     284  static PyObject *
     285  _testcapi_unwatch_type_impl(PyObject *module, int watcher_id, PyObject *type)
     286  /*[clinic end generated code: output=0389672d4ad5f68b input=6701911fb45edc9e]*/
     287  {
     288      if (PyType_Unwatch(watcher_id, type)) {
     289          return NULL;
     290      }
     291      Py_RETURN_NONE;
     292  }
     293  
     294  
     295  // Test code object watching
     296  
     297  #define NUM_CODE_WATCHERS 2
     298  static int code_watcher_ids[NUM_CODE_WATCHERS] = {-1, -1};
     299  static int num_code_object_created_events[NUM_CODE_WATCHERS] = {0, 0};
     300  static int num_code_object_destroyed_events[NUM_CODE_WATCHERS] = {0, 0};
     301  
     302  static int
     303  handle_code_object_event(int which_watcher, PyCodeEvent event, PyCodeObject *co) {
     304      if (event == PY_CODE_EVENT_CREATE) {
     305          num_code_object_created_events[which_watcher]++;
     306      }
     307      else if (event == PY_CODE_EVENT_DESTROY) {
     308          num_code_object_destroyed_events[which_watcher]++;
     309      }
     310      else {
     311          return -1;
     312      }
     313      return 0;
     314  }
     315  
     316  static int
     317  first_code_object_callback(PyCodeEvent event, PyCodeObject *co)
     318  {
     319      return handle_code_object_event(0, event, co);
     320  }
     321  
     322  static int
     323  second_code_object_callback(PyCodeEvent event, PyCodeObject *co)
     324  {
     325      return handle_code_object_event(1, event, co);
     326  }
     327  
     328  static int
     329  noop_code_event_handler(PyCodeEvent event, PyCodeObject *co)
     330  {
     331      return 0;
     332  }
     333  
     334  static int
     335  error_code_event_handler(PyCodeEvent event, PyCodeObject *co)
     336  {
     337      PyErr_SetString(PyExc_RuntimeError, "boom!");
     338      return -1;
     339  }
     340  
     341  static PyObject *
     342  add_code_watcher(PyObject *self, PyObject *which_watcher)
     343  {
     344      int watcher_id;
     345      assert(PyLong_Check(which_watcher));
     346      long which_l = PyLong_AsLong(which_watcher);
     347      if (which_l == 0) {
     348          watcher_id = PyCode_AddWatcher(first_code_object_callback);
     349          code_watcher_ids[0] = watcher_id;
     350          num_code_object_created_events[0] = 0;
     351          num_code_object_destroyed_events[0] = 0;
     352      }
     353      else if (which_l == 1) {
     354          watcher_id = PyCode_AddWatcher(second_code_object_callback);
     355          code_watcher_ids[1] = watcher_id;
     356          num_code_object_created_events[1] = 0;
     357          num_code_object_destroyed_events[1] = 0;
     358      }
     359      else if (which_l == 2) {
     360          watcher_id = PyCode_AddWatcher(error_code_event_handler);
     361      }
     362      else {
     363          PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l);
     364          return NULL;
     365      }
     366      if (watcher_id < 0) {
     367          return NULL;
     368      }
     369      return PyLong_FromLong(watcher_id);
     370  }
     371  
     372  static PyObject *
     373  clear_code_watcher(PyObject *self, PyObject *watcher_id)
     374  {
     375      assert(PyLong_Check(watcher_id));
     376      long watcher_id_l = PyLong_AsLong(watcher_id);
     377      if (PyCode_ClearWatcher(watcher_id_l) < 0) {
     378          return NULL;
     379      }
     380      // reset static events counters
     381      if (watcher_id_l >= 0) {
     382          for (int i = 0; i < NUM_CODE_WATCHERS; i++) {
     383              if (watcher_id_l == code_watcher_ids[i]) {
     384                  code_watcher_ids[i] = -1;
     385                  num_code_object_created_events[i] = 0;
     386                  num_code_object_destroyed_events[i] = 0;
     387              }
     388          }
     389      }
     390      Py_RETURN_NONE;
     391  }
     392  
     393  static PyObject *
     394  get_code_watcher_num_created_events(PyObject *self, PyObject *watcher_id)
     395  {
     396      assert(PyLong_Check(watcher_id));
     397      long watcher_id_l = PyLong_AsLong(watcher_id);
     398      assert(watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS);
     399      return PyLong_FromLong(num_code_object_created_events[watcher_id_l]);
     400  }
     401  
     402  static PyObject *
     403  get_code_watcher_num_destroyed_events(PyObject *self, PyObject *watcher_id)
     404  {
     405      assert(PyLong_Check(watcher_id));
     406      long watcher_id_l = PyLong_AsLong(watcher_id);
     407      assert(watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS);
     408      return PyLong_FromLong(num_code_object_destroyed_events[watcher_id_l]);
     409  }
     410  
     411  static PyObject *
     412  allocate_too_many_code_watchers(PyObject *self, PyObject *args)
     413  {
     414      int watcher_ids[CODE_MAX_WATCHERS + 1];
     415      int num_watchers = 0;
     416      for (unsigned long i = 0; i < sizeof(watcher_ids) / sizeof(int); i++) {
     417          int watcher_id = PyCode_AddWatcher(noop_code_event_handler);
     418          if (watcher_id == -1) {
     419              break;
     420          }
     421          watcher_ids[i] = watcher_id;
     422          num_watchers++;
     423      }
     424      PyObject *exc = PyErr_GetRaisedException();
     425      for (int i = 0; i < num_watchers; i++) {
     426          if (PyCode_ClearWatcher(watcher_ids[i]) < 0) {
     427              PyErr_WriteUnraisable(Py_None);
     428              break;
     429          }
     430      }
     431      if (exc) {
     432          PyErr_SetRaisedException(exc);
     433          return NULL;
     434      }
     435      else if (PyErr_Occurred()) {
     436          return NULL;
     437      }
     438      Py_RETURN_NONE;
     439  }
     440  
     441  // Test function watchers
     442  
     443  #define NUM_TEST_FUNC_WATCHERS 2
     444  static PyObject *pyfunc_watchers[NUM_TEST_FUNC_WATCHERS];
     445  static int func_watcher_ids[NUM_TEST_FUNC_WATCHERS] = {-1, -1};
     446  
     447  static PyObject *
     448  get_id(PyObject *obj)
     449  {
     450      PyObject *builtins = PyEval_GetBuiltins();  // borrowed ref.
     451      if (builtins == NULL) {
     452          return NULL;
     453      }
     454      PyObject *id_str = PyUnicode_FromString("id");
     455      if (id_str == NULL) {
     456          return NULL;
     457      }
     458      PyObject *id_func = PyObject_GetItem(builtins, id_str);
     459      Py_DECREF(id_str);
     460      if (id_func == NULL) {
     461          return NULL;
     462      }
     463      PyObject *stack[] = {obj};
     464      PyObject *id = PyObject_Vectorcall(id_func, stack, 1, NULL);
     465      Py_DECREF(id_func);
     466      return id;
     467  }
     468  
     469  static int
     470  call_pyfunc_watcher(PyObject *watcher, PyFunction_WatchEvent event,
     471                      PyFunctionObject *func, PyObject *new_value)
     472  {
     473      PyObject *event_obj = PyLong_FromLong(event);
     474      if (event_obj == NULL) {
     475          return -1;
     476      }
     477      if (new_value == NULL) {
     478          new_value = Py_None;
     479      }
     480      Py_INCREF(new_value);
     481      PyObject *func_or_id = NULL;
     482      if (event == PyFunction_EVENT_DESTROY) {
     483          /* Don't expose a function that's about to be destroyed to managed code */
     484          func_or_id = get_id((PyObject *) func);
     485          if (func_or_id == NULL) {
     486              Py_DECREF(event_obj);
     487              Py_DECREF(new_value);
     488              return -1;
     489          }
     490      }
     491      else {
     492          Py_INCREF(func);
     493          func_or_id = (PyObject *) func;
     494      }
     495      PyObject *stack[] = {event_obj, func_or_id, new_value};
     496      PyObject *res = PyObject_Vectorcall(watcher, stack, 3, NULL);
     497      int st = (res == NULL) ? -1 : 0;
     498      Py_XDECREF(res);
     499      Py_DECREF(new_value);
     500      Py_DECREF(event_obj);
     501      Py_DECREF(func_or_id);
     502      return st;
     503  }
     504  
     505  static int
     506  first_func_watcher_callback(PyFunction_WatchEvent event, PyFunctionObject *func,
     507                              PyObject *new_value)
     508  {
     509      return call_pyfunc_watcher(pyfunc_watchers[0], event, func, new_value);
     510  }
     511  
     512  static int
     513  second_func_watcher_callback(PyFunction_WatchEvent event,
     514                               PyFunctionObject *func, PyObject *new_value)
     515  {
     516      return call_pyfunc_watcher(pyfunc_watchers[1], event, func, new_value);
     517  }
     518  
     519  static PyFunction_WatchCallback func_watcher_callbacks[NUM_TEST_FUNC_WATCHERS] = {
     520      first_func_watcher_callback,
     521      second_func_watcher_callback
     522  };
     523  
     524  static int
     525  add_func_event(PyObject *module, const char *name, PyFunction_WatchEvent event)
     526  {
     527      PyObject *value = PyLong_FromLong(event);
     528      if (value == NULL) {
     529          return -1;
     530      }
     531      int ok = PyModule_AddObjectRef(module, name, value);
     532      Py_DECREF(value);
     533      return ok;
     534  }
     535  
     536  static PyObject *
     537  add_func_watcher(PyObject *self, PyObject *func)
     538  {
     539      if (!PyFunction_Check(func)) {
     540          PyErr_SetString(PyExc_TypeError, "'func' must be a function");
     541          return NULL;
     542      }
     543      int idx = -1;
     544      for (int i = 0; i < NUM_TEST_FUNC_WATCHERS; i++) {
     545          if (func_watcher_ids[i] == -1) {
     546              idx = i;
     547              break;
     548          }
     549      }
     550      if (idx == -1) {
     551          PyErr_SetString(PyExc_RuntimeError, "no free test watchers");
     552          return NULL;
     553      }
     554      func_watcher_ids[idx] = PyFunction_AddWatcher(func_watcher_callbacks[idx]);
     555      if (func_watcher_ids[idx] < 0) {
     556          return NULL;
     557      }
     558      pyfunc_watchers[idx] = Py_NewRef(func);
     559      PyObject *result = PyLong_FromLong(func_watcher_ids[idx]);
     560      if (result == NULL) {
     561          return NULL;
     562      }
     563      return result;
     564  }
     565  
     566  static PyObject *
     567  clear_func_watcher(PyObject *self, PyObject *watcher_id_obj)
     568  {
     569      long watcher_id = PyLong_AsLong(watcher_id_obj);
     570      if ((watcher_id < INT_MIN) || (watcher_id > INT_MAX)) {
     571          PyErr_SetString(PyExc_ValueError, "invalid watcher ID");
     572          return NULL;
     573      }
     574      int wid = (int) watcher_id;
     575      if (PyFunction_ClearWatcher(wid) < 0) {
     576          return NULL;
     577      }
     578      int idx = -1;
     579      for (int i = 0; i < NUM_TEST_FUNC_WATCHERS; i++) {
     580          if (func_watcher_ids[i] == wid) {
     581              idx = i;
     582              break;
     583          }
     584      }
     585      assert(idx != -1);
     586      Py_CLEAR(pyfunc_watchers[idx]);
     587      func_watcher_ids[idx] = -1;
     588      Py_RETURN_NONE;
     589  }
     590  
     591  static int
     592  noop_func_event_handler(PyFunction_WatchEvent event, PyFunctionObject *func,
     593               PyObject *new_value)
     594  {
     595      return 0;
     596  }
     597  
     598  static PyObject *
     599  allocate_too_many_func_watchers(PyObject *self, PyObject *args)
     600  {
     601      int watcher_ids[FUNC_MAX_WATCHERS + 1];
     602      int num_watchers = 0;
     603      for (unsigned long i = 0; i < sizeof(watcher_ids) / sizeof(int); i++) {
     604          int watcher_id = PyFunction_AddWatcher(noop_func_event_handler);
     605          if (watcher_id == -1) {
     606              break;
     607          }
     608          watcher_ids[i] = watcher_id;
     609          num_watchers++;
     610      }
     611      PyObject *exc = PyErr_GetRaisedException();
     612      for (int i = 0; i < num_watchers; i++) {
     613          if (PyFunction_ClearWatcher(watcher_ids[i]) < 0) {
     614              PyErr_WriteUnraisable(Py_None);
     615              break;
     616          }
     617      }
     618      if (exc) {
     619          PyErr_SetRaisedException(exc);
     620          return NULL;
     621      }
     622      else if (PyErr_Occurred()) {
     623          return NULL;
     624      }
     625      Py_RETURN_NONE;
     626  }
     627  
     628  /*[clinic input]
     629  _testcapi.set_func_defaults_via_capi
     630      func: object
     631      defaults: object
     632      /
     633  [clinic start generated code]*/
     634  
     635  static PyObject *
     636  _testcapi_set_func_defaults_via_capi_impl(PyObject *module, PyObject *func,
     637                                            PyObject *defaults)
     638  /*[clinic end generated code: output=caf0cb39db31ac24 input=e04a8508ca9d42fc]*/
     639  {
     640      if (PyFunction_SetDefaults(func, defaults) < 0) {
     641          return NULL;
     642      }
     643      Py_RETURN_NONE;
     644  }
     645  
     646  /*[clinic input]
     647  _testcapi.set_func_kwdefaults_via_capi = _testcapi.set_func_defaults_via_capi
     648  [clinic start generated code]*/
     649  
     650  static PyObject *
     651  _testcapi_set_func_kwdefaults_via_capi_impl(PyObject *module, PyObject *func,
     652                                              PyObject *defaults)
     653  /*[clinic end generated code: output=9ed3b08177025070 input=f3cd1ca3c18de8ce]*/
     654  {
     655      if (PyFunction_SetKwDefaults(func, defaults) < 0) {
     656          return NULL;
     657      }
     658      Py_RETURN_NONE;
     659  }
     660  
     661  static PyMethodDef test_methods[] = {
     662      // Dict watchers.
     663      {"add_dict_watcher",         add_dict_watcher,        METH_O,       NULL},
     664      {"clear_dict_watcher",       clear_dict_watcher,      METH_O,       NULL},
     665      _TESTCAPI_WATCH_DICT_METHODDEF
     666      _TESTCAPI_UNWATCH_DICT_METHODDEF
     667      {"get_dict_watcher_events",
     668       (PyCFunction) get_dict_watcher_events,               METH_NOARGS,  NULL},
     669  
     670      // Type watchers.
     671      {"add_type_watcher",         add_type_watcher,        METH_O,       NULL},
     672      {"clear_type_watcher",       clear_type_watcher,      METH_O,       NULL},
     673      _TESTCAPI_WATCH_TYPE_METHODDEF
     674      _TESTCAPI_UNWATCH_TYPE_METHODDEF
     675      {"get_type_modified_events",
     676       (PyCFunction) get_type_modified_events,              METH_NOARGS, NULL},
     677  
     678      // Code object watchers.
     679      {"add_code_watcher",         add_code_watcher,        METH_O,       NULL},
     680      {"clear_code_watcher",       clear_code_watcher,      METH_O,       NULL},
     681      {"get_code_watcher_num_created_events",
     682       get_code_watcher_num_created_events,                 METH_O,       NULL},
     683      {"get_code_watcher_num_destroyed_events",
     684       get_code_watcher_num_destroyed_events,               METH_O,       NULL},
     685      {"allocate_too_many_code_watchers",
     686       (PyCFunction) allocate_too_many_code_watchers,       METH_NOARGS,  NULL},
     687  
     688      // Function watchers.
     689      {"add_func_watcher",         add_func_watcher,        METH_O,       NULL},
     690      {"clear_func_watcher",       clear_func_watcher,      METH_O,       NULL},
     691      _TESTCAPI_SET_FUNC_DEFAULTS_VIA_CAPI_METHODDEF
     692      _TESTCAPI_SET_FUNC_KWDEFAULTS_VIA_CAPI_METHODDEF
     693      {"allocate_too_many_func_watchers", allocate_too_many_func_watchers,
     694       METH_NOARGS, NULL},
     695      {NULL},
     696  };
     697  
     698  int
     699  _PyTestCapi_Init_Watchers(PyObject *mod)
     700  {
     701      if (PyModule_AddFunctions(mod, test_methods) < 0) {
     702          return -1;
     703      }
     704  
     705      /* Expose each event as an attribute on the module */
     706  #define ADD_EVENT(event)  \
     707      if (add_func_event(mod, "PYFUNC_EVENT_" #event,   \
     708                         PyFunction_EVENT_##event)) {   \
     709          return -1;                                    \
     710      }
     711      PY_FOREACH_FUNC_EVENT(ADD_EVENT);
     712  #undef ADD_EVENT
     713  
     714      return 0;
     715  }