Skip to content

Commit 4f41506

Browse files
committed
feat: support Task.add_done_callback and Task.remove_done_callback
1 parent f97d965 commit 4f41506

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

extmod/modasyncio.c

+43
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,43 @@ STATIC mp_obj_t task_done(mp_obj_t self_in) {
191191
}
192192
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_done_obj, task_done);
193193

194+
STATIC mp_obj_t task_add_done_callback(mp_obj_t self_in, mp_obj_t callback) {
195+
assert(mp_obj_is_callable(callback));
196+
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
197+
198+
if (TASK_IS_DONE(self)) {
199+
// In CPython the callbacks are not immediately called and are instead
200+
// called by the event loop. However, CircuitPython's event loop doesn't
201+
// support `call_soon` to handle callback processing.
202+
//
203+
// Because of this, it's close enough to call the callback immediately.
204+
mp_call_function_1(callback, self_in);
205+
return mp_const_none;
206+
}
207+
208+
if (self->state != mp_const_true) {
209+
// Tasks SHOULD support more than one callback per CPython but to reduce
210+
// the surface area of this change tasks can currently only support one.
211+
mp_raise_RuntimeError(MP_ERROR_TEXT("Tasks only support one done callback."));
212+
}
213+
214+
self->state = callback;
215+
return mp_const_none;
216+
}
217+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_add_done_callback_obj, task_add_done_callback);
218+
219+
STATIC mp_obj_t task_remove_done_callback(mp_obj_t self_in, mp_obj_t callback) {
220+
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
221+
222+
if (callback != self->state) {
223+
return mp_obj_new_int(0);
224+
}
225+
226+
self->state = mp_const_true;
227+
return mp_obj_new_int(1);
228+
}
229+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_remove_done_callback_obj, task_remove_done_callback);
230+
194231
STATIC mp_obj_t task_get_coro(mp_obj_t self_in) {
195232
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
196233
return MP_OBJ_FROM_PTR(self->coro);
@@ -350,6 +387,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
350387
} else if (attr == MP_QSTR___await__) {
351388
dest[0] = MP_OBJ_FROM_PTR(&task_await_obj);
352389
dest[1] = self_in;
390+
} else if (attr == MP_QSTR_add_done_callback) {
391+
dest[0] = MP_OBJ_FROM_PTR(&task_add_done_callback_obj);
392+
dest[1] = self_in;
393+
} else if (attr == MP_QSTR_remove_done_callback) {
394+
dest[0] = MP_OBJ_FROM_PTR(&task_remove_done_callback_obj);
395+
dest[1] = self_in;
353396
} else if (attr == MP_QSTR_get_coro) {
354397
dest[0] = MP_OBJ_FROM_PTR(&task_get_coro_obj);
355398
dest[1] = self_in;

locale/circuitpython.pot

+4
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,10 @@ msgstr ""
20082008
msgid "Task does not support set_result operation"
20092009
msgstr ""
20102010

2011+
#: extmod/modasyncio.c
2012+
msgid "Tasks only support one done callback."
2013+
msgstr ""
2014+
20112015
#: ports/stm/common-hal/microcontroller/Processor.c
20122016
msgid "Temperature read timed out"
20132017
msgstr ""

0 commit comments

Comments
 (0)