Skip to content

Commit

Permalink
Resolve remaining compatibility issues with bokeh 2.4 (#2696)
Browse files Browse the repository at this point in the history
* Resolve remaining compatibility issues with bokeh 2.4

* Test against bokeh 2.4 dev

* Further fixes

* Fix flake
  • Loading branch information
philippjfr authored Sep 1, 2021
1 parent dbcd7c7 commit 3b6f0c9
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 64 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
DESC: "Python ${{ matrix.python-version }} tests"
HV_REQUIREMENTS: "unit_tests"
PYTHON_VERSION: ${{ matrix.python-version }}
CHANS_DEV: "-c pyviz/label/dev -c bokeh -c conda-forge"
CHANS: "-c pyviz -c bokeh -c conda-forge"
CHANS_DEV: "-c pyviz/label/dev -c bokeh/label/dev -c conda-forge"
CHANS: "-c pyviz -c bokeh/label/dev -c conda-forge"
DISPLAY: ":99.0"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
Expand Down
9 changes: 6 additions & 3 deletions panel/io/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from bokeh.models import CustomJS
from param.parameterized import Watcher

from ..util import doc_event_obj
from .model import add_to_doc, diff
from .state import state

Expand Down Expand Up @@ -301,7 +302,8 @@ def is_embeddable(object):
values.append((ws, w_models, vals, getter))

add_to_doc(model, doc, True)
doc._held_events = []
event_obj = doc_event_obj(doc)
event_obj._held_events = []

if not widget_data:
return
Expand Down Expand Up @@ -336,12 +338,13 @@ def is_embeddable(object):
break
sub_dict = sub_dict[g(m[0])]
if skip:
doc._held_events = []
event_obj._held_events = []
continue

# Drop events originating from widgets being varied
models = [m for v in values for m in v[1]]
doc._held_events = [e for e in doc._held_events if e.model not in models]
event_obj = doc_event_obj(doc)
event_obj._held_events = [e for e in event_obj._held_events if e.model not in models]
events = record_events(doc)
changes |= events['content'] != '{}'
if events:
Expand Down
28 changes: 9 additions & 19 deletions panel/io/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from bokeh.models import Box, ColumnDataSource, Model
from bokeh.protocol import Protocol

from ..util import bokeh_version
from ..util import doc_event_obj
from .state import state

#---------------------------------------------------------------------
Expand All @@ -21,12 +21,9 @@ def diff(doc, binary=True, events=None):
Returns a json diff required to update an existing plot with
the latest plot data.
"""
event_obj = doc_event_obj(doc)
if events is None:
if bokeh_version >= '2.4':
events = list(doc.callbacks._held_events)
else:
events = list(doc._held_events)
events = list(doc._held_events) if events is None else events
events = list(event_obj._held_events)
if not events or state._hold:
return None

Expand All @@ -36,7 +33,7 @@ def diff(doc, binary=True, events=None):
and e.hint.cols is not None):
e.hint.cols = None
msg = Protocol().create("PATCH-DOC", events, use_buffers=binary)
doc._held_events = [e for e in doc._held_events if e not in events]
event_obj._held_events = [e for e in event_obj._held_events if e not in events]
return msg


Expand All @@ -60,19 +57,15 @@ def add_to_doc(obj, doc, hold=False):
# Add new root
remove_root(obj)
doc.add_root(obj)
if bokeh_version >= '2.4':
doc_hold = doc.callbacks.hold_value
else:
doc_hold = doc._hold
event_obj = doc_event_obj(doc)
doc_hold = event_obj._hold
if doc_hold is None and hold:
doc.hold()

@contextmanager
def hold(doc, policy='combine', comm=None):
if bokeh_version >= '2.4':
held = doc.callbacks.hold_value
else:
held = doc._hold
event_obj = doc_event_obj(doc)
held = event_obj._hold
try:
if policy is None:
doc.unhold()
Expand All @@ -81,10 +74,7 @@ def hold(doc, policy='combine', comm=None):
yield
finally:
if held:
if bokeh_version >= '2.4':
doc.callbacks._hold = held
else:
doc._hold = held
event_obj._hold = held
else:
if comm is not None:
from .notebook import push
Expand Down
14 changes: 6 additions & 8 deletions panel/io/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
from tornado.wsgi import WSGIContainer

# Internal imports
from ..util import bokeh_version, edit_readonly
from ..util import bokeh_version, doc_event_obj, edit_readonly
from .logging import LOG_SESSION_CREATED, LOG_SESSION_DESTROYED, LOG_SESSION_LAUNCHING

from .profile import profile_ctx
Expand Down Expand Up @@ -452,12 +452,10 @@ def unlocked():
return
connections = curdoc.session_context.session._subscribed_connections

if bokeh_version >= '2.4':
hold = curdoc.callbacks.hold_value
else:
hold = curdoc._hold
event_obj = doc_event_obj(curdoc)
hold = event_obj._hold
if hold:
old_events = list(curdoc._held_events)
old_events = list(event_obj._held_events)
else:
old_events = []
curdoc.hold()
Expand All @@ -469,7 +467,7 @@ def unlocked():
if hasattr(socket, 'write_lock') and socket.write_lock._block._value == 0:
state._locks.add(socket)
locked = socket in state._locks
for event in curdoc._held_events:
for event in event_obj._held_events:
if (isinstance(event, ModelChangedEvent) and event not in old_events
and hasattr(socket, 'write_message') and not locked):
msg = conn.protocol.create('PATCH-DOC', [event])
Expand All @@ -481,7 +479,7 @@ def unlocked():
WebSocketHandler.write_message(socket, payload, binary=True)
elif event not in events:
events.append(event)
curdoc._held_events = events
event_obj._held_events = events
finally:
if not hold:
curdoc.unhold()
Expand Down
3 changes: 2 additions & 1 deletion panel/io/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ def sync_busy(self, indicator):
if not isinstance(indicator.param.value, param.Boolean):
raise ValueError("Busy indicator must have a value parameter"
"of Boolean type.")
self._indicators.append(indicator)
if indicator not in self._indicators:
self._indicators.append(indicator)

#----------------------------------------------------------------
# Public Properties
Expand Down
18 changes: 16 additions & 2 deletions panel/template/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def __init__(self, template=None, items=None, nb_template=None, **params):
self.nb_template = nb_template or template
self._render_items = OrderedDict()
self._render_variables = {}
self._documents = []
self._server = None
self._layout = self._build_layout()

Expand Down Expand Up @@ -132,12 +133,20 @@ def _apply_modifiers(cls, viewable, mref):
def _apply_root(self, name, viewable, tags):
pass

def _server_destroy(self, session_context):
doc = session_context._document
self._documents.remove(doc)
if doc in state._locations:
del state._locations[doc]

def _init_doc(self, doc=None, comm=None, title=None, notebook=False, location=True):
doc = doc or _curdoc()
self._documents.append(doc)
title = title or 'Panel Application'
if location and self.location:
loc = self._add_location(doc, location)
doc.on_session_destroyed(loc._server_destroy)
doc.on_session_destroyed(self._server_destroy)
doc.title = title

# Initialize fake root. This is needed to ensure preprocessors
Expand Down Expand Up @@ -475,8 +484,6 @@ def __init__(self, **params):
if 'theme' in params and isinstance(params['theme'], str):
params['theme'] = THEMES[params['theme']]
super().__init__(template=template, **params)
if self.busy_indicator:
state.sync_busy(self.busy_indicator)
self._js_area = HTML(margin=0, width=0, height=0)
if '{{ embed(roots.js_area) }}' in template:
self._render_items['js_area'] = (self._js_area, [])
Expand All @@ -494,6 +501,8 @@ def __init__(self, **params):

def _init_doc(self, doc=None, comm=None, title=None, notebook=False, location=True):
title = title or self.title
if self.busy_indicator:
state.sync_busy(self.busy_indicator)
self._update_vars()
doc = super()._init_doc(doc, comm, title, notebook, location)
if self.theme:
Expand Down Expand Up @@ -698,6 +707,11 @@ def _update_render_items(self, event):
self._render_variables['header'] = any('header' in ts for ts in tags)
self._render_variables['root_labels'] = labels

def _server_destroy(self, session_context):
super()._server_destroy(session_context)
if not self._documents and self.busy_indicator in state._indicators:
state._indicators.remove(self.busy_indicator)

def open_modal(self):
"""
Opens the modal area
Expand Down
2 changes: 2 additions & 0 deletions panel/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,5 @@ def server_cleanup():
"""
yield
state.kill_all_servers()
state._indicators.clear()
state._locations.clear()
12 changes: 6 additions & 6 deletions panel/tests/io/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,18 +448,18 @@ def test_embed_merged_sliders(document, comm):
ref1, ref2 = model.children[2].ref['id'], model.children[3].ref['id']
state0 = json.loads(state_model.state[0]['content'])['events']
assert state0 == [
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref1}, "new": "1"},
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref2}, "new": "1"}
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref1}, "new": "1", "hint": None},
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref2}, "new": "1", "hint": None}
]
state1 = json.loads(state_model.state[1]['content'])['events']
assert state1 == [
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref1}, "new": "5"},
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref2}, "new": "5"}
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref1}, "new": "5", "hint": None},
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref2}, "new": "5", "hint": None}
]
state2 = json.loads(state_model.state[2]['content'])['events']
assert state2 == [
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref1}, "new": "9"},
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref2}, "new": "9"}
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref1}, "new": "9", "hint": None},
{"attr": "text", "kind": "ModelChanged", "model": {"id": ref2}, "new": "9", "hint": None}
]


Expand Down
32 changes: 19 additions & 13 deletions panel/tests/template/fast/test_fast_grid_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
# pylint: disable=missing-function-docstring,missing-module-docstring,missing-class-docstring
import holoviews as hv
import numpy as np
import panel as pn

from bokeh.document import Document
from holoviews import opts

from panel.config import config
from panel.layout import Column
from panel.pane import HoloViews, HTML, Markdown
from panel.param import Param
from panel.template.fast.grid import FastGridTemplate, FastGridDarkTheme
from panel.widgets import Button

hv.extension("bokeh")
ACCENT_COLOR = "#f63366" # "lightblue"
Expand All @@ -19,7 +25,7 @@ def test_template_theme_parameter():
template = FastGridTemplate(title="Fast", theme="dark")
# Not '#3f3f3f' which is for the Vanilla theme

doc = template.server_doc()
doc = template.server_doc(Document())
assert doc.theme._json['attrs']['Figure']['background_fill_color']=="#181818"

assert isinstance(template._get_theme(), FastGridDarkTheme)
Expand Down Expand Up @@ -107,18 +113,18 @@ def _create_hvplot():


def _navigation_menu():
return pn.pane.HTML(NAVIGATION_HTML)
return HTML(NAVIGATION_HTML)


def _sidebar_items():
return [
pn.pane.Markdown("## Settings"),
Markdown("## Settings"),
_navigation_menu(),
]


def _fast_button_card():
button = pn.widgets.Button(name="Click me", button_type="primary")
button = Button(name="Click me", button_type="primary")
button.param.name.precedence = 0
button.param.clicks.precedence = 0
button.param.disabled.precedence = 0
Expand All @@ -132,16 +138,16 @@ def _fast_button_card():
"height",
"sizing_mode",
]
settings = pn.Param(
settings = Param(
button,
parameters=button_parameters,
show_name=False,
sizing_mode="stretch_width",
)
return pn.Column(
pn.pane.HTML("<h2>Button</h2>"),
return Column(
HTML("<h2>Button</h2>"),
button,
pn.pane.HTML("<h3>Parameters</h3>"),
HTML("<h3>Parameters</h3>"),
settings,
sizing_mode="stretch_both",
)
Expand All @@ -160,15 +166,15 @@ def test_app():
# main_layout="",
save_layout=True,
)
app.main[0:7, 0:6] = pn.pane.Markdown(INFO, sizing_mode="stretch_both")
app.main[0:7, 6:12] = pn.pane.HoloViews(_create_hvplot(), sizing_mode="stretch_both")
app.main[0:7, 0:6] = Markdown(INFO, sizing_mode="stretch_both")
app.main[0:7, 6:12] = HoloViews(_create_hvplot(), sizing_mode="stretch_both")
app.main[7:18, 0:6] = _fast_button_card()
app.main[7:14, 6:12] = pn.pane.HoloViews(_create_hvplot(), sizing_mode="stretch_both")
app.main[7:14, 6:12] = HoloViews(_create_hvplot(), sizing_mode="stretch_both")
app.sidebar.extend(_sidebar_items())

return app


if __name__.startswith("bokeh"):
pn.extension(sizing_mode="stretch_width")
config.sizing_mode = "stretch_width"
test_app().servable()
12 changes: 8 additions & 4 deletions panel/tests/template/fast/test_fast_list_template.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import panel as pn

from bokeh.document import Document
from holoviews import opts

from panel.pane import HoloViews, Markdown
from panel.template.fast.list import FastListDarkTheme, FastListTemplate
from panel.tests.template.fast.test_fast_grid_template import (
INFO, _create_hvplot, _fast_button_card, _sidebar_items)
Expand All @@ -12,7 +16,7 @@ def test_template_theme_parameter():
template = FastListTemplate(title="Fast", theme="dark")
# Not '#3f3f3f' which is for the Vanilla theme

doc = template.server_doc()
doc = template.server_doc(Document())
assert doc.theme._json['attrs']['Figure']['background_fill_color']=="#181818"

assert isinstance(template._get_theme(), FastListDarkTheme)
Expand All @@ -38,10 +42,10 @@ def test_app():
shadow=True,
)
app.main[:] = [
pn.pane.Markdown(INFO, sizing_mode="stretch_both"),
pn.pane.HoloViews(_create_hvplot(), sizing_mode="stretch_both"),
Markdown(INFO, sizing_mode="stretch_both"),
HoloViews(_create_hvplot(), sizing_mode="stretch_both"),
_fast_button_card(),
pn.pane.HoloViews(_create_hvplot(), sizing_mode="stretch_both"),
HoloViews(_create_hvplot(), sizing_mode="stretch_both"),
]
app.sidebar.extend(_sidebar_items())

Expand Down
Loading

0 comments on commit 3b6f0c9

Please sign in to comment.