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