Skip to content

Commit cb90d55

Browse files
authored
Fix html repr in untrusted notebooks (plain text fallback) (#4053)
* add html pre element with text repr as fallback The PRE element is not displayed when CSS is injected. When CSS is not injected (untrusted notebook), the PRE element is shown but not the DIV container used for the HTML repr. * remove title elements in svg icons Prevent showing those when fallback to plain text repr. A title tag is already present in the HTML label elements. * add basic test * update what's new
1 parent 261df2e commit cb90d55

File tree

5 files changed

+25
-6
lines changed

5 files changed

+25
-6
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ Bug fixes
116116
- Fix bug in time parsing failing to fall back to cftime. This was causing time
117117
variables with a time unit of `'msecs'` to fail to parse. (:pull:`3998`)
118118
By `Ryan May <https://github.com/dopplershift>`_.
119+
- Fix html repr in untrusted notebooks: fallback to plain text repr. (:pull:`4053`)
120+
By `Benoit Bovy <https://github.com/benbovy>`_.
119121

120122
Documentation
121123
~~~~~~~~~~~~~

xarray/core/formatting_html.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,20 @@ def array_section(obj):
222222
)
223223

224224

225-
def _obj_repr(header_components, sections):
225+
def _obj_repr(obj, header_components, sections):
226+
"""Return HTML repr of an xarray object.
227+
228+
If CSS is not injected (untrusted notebook), fallback to the plain text repr.
229+
230+
"""
226231
header = f"<div class='xr-header'>{''.join(h for h in header_components)}</div>"
227232
sections = "".join(f"<li class='xr-section-item'>{s}</li>" for s in sections)
228233

229234
return (
230235
"<div>"
231236
f"{ICONS_SVG}<style>{CSS_STYLE}</style>"
232-
"<div class='xr-wrap'>"
237+
f"<pre class='xr-text-repr-fallback'>{escape(repr(obj))}</pre>"
238+
"<div class='xr-wrap' hidden>"
233239
f"{header}"
234240
f"<ul class='xr-sections'>{sections}</ul>"
235241
"</div>"
@@ -257,7 +263,7 @@ def array_repr(arr):
257263

258264
sections.append(attr_section(arr.attrs))
259265

260-
return _obj_repr(header_components, sections)
266+
return _obj_repr(arr, header_components, sections)
261267

262268

263269
def dataset_repr(ds):
@@ -272,4 +278,4 @@ def dataset_repr(ds):
272278
attr_section(ds.attrs),
273279
]
274280

275-
return _obj_repr(header_components, sections)
281+
return _obj_repr(ds, header_components, sections)

xarray/static/css/style.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ body.vscode-dark {
2626
}
2727

2828
.xr-wrap {
29+
display: block;
2930
min-width: 300px;
3031
max-width: 700px;
3132
}
3233

34+
.xr-text-repr-fallback {
35+
/* fallback to plain text repr when CSS is not injected (untrusted notebook) */
36+
display: none;
37+
}
38+
3339
.xr-header {
3440
padding-top: 6px;
3541
padding-bottom: 6px;

xarray/static/html/icons-svg-inline.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
<svg style="position: absolute; width: 0; height: 0; overflow: hidden">
22
<defs>
33
<symbol id="icon-database" viewBox="0 0 32 32">
4-
<title>Show/Hide data repr</title>
54
<path d="M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z"></path>
65
<path d="M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
76
<path d="M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
87
</symbol>
98
<symbol id="icon-file-text2" viewBox="0 0 32 32">
10-
<title>Show/Hide attributes</title>
119
<path d="M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z"></path>
1210
<path d="M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
1311
<path d="M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>

xarray/tests/test_formatting_html.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ def test_repr_of_dataset(dataset):
139139
assert "&lt;IA&gt;" in formatted
140140

141141

142+
def test_repr_text_fallback(dataset):
143+
formatted = fh.dataset_repr(dataset)
144+
145+
# Just test that the "pre" block used for fallback to plain text is present.
146+
assert "<pre class='xr-text-repr-fallback'>" in formatted
147+
148+
142149
def test_variable_repr_html():
143150
v = xr.Variable(["time", "x"], [[1, 2, 3], [4, 5, 6]], {"foo": "bar"})
144151
assert hasattr(v, "_repr_html_")

0 commit comments

Comments
 (0)