Skip to content

Commit

Permalink
Add ability to Skip Param<Ref|Function|Method> updates
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Feb 26, 2024
1 parent 9e70185 commit 86bb623
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
17 changes: 15 additions & 2 deletions panel/param.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@

import param

try:
from param import Skip
except Exception:
class Skip(RuntimeError):
"""
Exception that allows skipping an update for function-level updates.
"""
from param.parameterized import (
classlist, discard_events, eval_function_with_deps, get_method_owner,
iscoroutinefunction, resolve_ref, resolve_value,
Expand Down Expand Up @@ -829,7 +836,10 @@ async def _eval_async(self, awaitable):
self._inner_layout.append(new_obj)
self._pane = self._inner_layout[-1]
else:
self._update_inner(new_obj)
try:
self._update_inner(new_obj)
except Skip:
pass
else:
self._update_inner(await awaitable)
except Exception as e:
Expand All @@ -850,7 +860,10 @@ def _replace_pane(self, *args, force=False):
if self.object is None:
new_object = Spacer()
else:
new_object = self.eval(self.object)
try:
new_object = self.eval(self.object)
except Skip:
return
if inspect.isawaitable(new_object) or isinstance(new_object, types.AsyncGeneratorType):
param.parameterized.async_executor(partial(self._eval_async, new_object))
return
Expand Down
59 changes: 52 additions & 7 deletions panel/tests/test_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import pytest

from bokeh.models import (
AutocompleteInput as BkAutocompleteInput, Button, Checkbox as BkCheckbox,
Column as BkColumn, Div, MultiSelect, RangeSlider as BkRangeSlider,
Row as BkRow, Select, Slider, Tabs as BkTabs, TextInput,
TextInput as BkTextInput, Toggle,
AutocompleteInput as BkAutocompleteInput, Button as BkButton,
Checkbox as BkCheckbox, Column as BkColumn, Div, MultiSelect,
RangeSlider as BkRangeSlider, Row as BkRow, Select, Slider, Tabs as BkTabs,
TextInput, TextInput as BkTextInput, Toggle,
)
from packaging.version import Version

Expand All @@ -22,11 +22,11 @@
HTML, Bokeh, Markdown, Matplotlib, PaneBase, Str, panel,
)
from panel.param import (
JSONInit, Param, ParamFunction, ParamMethod,
JSONInit, Param, ParamFunction, ParamMethod, Skip,
)
from panel.tests.util import mpl_available, mpl_figure
from panel.widgets import (
AutocompleteInput, Checkbox, DatePicker, DatetimeInput,
AutocompleteInput, Button, Checkbox, DatePicker, DatetimeInput,
EditableFloatSlider, EditableRangeSlider, LiteralInput, NumberInput,
RangeSlider,
)
Expand Down Expand Up @@ -392,7 +392,7 @@ class Test(param.Parameterized):
model = test_pane.get_root(document, comm=comm)

button = model.children[1]
assert isinstance(button, Button)
assert isinstance(button, BkButton)

# Check that the action is actually executed
pn_button = test_pane.layout[1]
Expand Down Expand Up @@ -1920,3 +1920,48 @@ async def function(value):
assert root.children[0].text == '&lt;p&gt;5&lt;/p&gt;\n'
await asyncio.sleep(0.1)
assert root.children[0].text == '&lt;p&gt;6&lt;/p&gt;\n'


def test_skip_param(document, comm):
checkbox = Checkbox(value=False)
button = Button()

def layout(value, click):
if not click:
raise Skip()
return Markdown(f"{value}")

layout = ParamFunction(bind(layout, checkbox, button))

root = layout.get_root(document, comm)

div = root.children[0]
assert div.text == '&lt;pre&gt; &lt;/pre&gt;'
checkbox.value = True
assert div.text == '&lt;pre&gt; &lt;/pre&gt;'
button.param.trigger('value')
assert div.text == '&lt;pre&gt; &lt;/pre&gt;'

@pytest.mark.asyncio
async def test_async_skip_param(document, comm):
checkbox = Checkbox(value=False)
button = Button()

async def layout(value, click):
if not click:
raise Skip()
return Markdown(f"{value}")

layout = ParamFunction(bind(layout, checkbox, button))

root = layout.get_root(document, comm)

div = root.children[0]
await asyncio.sleep(0.01)
assert div.text == '&lt;pre&gt; &lt;/pre&gt;'
checkbox.value = True
await asyncio.sleep(0.01)
assert div.text == '&lt;pre&gt; &lt;/pre&gt;'
button.param.trigger('value')
await asyncio.sleep(0.01)
assert div.text == '&lt;pre&gt; &lt;/pre&gt;'

0 comments on commit 86bb623

Please sign in to comment.