Skip to content

Commit f50993d

Browse files
authored
Merge pull request #461 from palewire/main
feat: add display method to BaseChart for rendering in Jupyter notebooks
2 parents 4ce777b + 8608449 commit f50993d

2 files changed

Lines changed: 118 additions & 8 deletions

File tree

datawrapper/charts/base.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,11 @@
55
from typing import Any, Literal
66

77
import pandas as pd
8-
from IPython.display import Image
8+
from IPython.display import IFrame, Image
99
from pydantic import BaseModel, ConfigDict, Field, model_serializer, model_validator
1010

1111
from datawrapper.__main__ import Datawrapper
12-
from datawrapper.charts.models import (
13-
Annotate,
14-
Describe,
15-
Publish,
16-
Transform,
17-
Visualize,
18-
)
12+
from datawrapper.charts.models import Annotate, Describe, Publish, Transform, Visualize
1913

2014

2115
class BaseChart(BaseModel):
@@ -982,6 +976,31 @@ def get_iframe_code(
982976
# Call the get_iframe_code method from the client
983977
return client.get_iframe_code(chart_id=self.chart_id, responsive=responsive)
984978

979+
def display(self, access_token: str | None = None) -> IFrame:
980+
"""Display the chart as an IFrame in a Jupyter notebook.
981+
982+
Args:
983+
access_token: Optional Datawrapper API access token.
984+
If not provided, will use DATAWRAPPER_ACCESS_TOKEN environment variable.
985+
986+
Returns:
987+
An IPython.display.IFrame object displaying the chart.
988+
989+
Raises:
990+
ValueError: If no chart_id is set or no access token is available.
991+
Exception: If the API request fails.
992+
"""
993+
if not self.chart_id:
994+
raise ValueError(
995+
"No chart_id set. Use create() first or set chart_id manually."
996+
)
997+
998+
# Get the client
999+
client = self._get_client(access_token)
1000+
1001+
# Call the display_chart method from the client
1002+
return client.display_chart(chart_id=self.chart_id)
1003+
9851004
def get_editor_url(self) -> str:
9861005
"""Get the Datawrapper editor URL for this chart.
9871006
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Test the display method on BaseChart."""
2+
3+
from unittest.mock import MagicMock, patch
4+
5+
import pytest
6+
from IPython.display import IFrame
7+
8+
from datawrapper.charts.base import BaseChart
9+
10+
11+
def test_base_chart_display_method_exists():
12+
"""Test that the display method exists on BaseChart."""
13+
chart = BaseChart(chart_type="d3-lines", title="Test Chart")
14+
assert hasattr(chart, "display")
15+
assert callable(chart.display)
16+
17+
18+
def test_base_chart_display_requires_chart_id():
19+
"""Test that display raises ValueError when chart_id is not set."""
20+
chart = BaseChart(chart_type="d3-lines", title="Test Chart")
21+
22+
with pytest.raises(ValueError, match="No chart_id set"):
23+
chart.display()
24+
25+
26+
def test_base_chart_display_with_chart_id():
27+
"""Test that display works when chart_id is set."""
28+
# Create a chart with a chart_id
29+
chart = BaseChart(
30+
chart_type="d3-lines",
31+
title="Test Display Chart",
32+
data=[{"x": 1, "y": 2}, {"x": 2, "y": 4}],
33+
)
34+
chart.chart_id = "test123"
35+
36+
# Mock the client and its display_chart method
37+
mock_client = MagicMock()
38+
mock_iframe = IFrame("https://example.com", width=600, height=400)
39+
mock_client.display_chart.return_value = mock_iframe
40+
41+
with patch.object(chart, "_get_client", return_value=mock_client):
42+
# Call the display method
43+
result = chart.display()
44+
45+
# Verify the client method was called
46+
mock_client.display_chart.assert_called_once()
47+
48+
# Verify the chart_id was passed
49+
call_kwargs = mock_client.display_chart.call_args.kwargs
50+
assert call_kwargs["chart_id"] == "test123"
51+
52+
# Verify the result is an IFrame
53+
assert result == mock_iframe
54+
assert isinstance(result, IFrame)
55+
56+
57+
def test_base_chart_display_with_access_token():
58+
"""Test that display passes access_token to the client."""
59+
# Create a chart with a chart_id
60+
chart = BaseChart(
61+
chart_type="d3-lines",
62+
title="Test Display Chart with Token",
63+
data=[{"x": 1, "y": 2}, {"x": 2, "y": 4}],
64+
)
65+
chart.chart_id = "test123"
66+
67+
# Mock the client and its display_chart method
68+
mock_client = MagicMock()
69+
mock_iframe = IFrame("https://example.com", width=600, height=400)
70+
mock_client.display_chart.return_value = mock_iframe
71+
72+
with patch.object(
73+
chart, "_get_client", return_value=mock_client
74+
) as mock_get_client:
75+
# Call the display method with an access token
76+
test_token = "test_access_token"
77+
result = chart.display(access_token=test_token)
78+
79+
# Verify _get_client was called with the access token
80+
mock_get_client.assert_called_once_with(test_token)
81+
82+
# Verify the client method was called
83+
mock_client.display_chart.assert_called_once()
84+
85+
# Verify the chart_id was passed
86+
call_kwargs = mock_client.display_chart.call_args.kwargs
87+
assert call_kwargs["chart_id"] == "test123"
88+
89+
# Verify the result is an IFrame
90+
assert result == mock_iframe
91+
assert isinstance(result, IFrame)

0 commit comments

Comments
 (0)