Closed 12rambau closed 3 years ago
As a quick check, can you please create a notebook that contains a cell from sepal_ui import sepalwidgets
, execute it, and attach here?
Jupyter-sphinx extract the outputs from executing notebooks, and therefore whatever causes the problems should be in that notebook.
sure:
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "9ab504b3-fe94-46c6-943b-1c068dba18c6",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "abc62f3369e249dfa319912be862f8c1",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Styles()"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from sepal_ui import sepalwidgets as sw "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Thanks, it seems that the problem is due to ipywidgets. Let's investigate this further.
Firstly, can you confirm that jupyter-sphinx produces the same broken output with
.. jupyter-execute::
import ipywidgets; ipywidgets.Button()
Then, what version of ipywidgets and sphinx do you have?
Finally, please search in the generated index.html
of your file for code embedding the widget. For me it looks like this:
<script type="application/vnd.jupyter.widget-view+json">
{"version_major": 2, "version_minor": 0, "model_id": "17ba71bde1f8459990f9f385b58e36a4"}
</script>
Searching for mimetype should yield the result.
Firstly, can you confirm that jupyter-sphinx produces the same broken output with
Nope, the result is perfectly normal when I import ipywidgets.
Then, what version of ipywidgets and sphinx do you have?
ipywidgets==7.6.3
Sphinx==4.0.3
I have in my page a first one:
<div class="cell_output docutils container">
<script type="application/vnd.jupyter.widget-view+json">
{"version_major": 2, "version_minor": 0, "model_id": "3ca7430425ae45d8902065b442db8558"}
</script></div>
and then a huge one:
<script type="application/vnd.jupyter.widget-state+json">
{"state": {"bb43da8e097447e3bc5bf776472e64c9": {"model_name": "LayoutModel", "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null}}, "46022dd5827b44a69311f246c3ee778a": {"model_name": "ForceLoadModel", "model_module": "jupyter-vue", "model_module_version": "^1.5.0", "state": {"_dom_classes": [], "_model_module": "jupyter-vue", "_model_module_version": "^1.5.0", "_model_name": "ForceLoadModel", "_view_count": null, "_view_module": null, "_view_module_version": "", "_view_name": null, "layout": "IPY_MODEL_bb43da8e097447e3bc5bf776472e64c9"}}, "15742b8121314f77b1f6d0b1bb935e21": {"model_name": "ThemeModel", "model_module": "jupyter-vuetify", "model_module_version": "^1.8.1", "state": {"_model_module": "jupyter-vuetify", "_model_module_version": "^1.8.1", "_model_name": "ThemeModel", "_view_count": null, "_view_module": null, "_view_module_version": "^1.8.1", "_view_name": null, "dark": true}}, "92047bdefbb4480b84bd1ce3a30cc246": {"model_name": "ThemeColorsModel", "model_module": "jupyter-vuetify", "model_module_version": "^1.8.1", "state": {"_model_module": "jupyter-vuetify", "_model_module_version": "^1.8.1", "_model_name": "ThemeColorsModel", "_theme_name": "light", "_view_count": null, "_view_module": null, "_view_module_version": "^1.8.1", "_view_name": null, "accent": "#82B1FF", "anchor": null, "error": "#FF5252", "info": "#2196F3", "primary": "#1976D2", "secondary": "#424242", "success": "#4CAF50", "warning": "#FB8C00"}}, "e95ab358f9aa4bd9801152793470271b": {"model_name": "ThemeColorsModel", "model_module": "jupyter-vuetify", "model_module_version": "^1.8.1", "state": {"_model_module": "jupyter-vuetify", "_model_module_version": "^1.8.1", "_model_name": "ThemeColorsModel", "_theme_name": "dark", "_view_count": null, "_view_module": null, "_view_module_version": "^1.8.1", "_view_name": null, "accent": "#a1458e", "anchor": null, "error": "#A63228", "info": "#79B1C9", "primary": "#B3842E", "secondary": "#324a88", "success": "#3F802A", "warning": "#b8721d"}}, "4e48a32be045476fb82c3684149a80e3": {"model_name": "LayoutModel", "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null}}, "3ca7430425ae45d8902065b442db8558": {"model_name": "VuetifyTemplateModel", "model_module": "jupyter-vuetify", "model_module_version": "^1.8.1", "state": {"_component_instances": [], "_dom_classes": [], "_jupyter_vue": "IPY_MODEL_46022dd5827b44a69311f246c3ee778a", "_model_module": "jupyter-vuetify", "_model_module_version": "^1.8.1", "_model_name": "VuetifyTemplateModel", "_view_count": null, "_view_module": "jupyter-vuetify", "_view_module_version": "^1.8.1", "_view_name": "VuetifyView", "components": null, "css": null, "data": null, "events": [], "layout": "IPY_MODEL_4e48a32be045476fb82c3684149a80e3", "methods": null, "template": "\n <style>\n .leaflet-pane {\n z-index : 2 !important;\n }\n .leaflet-top, .leaflet-bottom {\n z-index : 2 !important;\n }\n main.v-content {\n padding-top: 0px !important;\n }\n </style>\n "}}, "1d488d83c95b418bb28a0376159b4d41": {"model_name": "LayoutModel", "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null}}, "58f377c006094988b871b3e742de4052": {"model_name": "VuetifyTemplateModel", "model_module": "jupyter-vuetify", "model_module_version": "^1.8.1", "state": {"_component_instances": [], "_dom_classes": [], "_jupyter_vue": "IPY_MODEL_46022dd5827b44a69311f246c3ee778a", "_model_module": "jupyter-vuetify", "_model_module_version": "^1.8.1", "_model_name": "VuetifyTemplateModel", "_view_count": null, "_view_module": "jupyter-vuetify", "_view_module_version": "^1.8.1", "_view_name": "VuetifyView", "components": null, "css": null, "data": null, "events": [], "layout": "IPY_MODEL_1d488d83c95b418bb28a0376159b4d41", "methods": null, "resize": 0, "template": "\n <script>\n modules.export = {\n watch: {\n resize() {\n window.dispatchEvent(new Event('resize'));\n }\n }\n }\n </script>\n "}}}, "version_major": 2, "version_minor": 0}
</script>
And I think I get what's the issue, the <scripts>
is closed prematurely by the window.dispatchEvent(...)
at the very end. (it's coming from here: https://github.com/12rambau/sepal_ui/blob/master/sepal_ui/frontend/js.py)
confirmed by this test:
and now I have a minimal reproductible example:
.. jupyter-execute::
import ipyvuetify as v
from traitlets import Unicode
class ResizeTrigger(v.VuetifyTemplate):
template = Unicode("<script></script>").tag(sync=True)
rt = ResizeTrigger()
that leads to:
Thanks! Now it's clear what is happening. We dump JSON over here:
https://github.com/jupyter/jupyter-sphinx/blob/master/jupyter_sphinx/ast.py#L394-L396
Since this is embedded in html, and not saved as a separate asset, we'd need to escape the JSON for HTML first. Not immediately sure how to do it though.
I would be happy to contribute !
A first and easy fix is the replace </script>
by </scrip>
because it's in the end the only one that can cause trouble but i don't know if it can have any other consequences in the lib
That part is self-contained and won't influence anything but the widget inclusion, I'm only unsure if that's the only symbol we need to escape, and if it would work correctly after escaping. Special-casing only backslash seems fragile. Having some source on this would help a lot.
https://stackoverflow.com/questions/22488830/script-within-a-javascript-string-in-a-script-tag
https://stackoverflow.com/questions/1061697/whats-the-easiest-way-to-escape-html-in-python
from what I understand the only one that can interact is </script>
as everything is included in a <script>
tag. I experimented also with escape and it also work I'm just not sure it's necessary.
For my small usecase it works and everything is displayed as expected on screen.
If the output cell include "<" or ">" I don't think we want them to be escaped so a dedicated replace seems to be the safest to me.
Descripsion
As you can see on the image provided a normal
jupyter-execute
prints work but when I import my lib (sepal_ui), I get this strange display ending by"\n "}}}, "version_major": 2, "version_minor": 0}
.It seems related to https://github.com/jupyter-widgets/ipywidgets/issues/1305 but I don't get how it is link to this repository. Did someone already experiment this error and can tell me what's wrong in my lib ?
screenshot
steps to reproduce
create a new project:
then update your environment with the
sepal_ui
lib:update conf.py:
update index.rst:
build it and watch the produced single html page