I would like to wait to asynchronous jupyter widget events while the cell is blocked executing async code (thus, usually idle, waiting for I/O, utilising the %autowait
magic). Unfortunately, the jupyter notebook does not seem to send any traitlet events while the cell is blocking. The documentation above circumvents this, by sending the callback into the "background", so it can react after the cell has finished executing. I would like to avoid that, because it make reasoning about background tasks harder than it needs to be; it's precisely against the principles of my favourite async event loop in python: trio. Is there a way to make that work?
Here is the example from the jupyter docs adapted to trio (though it fails the same way with asyncio):
import trio
from IPython.display import display
from ipywidgets import IntSlider, Output
%autoawait trio
async def wait_for_change(widget, attribute):
result = None
evt = trio.Event()
def value_changed(change):
nonlocal result
result = change
evt.set()
widget.observe(value_changed, attribute)
try:
await evt.wait()
finally:
widget.unobserve(value_changed, attribute)
return result
slider = IntSlider()
out = Output()
display(slider)
display(out)
# at this point, the widgets are visible
for i in range(10):
out.append_stdout('did work ' + str(i) + '\n')
# here, the cell blocks thanks to the `%autoawait` above -
# but jupyter fails to forward any events
x = await wait_for_change(slider, 'value')
out.append_stdout('async function continued with value ' + str(x) + '\n')