Skip to content

Commit

Permalink
Save widget model state to notebook metadata
Browse files Browse the repository at this point in the history
Currently default values are not removed
  • Loading branch information
ricklupton committed Dec 10, 2017
1 parent 3e203ce commit 12cff06
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
8 changes: 8 additions & 0 deletions nbconvert/preprocessors/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,19 @@ def start_new_kernel(startup_timeout=60, kernel_name='python', **kwargs):
cwd=path)
self.kc.allow_stdin = False
self.nb = nb
self.widget_state = {}

try:
nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources)
finally:
self.kc.stop_channels()
self.km.shutdown_kernel(now=self.shutdown_kernel == 'immediate')
if self.widget_state:
self.nb.metadata.widgets = {
'application/vnd.jupyter.widget-state+json': {
'state': self.widget_state
}
}

delattr(self, 'nb')

Expand Down Expand Up @@ -409,6 +416,7 @@ def run_cell(self, cell, cell_index=0):
cell_map[cell_index] = []
continue
elif msg_type.startswith('comm'):
self.widget_state[content['comm_id']] = content['data']['state']
continue

display_id = None
Expand Down
32 changes: 32 additions & 0 deletions nbconvert/preprocessors/tests/files/widget-hello-world.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "64111c035eec4e1ab43895db8121e229",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"A Jupyter Widget"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import ipywidgets\n",
"ipywidgets.Label('Hello World')"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}
28 changes: 28 additions & 0 deletions nbconvert/preprocessors/tests/test_execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ def normalize_output(output):
if 'text/plain' in output.get('data', {}):
output['data']['text/plain'] = \
re.sub(addr_pat, '<HEXADDR>', output['data']['text/plain'])
if 'application/vnd.jupyter.widget-view+json' in output.get('data', {}):
output['data']['application/vnd.jupyter.widget-view+json'] \
['model_id'] = '<MODEL_ID>'
for key, value in output.get('data', {}).items():
if isinstance(value, string_types):
output['data'][key] = _normalize_base64(value)
Expand Down Expand Up @@ -270,3 +273,28 @@ def test_execute_function(self):
original = copy.deepcopy(input_nb)
executed = executenb(original, os.path.dirname(filename))
self.assert_notebooks_equal(original, executed)

def test_widgets(self):
"""Runs a test notebook with widgets and checks the widget state is saved."""
input_file = os.path.join(current_dir, 'files', 'widget-hello-world.ipynb')
opts = dict(kernel_name="python")
res = self.build_resources()
res['metadata']['path'] = os.path.dirname(input_file)
input_nb, output_nb = self.run_notebook(input_file, opts, res)

output_data = [
output.get('data', {})
for cell in output_nb['cells']
for output in cell['outputs']
]

model_ids = [
data['application/vnd.jupyter.widget-view+json']['model_id']
for data in output_data
if 'application/vnd.jupyter.widget-view+json' in data
]

widget_state = output_nb['metadata']['widgets'] \
['application/vnd.jupyter.widget-state+json']['state']
for k in model_ids:
assert k in widget_state

0 comments on commit 12cff06

Please sign in to comment.