Hi all,
I am running the following code in a notebook:
from ipywidgets import Box, Button, Text
import asyncio
from IPython.core.display import display
loop = asyncio.get_running_loop()
def wait_for_change(widget):
future = loop.create_future()
def getvalue(change):
if user_input.value != 'hi':
future.set_result(False)
else:
future.set_result(True)
widget.on_click(getvalue, remove=True)
widget.on_click(getvalue)
return future
button = Button(description='Submit')
user_input = Text()
async def f():
valid = False
while not valid:
valid = await wait_for_change(button)
print('done')
display(Box([user_input, button]))
loop.create_task(f())
print('continue...')
My goal is to stop the program until a specific user input is registered. For my given example this means that the print(âcontinueâŚâ) statement is printed after the user submitted âhiâ. Does someone has an idea what I have to change so that this works?
create_task, in this case, returns immediately. The obejct you get back, a Task, could be awaited, but this would then block your main thread, and the widget messages wouldnât go through.
So, unfortunately the answer today is pretty much âno,â you canât block the main execution loop and get back user input (about the only option is the input()) method, which has special treatment, and would remove the async stuff
If youâre already on the widget bus, you could fake it by chaining everything off certain traits changing values, which could appear to be executing cells: theyâd just be empty Box instances, and youâd fill in the children later, i guess. This would have the advantage (perhaps) of also not requiring any async functions, though if you do end up needing to call async stuff, it can be more predictable to use some of the tornado machinery, e.g. tornado.ioloop.IOLoop.get_current().add_callback, which will ensure it happens in the right place (especially for error reporting).
Maybe you can use the example code I have already to adapt it get the user input and then look like it changes when âSubmitâ is pressed. (My current button equivalent is âPlot Selectedâ.) To see my example and code, go to here and click on the âlaunch binderâ badge . Then under âAvailable Demonstration Notebooksâ, select â3D scatter plot using data in a file and Voila interfaceâ. The code you want to play with is in the only code cell on the page.
I think I need to adapt my idea because I am trying to write a package which is imported and executed in only one cell. So I need to wait for valid user input to continue with further calculations. But unfortunately it seems like this doesnât work.
I could use input() but then I canât create a frontend which looks nicely.
Ah, well, if you just have exactly one output, everythingâs way easier! In the past, Iâve even used a state machine library like transitions which lets you very predictably specify the state⌠and should probably be a standalone package ! (Note: i did try, a bit, but thereâs a lot to do!)
Basically, all the widgets get created up-front, and observed or added to children as needed. A handy thing from this is you can even get a nice state machine diagram for documentation purposes out of the end, which is better than the âtrait soupâ itâs easy to achieve with doing everything imperatively.