Jupyter UI Poll
jupyter-ui-poll is a Python library that enables blocking Jupyter cell execution while interacting with ipywidgets or similar interactive elements. It addresses the challenge of creating 'blocking GUI' within notebooks, allowing for sequential workflows where user input via widgets is required before subsequent cells execute. The current version, 1.1.0, includes critical fixes for compatibility with newer `ipykernel` versions and improved handling of asynchronous operations. The library maintains an active release cadence, primarily driven by `ipykernel` compatibility updates.
Common errors
-
The polling mechanism no longer works under the latest release of ipykernel from pip. ... The most immediate problem is that do_one_iteration is now an async method.
cause Incompatibility between `jupyter-ui-poll` and a newer `ipykernel` version, specifically when `ipykernel`'s internal event loop methods become asynchronous.fixUpgrade `jupyter-ui-poll` to the latest version. For `ipykernel` 6+, you may need to adopt `async` patterns in your `jupyter-ui-poll` usage (e.g., `async with ui_events() as poll: await poll()`) or ensure your `jupyter-ui-poll` version explicitly supports your `ipykernel` version. -
Jupyter kernel died / Jupyter Notebook connection error
cause While not directly a `jupyter-ui-poll` error, an incompatible `jupyter-ui-poll` or `ipykernel` setup can destabilize the kernel. If `jupyter-ui-poll` fails to correctly hook into the kernel's event handling, it can lead to dead kernels or connection issues. This can also be caused by general `ipykernel` installation issues, or conflicting `pyzmq` versions.fixFirst, ensure `jupyter-ui-poll` is the latest version. If the issue persists, try reinstalling `ipykernel` and `jupyter-ui-poll` in a fresh environment. Check for `pyzmq` compatibility issues by uninstalling and reinstalling it (e.g., `pip uninstall pyzmq; pip install pyzmq==19.0.2` if an older version is needed, or the latest otherwise). -
Callbacks you have registered with the widget library won't get a chance to run and so state of app.have_all_the_data() won't ever change.
cause This is the fundamental problem `jupyter-ui-poll` solves. Without `jupyter-ui-poll`, Jupyter's kernel is busy executing the current cell and does not process UI events or callbacks from widgets, leading to unresponsive UIs and blocking logic.fixWrap your polling logic within `with ui_events() as poll:` and call `poll()` periodically inside your loop to explicitly process UI events. Alternatively, use `async for` with `with_ui_events()` for asynchronous iterables.
Warnings
- breaking Version `0.2.0a0` introduced breaking changes by making the library async-only. Synchronous usage patterns for `with_ui_events` and `run_ui_poll_loop` were removed, requiring `async with` and `async for` instead. While `v0.2.0` later re-introduced synchronous support for `ui_events`, if you are on an `ipykernel` >= 6, the async patterns might be required for certain operations.
- breaking Version `1.1.0` includes crucial fixes for `ipykernel` series 7+. Newer `ipykernel` versions introduce internal locks that stop message processing during cell execution. `jupyter-ui-poll` v1.1.0 dynamically patches the running kernel instance to bypass this lock and allow UI event processing. Older versions of `jupyter-ui-poll` will likely cease to function correctly with `ipykernel` 7+.
- gotcha `jupyter-ui-poll` has historically had to adapt to significant changes in `ipykernel`'s internal architecture across major versions (e.g., v5, v6, v7). This means that a `jupyter-ui-poll` version compatible with `ipykernel` v5 might not work with v6 or v7, and vice-versa. Always check the release notes for specific `ipykernel` compatibility details.
Install
-
pip install jupyter-ui-poll -
conda install -c conda-forge jupyter-ui-poll
Imports
- ui_events
from jupyter_ui_poll import ui_events
- with_ui_events
from jupyter_ui_poll import with_ui_events
- run_ui_poll_loop
from jupyter_ui_poll import run_ui_poll_loop
Quickstart
import time
from ipywidgets import Button, display
from jupyter_ui_poll import ui_events
# Global flag to control the loop
ui_done = False
def on_click(btn):
global ui_done
ui_done = True
btn.description = 'Done!'
# Create a button
button = Button(description='Click Me to Continue')
button.on_click(on_click)
display(button)
print('Waiting for button click...')
# Wait for user to press the button, processing UI events
with ui_events() as poll:
while not ui_done:
poll(10) # Process up to 10 UI events per call
print('.', end='', flush=True)
time.sleep(0.1) # Prevent busy-waiting
print('\nButton clicked! Execution continues.')