Skip to content

Commit

Permalink
Check whether property value has changed after transform (#7432)
Browse files Browse the repository at this point in the history
* Check whether property value has changed after transform

* Add test
  • Loading branch information
philippjfr authored Oct 23, 2024
1 parent 7f850dc commit 4d4cd6b
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 7 deletions.
30 changes: 23 additions & 7 deletions panel/reactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -1582,16 +1582,32 @@ def _process_param_change(self, params):
def _set_on_model(self, msg: Mapping[str, Any], root: Model, model: Model) -> None:
if not msg:
return
old = self._changing.get(root.ref['id'], [])
self._changing[root.ref['id']] = [
attr for attr, value in msg.items()
if not model.lookup(attr).property.matches(getattr(model, attr), value)
]
prev_changing = self._changing.get(root.ref['id'], [])
changing = []
transformed = {}
for attr, value in msg.items():
prop = model.lookup(attr).property
old = getattr(model, attr)
try:
matches = bool(prop.matches(old, value))
except Exception:
for tp, converter in prop.alternatives:
if tp.is_valid(value):
value = converter(value)
break
try:
matches = bool(prop.matches(old, value))
except Exception:
matches = False
if not matches:
transformed[attr] = value
changing.append(attr)
self._changing[root.ref['id']] = changing
try:
model.update(**msg)
model.update(**transformed)
finally:
if old:
self._changing[root.ref['id']] = old
self._changing[root.ref['id']] = prev_changing
else:
del self._changing[root.ref['id']]

Expand Down
21 changes: 21 additions & 0 deletions panel/tests/test_custom.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import numpy as np
import pandas as pd
import param

from panel.custom import PyComponent, ReactiveESM
Expand Down Expand Up @@ -44,6 +46,25 @@ def test_py_component_cleanup(document, comm):
assert not spy._view__._models


class ESMDataFrame(ReactiveESM):

df = param.DataFrame()


def test_reactive_esm_sync_dataframe(document, comm):
esm_df = ESMDataFrame()

model = esm_df.get_root(document, comm)

esm_df.df = pd.DataFrame({"1": [2]})

assert isinstance(model.data.df, dict)
assert len(model.data.df) == 2
expected = {"index": np.array([0]), "1": np.array([2])}
for col, values in model.data.df.items():
np.testing.assert_array_equal(values, expected.get(col))


class ESMWithChildren(ReactiveESM):

child = param.ClassSelector(class_=Viewable)
Expand Down

0 comments on commit 4d4cd6b

Please sign in to comment.