Skip to content

Commit

Permalink
Merge pull request #2961 from adehad/lock_cdn_ver
Browse files Browse the repository at this point in the history
Specify version of plotly.js in CDN URL
  • Loading branch information
nicolaskruchten authored May 31, 2021
2 parents b0a5f77 + b4ecea0 commit be0dbc5
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 21 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [4.14.3] - 2021-01-12

### Fixed
- Plotly.js cdn url will now be versioned by default for:
`include_plotlyjs='cdn'` a new `include_plotlyjs='cdn-latest'` option
has the original behaviour. Prevents likelihood of htmls generated with older
`plotly.js` versions breaking with version bumps.
[2961](https://github.com/plotly/plotly.py/pull/2961)

- `px.timeline()` now allows `hover_data` formatting of start and end times [3018](https://github.com/plotly/plotly.py/pull/3018)
- Small change to packaging of `plotlywidget` extension for JupyterLab 3 [3021](https://github.com/plotly/plotly.py/pull/3021)
Expand Down
9 changes: 6 additions & 3 deletions packages/python/plotly/plotly/io/_base_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
from os.path import isdir

import six
from plotly.io import to_json, to_image, write_image, write_html
from plotly import utils, optional_imports
from plotly.io import to_json, to_image, write_image, write_html
from plotly.io._orca import ensure_server
from plotly.io._utils import plotly_cdn_url
from plotly.offline.offline import _get_jconfig, get_plotlyjs
from plotly.tools import return_figure_from_figure_or_data

Expand Down Expand Up @@ -289,7 +290,7 @@ def activate(self):
require.undef("plotly");
requirejs.config({{
paths: {{
'plotly': ['https://cdn.plot.ly/plotly-latest.min']
'plotly': ['{plotly_cdn}']
}}
}});
require(['plotly'], function(Plotly) {{
Expand All @@ -298,7 +299,9 @@ def activate(self):
}}
</script>
""".format(
win_config=_window_plotly_config, mathjax_config=_mathjax_config
win_config=_window_plotly_config,
mathjax_config=_mathjax_config,
plotly_cdn=plotly_cdn_url().rstrip(".js"),
)

else:
Expand Down
39 changes: 27 additions & 12 deletions packages/python/plotly/plotly/io/_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import six

from _plotly_utils.optional_imports import get_module
from plotly.io._utils import validate_coerce_fig_to_dict
from plotly.io._utils import validate_coerce_fig_to_dict, plotly_cdn_url
from plotly.offline.offline import _get_jconfig, get_plotlyjs
from plotly import utils

Expand Down Expand Up @@ -61,10 +61,16 @@ def to_html(
fully self-contained and can be used offline.
If 'cdn', a script tag that references the plotly.js CDN is included
in the output. HTML files generated with this option are about 3MB
smaller than those generated with include_plotlyjs=True, but they
require an active internet connection in order to load the plotly.js
library.
in the output. The url used is versioned to match the bundled plotly.js.
HTML files generated with this option are about 3MB smaller than those
generated with include_plotlyjs=True, but they require an active
internet connection in order to load the plotly.js library.
If 'cdn-latest', a script tag that always references the latest plotly.js
CDN is included in the output.
HTML files generated with this option are about 3MB smaller than those
generated with include_plotlyjs=True, but they require an active
internet connection in order to load the plotly.js library.
If 'directory', a script tag is included that references an external
plotly.min.js bundle that is assumed to reside in the same
Expand Down Expand Up @@ -266,12 +272,15 @@ def to_html(
require_start = 'require(["plotly"], function(Plotly) {'
require_end = "});"

elif include_plotlyjs == "cdn":
elif include_plotlyjs == "cdn" or include_plotlyjs == "cdn-latest":
cdn_url = plotly_cdn_url()
if include_plotlyjs == "cdn-latest":
cdn_url = plotly_cdn_url(cdn_ver="latest")
load_plotlyjs = """\
{win_config}
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>\
<script src="{cdn_url}"></script>\
""".format(
win_config=_window_plotly_config
win_config=_window_plotly_config, cdn_url=cdn_url
)

elif include_plotlyjs == "directory":
Expand Down Expand Up @@ -417,10 +426,16 @@ def write_html(
fully self-contained and can be used offline.
If 'cdn', a script tag that references the plotly.js CDN is included
in the output. HTML files generated with this option are about 3MB
smaller than those generated with include_plotlyjs=True, but they
require an active internet connection in order to load the plotly.js
library.
in the output. The url used is versioned to match the bundled plotly.js.
HTML files generated with this option are about 3MB smaller than those
generated with include_plotlyjs=True, but they require an active
internet connection in order to load the plotly.js library.
If 'cdn-latest', a script tag that always references the latest plotly.js
CDN is included in the output.
HTML files generated with this option are about 3MB smaller than those
generated with include_plotlyjs=True, but they require an active
internet connection in order to load the plotly.js library.
If 'directory', a script tag is included that references an external
plotly.min.js bundle that is assumed to reside in the same
Expand Down
6 changes: 6 additions & 0 deletions packages/python/plotly/plotly/io/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import plotly
import plotly.graph_objs as go
from plotly.offline import get_plotlyjs_version


def validate_coerce_fig_to_dict(fig, validate):
Expand Down Expand Up @@ -42,3 +43,8 @@ def validate_coerce_output_type(output_type):
Must be one of: 'Figure', 'FigureWidget'"""
)
return cls


def plotly_cdn_url(cdn_ver=get_plotlyjs_version()):
"""Return a valid plotly CDN url."""
return "https://cdn.plot.ly/plotly-{cdn_ver}.min.js".format(cdn_ver=cdn_ver,)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

import plotly
import plotly.io as pio
from plotly.io._utils import plotly_cdn_url

import json

packages_root = os.path.dirname(
Expand Down Expand Up @@ -39,7 +41,7 @@
<script type="text/javascript">\
window.PlotlyConfig = {MathJaxConfig: 'local'};</script>"""

cdn_script = '<script src="https://cdn.plot.ly/plotly-latest.min.js">' "</script>"
cdn_script = '<script src="{cdn_url}"></script>'.format(cdn_url=plotly_cdn_url())

directory_script = '<script src="plotly.min.js"></script>'

Expand Down
52 changes: 52 additions & 0 deletions packages/python/plotly/plotly/tests/test_io/test_html.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import sys

import pytest
import numpy as np


import plotly.graph_objs as go
import plotly.io as pio
from plotly.io._utils import plotly_cdn_url


if sys.version_info >= (3, 3):
import unittest.mock as mock
from unittest.mock import MagicMock
else:
import mock
from mock import MagicMock

# fixtures
# --------
@pytest.fixture
def fig1(request):
return go.Figure(
data=[
{
"type": "scatter",
"y": np.array([2, 1, 3, 2, 4, 2]),
"marker": {"color": "green"},
}
],
layout={"title": {"text": "Figure title"}},
)


# HTML
# ----
def assert_latest_cdn_connected(html):
assert plotly_cdn_url(cdn_ver="latest") in html


def assert_locked_version_cdn_connected(html):
assert plotly_cdn_url() in html


def test_latest_cdn_included(fig1):
html_str = pio.to_html(fig1, include_plotlyjs="cdn-latest")
assert_latest_cdn_connected(html_str)


def test_versioned_cdn_included(fig1):
html_str = pio.to_html(fig1, include_plotlyjs="cdn")
assert_locked_version_cdn_connected(html_str)
11 changes: 6 additions & 5 deletions packages/python/plotly/plotly/tests/test_io/test_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import plotly.graph_objs as go
import plotly.io as pio
from plotly.offline import get_plotlyjs
from plotly.io._utils import plotly_cdn_url

if sys.version_info >= (3, 3):
import unittest.mock as mock
Expand Down Expand Up @@ -134,8 +135,8 @@ def assert_not_full_html(html):
assert not html.startswith("<html")


def assert_connected(html):
assert "https://cdn.plot.ly/plotly-latest.min" in html
def assert_html_renderer_connected(html):
assert plotly_cdn_url().rstrip(".js") in html


def assert_offline(html):
Expand Down Expand Up @@ -166,7 +167,7 @@ def test_colab_renderer_show(fig1):
# Check html contents
html = mock_arg1["text/html"]
assert_full_html(html)
assert_connected(html)
assert_html_renderer_connected(html)
assert_not_requirejs(html)

# check kwargs
Expand Down Expand Up @@ -195,7 +196,7 @@ def test_notebook_connected_show(fig1, name, connected):
# Check init display contents
bundle_display_html = mock_arg1_html
if connected:
assert_connected(bundle_display_html)
assert_html_renderer_connected(bundle_display_html)
else:
assert_offline(bundle_display_html)

Expand Down Expand Up @@ -306,7 +307,7 @@ def test_repr_html(renderer):
template = (
'<div> <script type="text/javascript">'
"window.PlotlyConfig = {MathJaxConfig: 'local'};</script>\n "
'<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> '
'<script src="' + plotly_cdn_url() + '"></script> '
'<div id="cd462b94-79ce-42a2-887f-2650a761a144" class="plotly-graph-div" '
'style="height:100%; width:100%;"></div> <script type="text/javascript">'
" window.PLOTLYENV=window.PLOTLYENV || {};"
Expand Down

0 comments on commit be0dbc5

Please sign in to comment.