ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

Question: Block kernel until ipywidget's initial rendering has completed

Open anant-k-singh opened this issue 4 years ago • 3 comments
trafficstars

Question: I am building a custom ipywidget and the first rendering of widget (in output cell) takes some time. The following cells in the notebook interact with the widget and it requires the widget to be fully rendered before interacting with it in other cells. There is no python function which I can await, as the widget start rendering as soon as we execute the widget class's object

In other words, I want the kernel to wait until DOMWidgetView.render() has finished rendering in output cell.

anant-k-singh avatar Mar 02 '21 09:03 anant-k-singh

I would expose a Promise on the "slow to start" widget, and have any widgets that need to interact with that one await the widget before rendering themselves fully. A (somewhat complicated) example is in pythreejs, where we use an initPromise: https://github.com/jupyter-widgets/pythreejs/search?q=initPromise

vidartf avatar Mar 02 '21 14:03 vidartf

Relevant other points of note, that might or might not be useful:

  • Deserializers are async
  • The view render call is async (https://github.com/jupyter-widgets/ipywidgets/blob/1a121620aea08b2df4bcf92e851bd961317dc1db/packages/base/src/widget.ts#L681-L688)

vidartf avatar Mar 02 '21 14:03 vidartf

Hi @vidartf I am also looking for a method to block execution until specific event happens, but it turns out that the event won't be sent if the main thread of Jupyter is blocking. For example,

import asyncio
from IPython.display import display
from ipywidgets import Text
def wait_for_change(widget, value):
    future = asyncio.Future()
    def getvalue(change):
        # make the new value available
        future.set_result(change.new)
        widget.unobserve(getvalue, value)
    widget.observe(getvalue, value)
    return future

text_input = Text()
print('before', text_input.value)

display(text_input)
future = wait_for_change(text_input, 'value') 

await asyncio.ensure_future(future)  # block forever, the future didn't get resolved after user finishing input

# never reach this line
print(text_input.value)

There are more examples in the SO issue: https://stackoverflow.com/questions/77363909/how-to-block-execution-until-jupyter-widgets-value-has-been-changed Is there any solution to make it work?

link89 avatar Nov 01 '23 01:11 link89