Skip to content

Commit

Permalink
Update state filter (#1664)
Browse files Browse the repository at this point in the history
* Add test for widget rendering.

* Save notebook metadata in `Exporter`

* Add tests
  • Loading branch information
trungleduc committed Oct 28, 2021
1 parent 11ea593 commit 5d2c5e2
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 13 deletions.
9 changes: 7 additions & 2 deletions nbconvert/exporters/exporter.py
Expand Up @@ -112,7 +112,7 @@ def __init__(self, config=None, **kw):
super().__init__(config=with_default_config, **kw)

self._init_preprocessors()

self._nb_metadata = {}

@property
def default_config(self):
Expand Down Expand Up @@ -141,7 +141,12 @@ def from_notebook_node(self, nb, resources=None, **kw):

# Preprocess
nb_copy, resources = self._preprocess(nb_copy, resources)

notebook_name = ''
if resources is not None:
name = resources.get('metadata', {}).get('name', '')
path = resources.get('metadata', {}).get('path', '')
notebook_name = os.path.join(path, name)
self._nb_metadata[notebook_name] = nb_copy.metadata
return nb_copy, resources

def from_filename(self, filename: str, resources: Optional[dict] = None, **kw):
Expand Down
4 changes: 2 additions & 2 deletions nbconvert/exporters/html.py
Expand Up @@ -137,7 +137,8 @@ def from_notebook_node(self, nb, resources=None, **kw):
langinfo = nb.metadata.get('language_info', {})
lexer = langinfo.get('pygments_lexer', langinfo.get('name', None))
highlight_code = self.filters.get('highlight_code', Highlight2HTML(pygments_lexer=lexer, parent=self))
filter_data_type = WidgetsDataTypeFilter(notebook_metadata=nb.metadata, parent=self)

filter_data_type = WidgetsDataTypeFilter(notebook_metadata=self._nb_metadata, parent=self, resources=resources)

self.register_filter('highlight_code', highlight_code)
self.register_filter('filter_data_type', filter_data_type)
Expand Down Expand Up @@ -167,7 +168,6 @@ def resources_include_url(name):
pieces = split_template_path(name)
for searchpath in self.template_paths:
filename = os.path.join(searchpath, *pieces)
print(filename, os.path.exists(filename))
if os.path.exists(filename):
with open(filename, "rb") as f:
data = f.read()
Expand Down
1 change: 1 addition & 0 deletions nbconvert/exporters/tests/test_templateexporter.py
Expand Up @@ -326,6 +326,7 @@ def test_raw_template_init(self):
class AttrExporter(RSTExporter):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.raw_template = raw_template

exporter_init = AttrExporter()
Expand Down
23 changes: 14 additions & 9 deletions nbconvert/filters/widgetsdatatypefilter.py
Expand Up @@ -19,7 +19,7 @@
#-----------------------------------------------------------------------------

from warnings import warn

import os
from ..utils.base import NbConvertBase

__all__ = ['WidgetsDataTypeFilter']
Expand All @@ -33,13 +33,13 @@ class WidgetsDataTypeFilter(NbConvertBase):
""" Returns the preferred display format, excluding the widget output if
there is no widget state available """

def __init__(self, notebook_metadata=None, **kwargs):
metadata = notebook_metadata or {}

self.widgets_state = (
metadata['widgets'][WIDGET_STATE_MIMETYPE]['state'] if
metadata.get('widgets') is not None else {}
)
def __init__(self, notebook_metadata=None, resources=None, **kwargs):
self.metadata = notebook_metadata
self.notebook_path = ''
if resources is not None:
name = resources.get('metadata', {}).get('name', '')
path = resources.get('metadata', {}).get('path', '')
self.notebook_path = os.path.join(path, name)

super().__init__(**kwargs)

Expand All @@ -51,12 +51,17 @@ def __call__(self, output):
`output` is dict with structure {mimetype-of-element: value-of-element}
"""
metadata = self.metadata.get(self.notebook_path, {})
widgets_state = (
metadata['widgets'][WIDGET_STATE_MIMETYPE]['state'] if
metadata.get('widgets') is not None else {}
)
for fmt in self.display_data_priority:
if fmt in output:
# If there is no widget state available, we skip this mimetype
if (
fmt == WIDGET_VIEW_MIMETYPE and
output[WIDGET_VIEW_MIMETYPE]['model_id'] not in self.widgets_state
output[WIDGET_VIEW_MIMETYPE]['model_id'] not in widgets_state
):
continue

Expand Down
47 changes: 47 additions & 0 deletions nbconvert/tests/files/Unexecuted_widget.ipynb
@@ -0,0 +1,47 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "036cb3ce-96fe-4159-8145-40bb74b263f9",
"metadata": {},
"outputs": [],
"source": [
"import ipywidgets as widgets\n",
"widgets.IntSlider(\n",
" value=7,\n",
" min=0,\n",
" max=10,\n",
" step=1,\n",
" description='Test:',\n",
" disabled=False,\n",
" continuous_update=False,\n",
" orientation='horizontal',\n",
" readout=True,\n",
" readout_format='d'\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
47 changes: 47 additions & 0 deletions nbconvert/tests/files/Unexecuted_widget_2.ipynb
@@ -0,0 +1,47 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "036cb3ce-96fe-4159-8145-40bb74b263f9",
"metadata": {},
"outputs": [],
"source": [
"import ipywidgets as widgets\n",
"widgets.IntSlider(\n",
" value=7,\n",
" min=0,\n",
" max=10,\n",
" step=1,\n",
" description='Test:',\n",
" disabled=False,\n",
" continuous_update=False,\n",
" orientation='horizontal',\n",
" readout=True,\n",
" readout_format='d'\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
26 changes: 26 additions & 0 deletions nbconvert/tests/test_nbconvertapp.py
Expand Up @@ -570,3 +570,29 @@ def test_widgets_from_htmlexporter(self):
output, _ = HTMLExporter().from_notebook_node(nb)

assert "var widgetRendererSrc = 'https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed-amd.js';" in output

def test_execute_widgets_from_nbconvert(self):
"""Check jupyter widgets render"""
notebookName = "Unexecuted_widget"
with self.create_temp_cwd([f"{notebookName}.ipynb"]):
self.nbconvert(
f"{notebookName}.ipynb --execute --log-level 0 --to html")
assert os.path.isfile(f"{notebookName}.html")
with open(f"{notebookName}.html", "r", encoding="utf8") as f:
text = f.read()
assert '<script type="application/vnd.jupyter.widget-view+json">' in text
assert '<script type="application/vnd.jupyter.widget-state+json">' in text

def test_execute_multiple_notebooks(self):
"""Check jupyter widgets render in case of batch convert"""
notebookName = "Unexecuted_widget"
with self.create_temp_cwd([f"{notebookName}*.ipynb"]):
self.nbconvert(
"*.ipynb --execute --log-level 0 --to html")

for name in (notebookName, f"{notebookName}_2"):
assert os.path.isfile(f"{name}.html")
with open(f"{name}.html", "r", encoding="utf8") as f:
text = f.read()
assert '<script type="application/vnd.jupyter.widget-view+json">' in text
assert '<script type="application/vnd.jupyter.widget-state+json">' in text

0 comments on commit 5d2c5e2

Please sign in to comment.