erdewit/nest_asyncio

Fail to wait for user action

AlexBdx opened this issue · 1 comments

I have a simple GUI in a Jupyter Notebook with two widgets: a drop down menu with 3 choices and a push button.
The desired behavior is:

  1. Execute the cell that contains the widgets (see code below)
  2. Wait (as long as needed) for the user to click on the push button
  3. Print the value of the drop down menu (the user's choice)

Using asyncio out of the box does not work in Jupyter Notebook because there is already an event loop running. I tried to user nest_asyncio to solve that issue, and the RunTimeError did go away. But instead, the notebook hangs forever. When I click on the push button, nothing happens.
I saw there were issues with asyncio.Future in #22, so maybe I am missing something. Any idea how I can leverage nest_asyncio to make this work? Thanks

import nest_asyncio
nest_asyncio.apply()
from ipywidgets import Button, Dropdown, HBox
import asyncio

choices = Dropdown(options=[1, 2, 3], description='Choice')
button = Button(description="Select")
panel = HBox([choices, button])

def wait_for_change(push_button, dropdown):
    future = asyncio.Future()  # Make getvalue function awaitable
    def getvalue(change):
        future.set_result(dropdown.value)
        push_button.on_click(getvalue, remove=True)  # Unbind function from widget
    push_button.on_click(getvalue)
    return future

async def main():
    user_choice = await wait_for_change(button, choices)
    print(f"User selected option {user_choice}")
    return user_choice

display(panel)
print("Which option would you like to choose?")
out = asyncio.run(main())
print("End of code")
import nest_asyncio
nest_asyncio.apply()
...
out = asyncio.run(main())

Using the top-level await from IPython, these lines of code can be replaced with

out = await main()

When I try this it hangs as well, and since it's not using nest_asyncio anymore it must be something in ipywidgets itself..