Skip to content

Commit 300f2fc

Browse files
committed
gh-124872: Change PyContext_WatchCallback return type to void
The callback cannot prevent the event from occurring by raising an exception. Nor should it be able to; any failure to switch contexts would be difficult if not impossible to handle correctly. The API should reflect that the callback is purely informational, and that the context switch will happen even if the callback doesn't want it to.
1 parent 4c115ab commit 300f2fc

File tree

4 files changed

+16
-21
lines changed

4 files changed

+16
-21
lines changed

Doc/c-api/contextvars.rst

+3-5
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,16 @@ Context object management functions:
136136
137137
.. versionadded:: 3.14
138138
139-
.. c:type:: int (*PyContext_WatchCallback)(PyContextEvent event, PyObject *obj)
139+
.. c:type:: void (*PyContext_WatchCallback)(PyContextEvent event, PyObject *obj)
140140
141141
Context object watcher callback function. The object passed to the callback
142142
is event-specific; see :c:type:`PyContextEvent` for details.
143143
144144
Any pending exception is cleared before the callback is called and restored
145145
after the callback returns.
146146
147-
If the callback raises an exception it must return ``-1``; the exception
148-
will be printed as an unraisable exception using
149-
:c:func:`PyErr_FormatUnraisable` and discarded. Otherwise it must return
150-
``0``.
147+
If the callback raises an exception it will be printed as an unraisable
148+
exception using :c:func`PyErr_FormatUnraisable` and discarded.
151149
152150
.. versionadded:: 3.14
153151

Include/cpython/context.h

+3-4
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,10 @@ typedef enum {
5252
* Any pending exception is cleared before the callback is called and restored
5353
* after the callback returns.
5454
*
55-
* If the callback raises an exception it must return -1; the exception will be
56-
* printed as an unraisable exception using PyErr_FormatUnraisable and
57-
* discarded. Otherwise it must return 0.
55+
* If the callback raises an exception it will be printed as an unraisable
56+
* exception using PyErr_FormatUnraisable and discarded.
5857
*/
59-
typedef int (*PyContext_WatchCallback)(PyContextEvent, PyObject *);
58+
typedef void (*PyContext_WatchCallback)(PyContextEvent, PyObject *);
6059

6160
/*
6261
* Register a per-interpreter callback that will be invoked for context object

Modules/_testcapi/watchers.c

+8-11
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ static int context_watcher_ids[NUM_CONTEXT_WATCHERS] = {-1, -1};
629629
static int num_context_object_enter_events[NUM_CONTEXT_WATCHERS] = {0, 0};
630630
static int num_context_object_exit_events[NUM_CONTEXT_WATCHERS] = {0, 0};
631631

632-
static int
632+
static void
633633
handle_context_watcher_event(int which_watcher, PyContextEvent event, PyObject *ctx) {
634634
if (event == Py_CONTEXT_EVENT_ENTER) {
635635
num_context_object_enter_events[which_watcher]++;
@@ -638,30 +638,27 @@ handle_context_watcher_event(int which_watcher, PyContextEvent event, PyObject *
638638
num_context_object_exit_events[which_watcher]++;
639639
}
640640
else {
641-
return -1;
641+
Py_UNREACHABLE();
642642
}
643-
return 0;
644643
}
645644

646-
static int
645+
static void
647646
first_context_watcher_callback(PyContextEvent event, PyObject *ctx) {
648-
return handle_context_watcher_event(0, event, ctx);
647+
handle_context_watcher_event(0, event, ctx);
649648
}
650649

651-
static int
650+
static void
652651
second_context_watcher_callback(PyContextEvent event, PyObject *ctx) {
653-
return handle_context_watcher_event(1, event, ctx);
652+
handle_context_watcher_event(1, event, ctx);
654653
}
655654

656-
static int
655+
static void
657656
noop_context_event_handler(PyContextEvent event, PyObject *ctx) {
658-
return 0;
659657
}
660658

661-
static int
659+
static void
662660
error_context_event_handler(PyContextEvent event, PyObject *ctx) {
663661
PyErr_SetString(PyExc_RuntimeError, "boom!");
664-
return -1;
665662
}
666663

667664
static PyObject *

Python/context.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx)
126126
PyContext_WatchCallback cb = interp->context_watchers[i];
127127
assert(cb != NULL);
128128
PyObject *exc = _PyErr_GetRaisedException(ts);
129-
if (cb(event, ctx) < 0) {
129+
cb(event, ctx);
130+
if (_PyErr_Occurred(ts) != NULL) {
130131
PyErr_FormatUnraisable(
131132
"Exception ignored in %s watcher callback for %R",
132133
context_event_name(event), ctx);

0 commit comments

Comments
 (0)