Skip to content

Commit

Permalink
Merge branch 'main' into auth_root_url
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Jan 31, 2025
2 parents a0316dc + fb24162 commit 6e0405e
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 49 deletions.
5 changes: 5 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,9 @@ def setup(app) -> None:
nbbuild.setup(app)
app.add_config_value('grid_item_link_domain', '', 'html')

# hv_sidebar_dropdown
app.add_config_value('nbsite_hv_sidebar_dropdown', {}, 'html')
app.connect("html-page-context", add_hv_sidebar_dropdown_context)


grid_item_link_domain = gallery_endpoint
10 changes: 10 additions & 0 deletions panel/chat/feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,16 @@ async def _cleanup_response(self):
self.disabled = self._disabled_stack.pop() if self._disabled_stack else False

# Public API
def scroll_to(self, index: int):
"""
Scrolls the chat log to the provided index.
Arguments
---------
index : int
The index to scroll to.
"""
self._chat_log.scroll_to(index)

def send(
self,
Expand Down
8 changes: 4 additions & 4 deletions panel/models/plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
from bokeh.events import ModelEvent
from bokeh.models import ColumnDataSource, LayoutDOM

from ..io.resources import JS_URLS, bundled_files
from ..config import config
from ..io.resources import bundled_files
from ..util import classproperty

PLOTLY_VERSION = '2.35.3'
PLOTLY_VERSION = '3.0.0'


class PlotlyEvent(ModelEvent):
Expand All @@ -28,15 +29,14 @@ class PlotlyPlot(LayoutDOM):
a bokeh plot.
"""
__css_raw__ = [
"https://api.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.css",
f"{config.npm_cdn}/maplibre-gl@4.4.1/dist/maplibre-gl.css"
]

@classproperty
def __css__(cls):
return bundled_files(cls, 'css')

__javascript_raw__ = [
JS_URLS['jQuery'],
f'https://cdn.plot.ly/plotly-{PLOTLY_VERSION}.min.js'
]

Expand Down
49 changes: 29 additions & 20 deletions panel/pane/plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from bokeh.models import ColumnDataSource
from pyviz_comms import JupyterComm

from ..util import lazy_load
from ..util import lazy_load, try_datetime64_to_datetime
from ..util.checks import datetime_types, isdatetime
from ..viewable import Layoutable
from .base import ModelPane
Expand Down Expand Up @@ -156,7 +156,7 @@ def _get_sources_for_trace(json, data, parent_path=''):
def _update_figure(self):
import plotly.graph_objs as go

if (self.object is None or type(self.object) not in (go.Figure, go.FigureWidget) or
if (self.object is None or not isinstance(self.object, (go.Figure, go.FigureWidget)) or
self.object is self._figure or not self.link_figure):
return

Expand Down Expand Up @@ -250,28 +250,37 @@ def _update_data_sources(self, cds, trace):
return update_sources

@staticmethod
def _plotly_json_wrapper(fig):
def _convert_trace(trace):
trace = dict(trace)
for key in trace:
if not isdatetime(trace[key]):
continue
arr = trace[key]
if isinstance(arr, np.ndarray):
if arr.dtype.kind == 'M' and arr.ndim == 2 and arr.shape[1] == 1:
arr = np.array([[str(try_datetime64_to_datetime(v[0]))] for v in arr])
else:
arr = arr.astype(str)
elif isinstance(arr, datetime_types):
arr = str(arr)
else:
arr = [str(v) for v in arr]
trace[key] = arr
return trace

@classmethod
def _plotly_json_wrapper(cls, fig):
"""Wraps around to_plotly_json and applies necessary fixes.
For #382: Map datetime elements to strings.
"""
json = fig.to_plotly_json()
layout = json['layout']
data = json['data']
shapes = layout.get('shapes', [])
for trace in data+shapes:
for key in trace:
if not isdatetime(trace[key]):
continue
arr = trace[key]
if isinstance(arr, np.ndarray):
arr = arr.astype(str)
elif isinstance(arr, datetime_types):
arr = str(arr)
else:
arr = [str(v) for v in arr]
trace[key] = arr
return json
layout = dict(fig._layout)
data = [cls._convert_trace(trace) for trace in fig._data]
if 'shapes' in layout:
layout['shapes'] = [
cls._convert_trace(shape) for shape in layout['shapes']
]
return {'data': data, 'layout': layout}

def _init_params(self):
viewport_params = [p for p in self.param if 'viewport' in p]
Expand Down
8 changes: 7 additions & 1 deletion panel/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from panel.io.state import set_curdoc, state
from panel.pane import HTML, Markdown
from panel.tests.util import get_open_ports
from panel.tests.util import get_open_ports, reverse_proxy as reverse_proxy_ctx
from panel.theme import Design

CUSTOM_MARKS = ('ui', 'jupyter', 'subprocess', 'docs')
Expand Down Expand Up @@ -589,3 +589,9 @@ def df_strings():
code = [f'{i:02d}' for i in range(len(descr))]

return pd.DataFrame(dict(code=code, descr=descr))


@pytest.fixture
def reverse_proxy():
with reverse_proxy_ctx() as (port, proxy):
yield port, proxy
20 changes: 10 additions & 10 deletions panel/tests/pane/test_plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,11 @@ def test_plotly_autosize(document, comm):
@plotly_available
def test_clean_relayout_data():
relayout_data = {
"mapbox.center": {"lon": -73.59183434290809, "lat": 45.52341668343991},
"mapbox.zoom": 10,
"mapbox.bearing": 0,
"mapbox.pitch": 0,
"mapbox._derived": {
"map.center": {"lon": -73.59183434290809, "lat": 45.52341668343991},
"map.zoom": 10,
"map.bearing": 0,
"map.pitch": 0,
"map._derived": {
"coordinates": [
[-73.92279747767401, 45.597934047192865],
[-73.26087120814279, 45.597934047192865],
Expand All @@ -206,10 +206,10 @@ def test_clean_relayout_data():
}
result = Plotly._clean_relayout_data(relayout_data)
assert result == {
"mapbox.center": {"lon": -73.59183434290809, "lat": 45.52341668343991},
"mapbox.zoom": 10,
"mapbox.bearing": 0,
"mapbox.pitch": 0,
"map.center": {"lon": -73.59183434290809, "lat": 45.52341668343991},
"map.zoom": 10,
"map.bearing": 0,
"map.pitch": 0,
}


Expand Down Expand Up @@ -276,7 +276,7 @@ def test_plotly_datetime_converted_2d_array(document, comm):
'longitude': np.cumsum(np.random.randn(n_points) * 0.01) + 4.8952, # Centered around Amsterdam
})

fig = px.scatter_mapbox(data, lon='longitude', lat='latitude', custom_data='timestamp')
fig = px.scatter_map(data, lon='longitude', lat='latitude', custom_data='timestamp')

p = Plotly(fig)

Expand Down
59 changes: 50 additions & 9 deletions panel/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
from panel.reactive import ReactiveHTML
from panel.template import BootstrapTemplate
from panel.tests.util import (
get_open_ports, serve_and_request, serve_and_wait, wait_until,
get_open_ports, reverse_proxy_available, serve_and_request, serve_and_wait,
wait_until,
)
from panel.widgets import (
Button, Tabulator, Terminal, TextInput,
Expand Down Expand Up @@ -904,6 +905,18 @@ def test_server_template_custom_resources(port):
with open(pathlib.Path(__file__).parent / 'assets' / 'custom.css', encoding='utf-8') as f:
assert f.read() == r.content.decode('utf-8').replace('\r\n', '\n')

@reverse_proxy_available
def test_server_template_custom_resources_on_proxy(reverse_proxy):
template = CustomBootstrapTemplate()

port, proxy = reverse_proxy
r = serve_and_request(
{'template': template}, port=port, proxy=proxy,
suffix="/proxy/components/panel.tests.test_server/CustomBootstrapTemplate/_css/assets/custom.css"
)

with open(pathlib.Path(__file__).parent / 'assets' / 'custom.css', encoding='utf-8') as f:
assert f.read() == r.content.decode('utf-8').replace('\r\n', '\n')

def test_server_template_custom_resources_with_prefix(port):
template = CustomBootstrapTemplate()
Expand All @@ -913,19 +926,46 @@ def test_server_template_custom_resources_with_prefix(port):
with open(pathlib.Path(__file__).parent / 'assets' / 'custom.css', encoding='utf-8') as f:
assert f.read() == r.content.decode('utf-8').replace('\r\n', '\n')

@reverse_proxy_available
def test_server_template_custom_resources_with_prefix_and_proxy(reverse_proxy):
(port, proxy) = reverse_proxy
template = CustomBootstrapTemplate()

path = "/proxy/prefix/components/panel.tests.test_server/CustomBootstrapTemplate/_css/assets/custom.css"
r = serve_and_request({'template': template}, port=port, proxy=proxy, prefix='/prefix', suffix=path)

with open(pathlib.Path(__file__).parent / 'assets' / 'custom.css', encoding='utf-8') as f:
assert f.read() == r.content.decode('utf-8').replace('\r\n', '\n')

def test_server_template_custom_resources_with_prefix_relative_url(port):
template = CustomBootstrapTemplate()

r = serve_and_request({'template': template}, prefix='/prefix', suffix='/prefix/template')
r = serve_and_request({'template': template}, prefix='/prefix', port=port, suffix='/prefix/template')

assert 'href="components/panel.tests.test_server/CustomBootstrapTemplate/_css/assets/custom.css"' in r.content.decode('utf-8')

@reverse_proxy_available
def test_server_template_custom_resources_with_prefix_and_proxy_relative_url(reverse_proxy):
template = CustomBootstrapTemplate()

(port, proxy) = reverse_proxy
r = serve_and_request({'template': template}, prefix='/prefix', port=port, proxy=proxy, suffix='/proxy/prefix/template')

assert 'href="components/panel.tests.test_server/CustomBootstrapTemplate/_css/assets/custom.css"' in r.content.decode('utf-8')

def test_server_template_custom_resources_with_subpath_and_prefix_relative_url(port):
template = CustomBootstrapTemplate()

r = serve_and_request({'/subpath/template': template}, prefix='/prefix', suffix='/prefix/subpath/template')
r = serve_and_request({'/subpath/template': template}, port=port, prefix='/prefix', suffix='/prefix/subpath/template')

assert 'href="../components/panel.tests.test_server/CustomBootstrapTemplate/_css/assets/custom.css"' in r.content.decode('utf-8')

@reverse_proxy_available
def test_server_template_custom_resources_with_subpath_and_prefix_and_proxy_relative_url(reverse_proxy):
template = CustomBootstrapTemplate()

port, proxy = reverse_proxy
r = serve_and_request({'/subpath/template': template}, port=port, proxy=proxy, prefix='/prefix', suffix='/proxy/prefix/subpath/template')

assert 'href="../components/panel.tests.test_server/CustomBootstrapTemplate/_css/assets/custom.css"' in r.content.decode('utf-8')

Expand All @@ -941,7 +981,7 @@ def test_server_component_custom_resources(port):
component = CustomComponent()

path = "/components/panel.tests.test_server/CustomComponent/__css__/assets/custom.css"
r = serve_and_request({'component': component}, suffix=path)
r = serve_and_request({'component': component}, suffix=path, port=port)

with open(pathlib.Path(__file__).parent / 'assets' / 'custom.css', encoding='utf-8') as f:
assert f.read() == r.content.decode('utf-8').replace('\r\n', '\n')
Expand All @@ -951,7 +991,8 @@ def test_server_component_custom_resources_with_prefix(port):
component = CustomComponent()

r = serve_and_request(
{'component': component}, prefix='/prefix', suffix="/prefix/components/panel.tests.test_server/CustomComponent/__css__/assets/custom.css"
{'component': component}, prefix='/prefix', port=port,
suffix="/prefix/components/panel.tests.test_server/CustomComponent/__css__/assets/custom.css"
)

with open(pathlib.Path(__file__).parent / 'assets' / 'custom.css', encoding='utf-8') as f:
Expand All @@ -961,31 +1002,31 @@ def test_server_component_custom_resources_with_prefix(port):
def test_server_component_custom_resources_with_prefix_relative_url(port):
component = CustomComponent()

r = serve_and_request({'component': component}, prefix='/prefix', suffix='/prefix/component')
r = serve_and_request({'component': component}, port=port, prefix='/prefix', suffix='/prefix/component')

assert f'href="components/panel.tests.test_server/CustomComponent/__css__/assets/custom.css?v={JS_VERSION}"' in r.content.decode('utf-8')


def test_server_component_custom_resources_with_subpath_and_prefix_relative_url(port):
component = CustomComponent()

r = serve_and_request({'/subpath/component': component}, prefix='/prefix', suffix='/prefix/subpath/component')
r = serve_and_request({'/subpath/component': component}, port=port, prefix='/prefix', suffix='/prefix/subpath/component')

assert f'href="../components/panel.tests.test_server/CustomComponent/__css__/assets/custom.css?v={JS_VERSION}"' in r.content.decode('utf-8')


def test_server_component_css_with_prefix_relative_url(port):
component = Terminal()

r = serve_and_request({'component': component}, suffix='/component')
r = serve_and_request({'component': component}, suffix='/component', port=port)

assert 'href="static/extensions/panel/bundled/terminal/[email protected]/css/xterm.css' in r.content.decode('utf-8')


def test_server_component_css_with_subpath_and_prefix_relative_url(port):
component = Terminal()

r = serve_and_request({'/subpath/component': component}, prefix='/prefix', suffix='/prefix/subpath/component')
r = serve_and_request({'/subpath/component': component}, prefix='/prefix', suffix='/prefix/subpath/component', port=port)

assert 'href="../static/extensions/panel/bundled/terminal/[email protected]/css/xterm.css' in r.content.decode('utf-8')

Expand Down
Loading

0 comments on commit 6e0405e

Please sign in to comment.