ipywidgets: Output widget context manager prints to wrong cell (if used in a Thread)

If I wrap this code from source/docs/examples/Output Widget.ipynb,

import ipywidgets as widgets
out = widgets.Output(layout={'border': '1px solid black'})
with out:
    for i in range(10):
        print(i, 'Hello world!')

in a Thread,

import ipywidgets as widgets
out = widgets.Output(layout={'border': '1px solid black'})
def foo():
    with out:
        for i in range(10):
            print(i,'Hello world!')
IPython.display.display(out)
threading.Thread(target=foo).start()

then the output ends up in a wrong cell as soon as I execute another cell.

I would consider this a bug, as I cannot imagine anyone wanting the Output widget to change cells. To convince you of the awesomeness of updating the Output widget in the cell where it was started, imagine how easy it would be to make a simple

%%run_cell_in_background
for i in range(10):
        print(i, 'Hello world!')

out of this (indeed, that’s what I did, and it works beautifully except for the problem above. In my application, I need a simple job monitor, but I am sure there would be dozens of different uses for this)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 17 (10 by maintainers)

Most upvoted comments

It wouldn’t be such a bad idea to refactor the output widget. We could have the same logic in the frontend and backend (so that the Output widget behaves the same without a front-end connected). And if we send the outputs using a custom msg, we could send the msg_id with it. It is tricky work, and requires ipywidgets, the labextension, the notebook extension, nbconvert and voila to all be in sync.

Are there plans to improve that situation? Or is it something that’s too difficult to address without completely uprooting things

I don’t know of anyone working on this in IPython itself (though that repo would be the place to ask). @SylvainCorlay and some others from quantstack are experimenting with a new python kernel based on the C++ backend xeus that experiments with other concurrency models.

I see that it uses ip.kernel._parent_header['header']['msg_id'] which looks like a global id so I’m not sure.

That’s the key problem in the current IPython kernel - the parent header (which is how things are routed) is a global shared across all threads.

Can you read https://ipywidgets.readthedocs.io/en/stable/examples/Output Widget.html#Interacting-with-output-widgets-from-background-threads carefully, which talks about using an output widget from a thread, and then post your thoughts about it?