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