jupyter-widgets / ipywidgets

Interactive Widgets for the Jupyter Notebook
https://ipywidgets.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.14k stars 948 forks source link

Mention ipython_blocking in the async docs #2417

Open jasongrout opened 5 years ago

jasongrout commented 5 years ago

https://github.com/kafonek/ipython_blocking is a clever way to block execution on user input. It essentially monkey-patches the kernel execution on the kernel side to save execution messages until a condition is met, then executes the saved messages.

@kafonek - is it all right with you if we note that your package is another way to write a notebook where cell execution waits on user input? We would note that it is provided by a community package.

kafonek commented 5 years ago

@jasongrout yep that sounds great. I was planning on making a PR to the docs (and talk about potential improvements to the library) at the Dashboarding conference in two weeks. If you get to it before then, I'm sure we'll find other conversation topics.

I appreciate the kind words and mention, thanks.

hainm commented 5 years ago

ipython_blocking is pretty handy. In current version of nglview (v2.1), user needs to sleep between cells to get the rendered image data.

# cell 1
x = view.render_image()

# cell 2
time.sleep(1)

# cell 3
print(x.value[:10])

with ipython_blocking, nglview doesn't need to sleep

# cell 1
c = CaptureExecution()
with c:
    x = view.render_image()
    while True:
        if x.value:
            break
        c.step()

# cell2 
print(x.value[:10])

By the way, it would be nicer if I can do this

with CaptureExecution() as c:
    bla bla
# `__enter__` just return `self`.
kafonek commented 5 years ago

@hainm, I can't think offhand how I would implement the with syntax there to accept different ways to break out of the context (e.g. on value change or on button push or on some other threshold). I think the %block magic addresses your use case of just setting up the context to exit when the widget has a .value.

# cell 1
import ipython_blocking # enables %block and %blockrun
x = view.render_image()

# cell 2
%block x

# cell 3
print(x.value[:10])
hainm commented 5 years ago

hi @kafonek, thanks. But your example only works if I run the whole notebook via "Restart & Run All". If I run each cell manually, the notebook cell is frozen.

yes

no

hainm commented 5 years ago

If combining cell 1 and 2 into a single cell, your example work for both cases.

ok

kafonek commented 5 years ago

@hainm when you are running them manually, I think the image is getting rendered before you run the cell with %block x. The default behavior for %block is actually to capture cell execution until the value changes. You could instead pass in a function for just checking that the widget has a non-empty .value in general, %block lambda: x.value or a more verbose,

def exit_function():
    return x.value # or len(x.value) > 1 or some other validation function
%block exit_function

Your solution to put them in the same cell is also totally valid.

hainm commented 5 years ago

thanks @kafonek, I am actually more interested in non-magic code so I could implement something in nglview. Here is an example using ipython_blocking under the hood. cheers. https://github.com/arose/nglview/pull/811

kafonek commented 5 years ago

very cool, thanks for the heads up @hainm. cheers.