ipython_blocking offers a context manager and IPython magic to capture cell execution.
Project description
ipython_blocking
A Python library that offers a context manager and IPython magic to capture execute_request
messages on the IPython comms channels and then replay them later. It is a way to "block" Jupyter notebook cells from running while waiting for a Widget value to change, a Widget button to be pressed, or other validation functions to happen.
What problem is this solving
In our corporate work environment, we have several thousand Jupyter notebook users. A small fraction are notebook authors, while the majority of users are running notebooks that other people have written. Non-authors fall along a spectrum of "code comfort": some users want the notebook experience to be like a regular web application where they don't even see the code, while others are experienced enough to read the code and edit it to fit their individual needs.
ipywidgets are a very popular and easy way to make rich user interfaces that are engaging for even non-technical users. It is also common practice to write notebooks designed to work in dashboard mode or which users will interact with by clicking "cell -> run all" right from the start.
The problem is that notebook authors must structure the rest of their code as call-back functions if they want to reference data entered into a widget, such as a query string in a widgets.Text
box or an option picked from a widget.Dropdown
. Wrapping code in a function that is triggered by an on_click
handler or similar isn't inherently bad, but there are problems that show up over and over. Generally speaking, using widgets for input data and then using callback functions to do the work in a notebook makes the notebook harder to read, harder to debug, harder to maintain, and harder to build on.
Without ipython_blocking
, our notebook authors faced the choice of leveraging widgets for user-friendly input forms and then having "ugly" callback code afterwards, or writing "cleaner" exploratory-style code that might not have gotten traction with some non-technical users. With ipython_blocking
, notebook authors can get the best of both worlds.
When to use ipython_blocking
and when not to
If your notebook is designed to be run once, execute in a linear fashion, and uses widgets for input, then ipython_blocking
is perfect for you. However, it's not a library for all use cases. For instance, if you have a notebook where you expect users to change values in a widget and then that updates a visualization, using regular on_click
handlers is better.
Install
ipython_blocking
is on PyPI.
>>> pip install ipython_blocking
Examples
See the demo notebook for an interactive example.
Using the CaptureExecution context manager
The most explicit way to use ipython_blocking
is to use the context manager directly. In this example, cell #3 (printing the dropdown value) will not actually execute until you have chosen a new value besides the default empty string.
### Cell 1
import ipywidgets
dd = widgets.Dropdown(options=['', 'foo', 'bar', 'baz'])
dd
### Cell 2
import ipython_blocking
ctx = ipython_blocking.CaptureExecution()
with ctx:
while True:
if dd.value:
break
ctx.step()
### Cell 3 (doesn't run until the dropdown value changes)
print(dd.value)
IPython %block
line magic
Creating the context is verbose so ipython_blocking
offers a line magic that will set up the context and break out of it in common situations. It expects one of three types of objects: a ValueWidget
, or a ButtonWidget
, or a function/method,. Each different type of object that can be passed to %block
offers a slightly different trigger to stop capturing cell execution and to replay all captured cells.
- If you pass a
ValueWidget
, the blocking will stop when the widget value changes - If you pass a
ButtonWidget
, the blocking will stop when the button is pressed - If you pass a function or method, the function will be called often (every
kernel.do_one_iteration()
) and the blocking will stop when it returns True
Using %block
with a ValueWidget
The %block
cell execution capture context with a ValueWidget
will stop when the value of the widget changes.
### Cell 1
import ipython_blocking
ipython_blocking.load_ipython_extensions()
import ipywidgets
dd = widgets.Dropdown(options=['', 'foo', 'bar', 'baz'])
dd
### Cell 2
%block dd
### Cell 3 (doesn't run until the dropdown value has changed)
print(dd.value)
Using %block
with a Button
The %block
cell execution capture context with a Button
will stop when the button has been clicked. It's handy to make a button disabled until other validation has been met.
### Cell 1
import ipython_blocking
ipython_blocking.load_ipython_extensions()
import ipywidgets
query_input = widgets.Text(description="Query string:")
button = widgets.Button(description="Submit", disabled=True)
def input_observe(ev):
value = ev['new']
if len(value) >= 14:
button.disabled = False
button.button_style = 'success'
query_input.observe(input_observe, 'value')
box = widgets.VBox(children=[query_input, button])
box
### Cell 2
%block button
### Cell 3 (doesn't run until the button is pressed)
print(query_input.value)
Using %block
with a function/method
The %block
cell execution capture context with a function/method will stop when that function/method returns True. Use this when you need to do complex input validation.
### Cell 1
dd1 = widgets.Dropdown(options=['', 'foo', 'bar', 'baz'])
dd2 = widgets.Dropdown(options=['', 'foo', 'bar', 'baz'])
box = widgets.VBox(children=[dd1, dd2])
box
### Cell 2
def complex_validation():
"return False unless both dropdowns are non-empty strings and don't equal each other"
return dd1.value and dd1.value and dd1.value != dd2.value
### Cell 3
%block complex_validation
### Cell 4 (doesn't run until complex_validation returns True)
print(dd1.value, dd2.value)
Timeout arguments
The %block
magic accepts one optional argument -t
/ --timeout
, which is a number of seconds until the cell execution context stops. The default is no timeout, which means the %block
will run forever until the criteria is met to stop capturing cell execution and replay any captured cells.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file ipython_blocking-0.1.1.tar.gz
.
File metadata
- Download URL: ipython_blocking-0.1.1.tar.gz
- Upload date:
- Size: 8.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: python-requests/2.19.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b71f5d560f5245c4ace9ed39f30c2a84f9fd8af0e207499c5b284922e150b6ce |
|
MD5 | f05eabe551f9ac69f3ea98fe1d37b85b |
|
BLAKE2b-256 | 959781f23f0efb8b7f2d3e5abebb446943c2c4a6898f137925c00c1416e7b890 |
File details
Details for the file ipython_blocking-0.1.1-py2.py3-none-any.whl
.
File metadata
- Download URL: ipython_blocking-0.1.1-py2.py3-none-any.whl
- Upload date:
- Size: 10.1 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: python-requests/2.19.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6a743969ca4a78f35eef144d74fde51aeed1c53d81d4fe7378ca52fee480955c |
|
MD5 | 5747a3ba73ccb16ff56b9d8162b34a71 |
|
BLAKE2b-256 | 78ef51d7515b59b93b80a6a6669745be908026599cafac98643434a3ce74e8fa |