Skip to content

Commit 777d56e

Browse files
authored
fix: Display code that triggered an error in warning (#13)
1 parent 7940667 commit 777d56e

File tree

4 files changed

+49
-12
lines changed

4 files changed

+49
-12
lines changed

sphinxext_altair/altairplot.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ def run(self) -> list[nodes.Element]:
233233
return result
234234

235235

236+
class AltairPlotWarning(UserWarning): ...
237+
238+
236239
def html_visit_altair_plot(self: altair_plot, node: nodes.Element) -> None: # noqa: C901
237240
# Execute the code, saving output and namespace
238241
namespace = node["namespace"]
@@ -242,14 +245,19 @@ def html_visit_altair_plot(self: altair_plot, node: nodes.Element) -> None: # n
242245
chart = eval_block(node["code"], namespace)
243246
stdout = f.getvalue()
244247
except Exception as err:
248+
err_file = node["rst_source"]
249+
line_no = node["rst_lineno"]
250+
err_code = node["code"]
245251
msg = (
246-
f"altair-plot: {node['rst_source']}:{node['rst_lineno']} "
247-
f"Code Execution failed: {type(err).__name__}: {err!s}"
252+
f"Code Execution failed.\n"
253+
f" {err_file}:{line_no}\n"
254+
f" {type(err).__name__}: {err!s}\n"
255+
f" {err_code}"
248256
)
249257
if node["strict"]:
250258
raise ValueError(msg) from err
251259
else:
252-
warnings.warn(msg, stacklevel=1)
260+
warnings.warn(msg, AltairPlotWarning, stacklevel=1)
253261
raise nodes.SkipNode from err
254262

255263
if chart_name := node.get("chart-var-name", None):
@@ -298,11 +306,14 @@ def html_visit_altair_plot(self: altair_plot, node: nodes.Element) -> None: # n
298306
)
299307
self.body.append(html)
300308
else:
309+
err_file = node["rst_source"]
310+
line_no = node["rst_lineno"]
301311
msg = (
302-
f"altair-plot: {node['rst_source']}:{node['rst_lineno']} Malformed block. "
303-
"Last line of code block should define a valid altair Chart object."
312+
f"Malformed block.\n"
313+
f" {err_file}:{line_no}\n"
314+
f" Last line of code block should define a valid altair Chart object."
304315
)
305-
warnings.warn(msg, stacklevel=1)
316+
warnings.warn(msg, AltairPlotWarning, stacklevel=1)
306317
raise nodes.SkipNode
307318

308319

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010

1111

1212
@pytest.fixture(scope="session")
13-
def rootdir():
13+
def rootdir() -> Path:
1414
return Path(__file__).parent / "roots"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Trigger a NameError
2+
---------------------------
3+
...
4+
5+
.. altair-plot::
6+
7+
polars.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
8+

tests/test_altairplot.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
# ruff: noqa: E501
22
# Tests are inspired by the test suite of sphinx itself
3+
from __future__ import annotations
4+
5+
import re
6+
from typing import TYPE_CHECKING, cast
7+
38
import pytest
49

510
from altair import SCHEMA_URL
611
from sphinxext_altair.altairplot import (
712
VEGA_JS_URL_DEFAULT,
813
VEGAEMBED_JS_URL_DEFAULT,
914
VEGALITE_JS_URL_DEFAULT,
15+
AltairPlotWarning,
1016
purge_altair_namespaces,
1117
validate_links,
1218
)
1319

20+
if TYPE_CHECKING:
21+
from sphinx.application import Sphinx
22+
23+
from sphinxext_altair.altairplot import BuildEnvironment
24+
1425

1526
@pytest.mark.parametrize("add_namespaces_attr", [True, False])
1627
@pytest.mark.sphinx(testroot="altairplot")
17-
def test_purge_altair_namespaces(add_namespaces_attr, app):
18-
env = app.env
28+
def test_purge_altair_namespaces(add_namespaces_attr: bool, app: Sphinx) -> None:
29+
env: BuildEnvironment = cast("BuildEnvironment", app.env)
1930
if add_namespaces_attr:
2031
env._altair_namespaces = {"docname": {}}
2132

@@ -39,7 +50,7 @@ def test_purge_altair_namespaces(add_namespaces_attr, app):
3950
("editor source", {"editor": True, "source": True, "export": False}),
4051
],
4152
)
42-
def test_validate_links(links, expected):
53+
def test_validate_links(links: str, expected: str | bool | dict[str, bool]) -> None:
4354
if expected == "raise":
4455
with pytest.raises(
4556
ValueError, match=r"Following links are invalid: \['unknown'\]"
@@ -51,8 +62,15 @@ def test_validate_links(links, expected):
5162

5263

5364
@pytest.mark.sphinx(testroot="altairplot", freshenv=True)
54-
def test_altairplotdirective(app):
55-
app.builder.build_all()
65+
def test_altairplotdirective(app: Sphinx) -> None:
66+
with pytest.warns(
67+
AltairPlotWarning,
68+
match=re.compile(
69+
r"errors_warnings\.rst:5\n.+polars\.DataFrame\(\{\"a\": \[1, 2, 3\], \"b\": \[4, 5, 6\]\}\)",
70+
re.DOTALL,
71+
),
72+
):
73+
app.builder.build_all()
5674
result = (app.outdir / "index.html").read_text(encoding="utf8")
5775
assert result.count("https://cdn.jsdelivr.net/npm/vega@") == 1
5876
assert result.count("https://cdn.jsdelivr.net/npm/vega-lite@") == 1

0 commit comments

Comments
 (0)