Skip to content

Commit 133e00c

Browse files
committed
fixup! pythongh-127124: Pass optional state to context watcher callback
1 parent c9e95d4 commit 133e00c

File tree

2 files changed

+18
-36
lines changed

2 files changed

+18
-36
lines changed

Lib/test/test_capi/test_watchers.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import contextlib
12
import unittest
23
import contextvars
34

@@ -639,16 +640,19 @@ def _in_outer():
639640
def test_clear_out_of_range_watcher_id(self):
640641
with self.assertRaisesRegex(ValueError, r"Invalid context watcher ID -1"):
641642
_testcapi.clear_context_watcher(-1)
642-
with self.assertRaisesRegex(ValueError, r"Invalid context watcher ID 8"):
643-
_testcapi.clear_context_watcher(8) # CONTEXT_MAX_WATCHERS = 8
643+
with self.assertRaisesRegex(ValueError, f"Invalid context watcher ID {_testcapi.CONTEXT_MAX_WATCHERS}"):
644+
_testcapi.clear_context_watcher(_testcapi.CONTEXT_MAX_WATCHERS)
644645

645646
def test_clear_unassigned_watcher_id(self):
646647
with self.assertRaisesRegex(ValueError, r"No context watcher set for ID 1"):
647648
_testcapi.clear_context_watcher(1)
648649

649650
def test_allocate_too_many_watchers(self):
650-
with self.assertRaisesRegex(RuntimeError, r"no more context watcher IDs available"):
651-
_testcapi.allocate_too_many_context_watchers()
651+
with contextlib.ExitStack() as stack:
652+
for i in range(_testcapi.CONTEXT_MAX_WATCHERS):
653+
stack.enter_context(self.context_watcher())
654+
with self.assertRaisesRegex(RuntimeError, r"no more context watcher IDs available"):
655+
stack.enter_context(self.context_watcher())
652656

653657
def test_exit_base_context(self):
654658
ctx = contextvars.Context()

Modules/_testcapi/watchers.c

+10-32
Original file line numberDiff line numberDiff line change
@@ -710,36 +710,6 @@ clear_context_stack(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
710710
Py_RETURN_NONE;
711711
}
712712

713-
static PyObject *
714-
allocate_too_many_context_watchers(PyObject *self, PyObject *args)
715-
{
716-
int watcher_ids[CONTEXT_MAX_WATCHERS + 1];
717-
int num_watchers = 0;
718-
for (unsigned long i = 0; i < sizeof(watcher_ids) / sizeof(int); i++) {
719-
int watcher_id = PyContext_AddWatcher(&context_watcher, NULL);
720-
if (watcher_id == -1) {
721-
break;
722-
}
723-
watcher_ids[i] = watcher_id;
724-
num_watchers++;
725-
}
726-
PyObject *exc = PyErr_GetRaisedException();
727-
for (int i = 0; i < num_watchers; i++) {
728-
if (PyContext_ClearWatcher(watcher_ids[i]) < 0) {
729-
PyErr_WriteUnraisable(Py_None);
730-
break;
731-
}
732-
}
733-
if (exc) {
734-
PyErr_SetRaisedException(exc);
735-
return NULL;
736-
}
737-
else if (PyErr_Occurred()) {
738-
return NULL;
739-
}
740-
Py_RETURN_NONE;
741-
}
742-
743713
/*[clinic input]
744714
_testcapi.set_func_defaults_via_capi
745715
func: object
@@ -812,8 +782,6 @@ static PyMethodDef test_methods[] = {
812782
_TESTCAPI_ADD_CONTEXT_WATCHER_METHODDEF
813783
_TESTCAPI_CLEAR_CONTEXT_WATCHER_METHODDEF
814784
{"clear_context_stack", clear_context_stack, METH_NOARGS, NULL},
815-
{"allocate_too_many_context_watchers",
816-
(PyCFunction) allocate_too_many_context_watchers, METH_NOARGS, NULL},
817785
{NULL},
818786
};
819787

@@ -824,6 +792,16 @@ _PyTestCapi_Init_Watchers(PyObject *mod)
824792
return -1;
825793
}
826794

795+
#define ADD_INT_CONST(INT) \
796+
do { \
797+
if (PyModule_AddIntConstant(mod, #INT, INT) < 0) { \
798+
return -1; \
799+
} \
800+
} while(0)
801+
ADD_INT_CONST(CONTEXT_MAX_WATCHERS);
802+
ADD_INT_CONST(Py_CONTEXT_SWITCHED);
803+
#undef ADD_INT_CONST
804+
827805
/* Expose each event as an attribute on the module */
828806
#define ADD_EVENT(event) \
829807
if (add_func_event(mod, "PYFUNC_EVENT_" #event, \

0 commit comments

Comments
 (0)