Skip to content

Commit 0fef362

Browse files
committed
feat: support Task.add_done_callback and Task.remove_done_callback
1 parent 0faefcb commit 0fef362

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

extmod/modasyncio.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,43 @@ STATIC mp_obj_t task_done(mp_obj_t self_in) {
205205
}
206206
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_done_obj, task_done);
207207

208+
STATIC mp_obj_t task_add_done_callback(mp_obj_t self_in, mp_obj_t callback) {
209+
assert(mp_obj_is_callable(callback));
210+
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
211+
212+
if (TASK_IS_DONE(self)) {
213+
// In CPython the callbacks are not immediately called and are instead
214+
// called by the event loop. However, CircuitPython's event loop doesn't
215+
// support `call_soon` to handle callback processing.
216+
//
217+
// Because of this, it's close enough to call the callback immediately.
218+
mp_call_function_1(callback, self_in);
219+
return mp_const_none;
220+
}
221+
222+
if (self->state != mp_const_true) {
223+
// Tasks SHOULD support more than one callback per CPython but to reduce
224+
// the surface area of this change tasks can currently only support one.
225+
mp_raise_RuntimeError(MP_ERROR_TEXT("Tasks only support one done callback."));
226+
}
227+
228+
self->state = callback;
229+
return mp_const_none;
230+
}
231+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_add_done_callback_obj, task_add_done_callback);
232+
233+
STATIC mp_obj_t task_remove_done_callback(mp_obj_t self_in, mp_obj_t callback) {
234+
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
235+
236+
if (callback != self->state) {
237+
return mp_obj_new_int(0);
238+
}
239+
240+
self->state = mp_const_true;
241+
return mp_obj_new_int(1);
242+
}
243+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_remove_done_callback_obj, task_remove_done_callback);
244+
208245
STATIC mp_obj_t task_get_coro(mp_obj_t self_in) {
209246
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
210247
return MP_OBJ_FROM_PTR(self->coro);
@@ -364,6 +401,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
364401
} else if (attr == MP_QSTR___await__) {
365402
dest[0] = MP_OBJ_FROM_PTR(&task_await_obj);
366403
dest[1] = self_in;
404+
} else if (attr == MP_QSTR_add_done_callback) {
405+
dest[0] = MP_OBJ_FROM_PTR(&task_add_done_callback_obj);
406+
dest[1] = self_in;
407+
} else if (attr == MP_QSTR_remove_done_callback) {
408+
dest[0] = MP_OBJ_FROM_PTR(&task_remove_done_callback_obj);
409+
dest[1] = self_in;
367410
} else if (attr == MP_QSTR_get_coro) {
368411
dest[0] = MP_OBJ_FROM_PTR(&task_get_coro_obj);
369412
dest[1] = self_in;

locale/circuitpython.pot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,10 @@ msgstr ""
19791979
msgid "Task does not support set_result operation"
19801980
msgstr ""
19811981

1982+
#: extmod/modasyncio.c
1983+
msgid "Tasks only support one done callback."
1984+
msgstr ""
1985+
19821986
#: ports/stm/common-hal/microcontroller/Processor.c
19831987
msgid "Temperature read timed out"
19841988
msgstr ""

0 commit comments

Comments
 (0)