From c1bc3a3222d1dcd5ecb93a429c628cc6e1041a48 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Tue, 15 Sep 2020 12:47:38 +0200 Subject: [PATCH] fixed issue 1581 (#1584) * fixed issue 1581 * Handle condition where Param.parameters was set * Keep track whether parameters was explicitly set Co-authored-by: Marc Skov Madsen Co-authored-by: Philipp Rudiger --- panel/param.py | 22 +++++++++++++++++++--- panel/tests/test_param.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/panel/param.py b/panel/param.py index c9ebc626bb..f71e616278 100644 --- a/panel/param.py +++ b/panel/param.py @@ -98,7 +98,7 @@ class Param(PaneBase): name = param.String(default='', doc=""" Title of the pane.""") - parameters = param.List(default=[], doc=""" + parameters = param.List(default=[], allow_None=True, doc=""" If set this serves as a whitelist of parameters to display on the supplied Parameterized object.""") @@ -154,8 +154,13 @@ def __init__(self, object=None, **params): object = object.owner if isinstance(object, param.parameterized.Parameters): object = object.cls if object.self is None else object.self + if 'parameters' not in params and object is not None: params['parameters'] = [p for p in object.param if p != 'name'] + self._explicit_parameters = False + else: + self._explicit_parameters = object is not None + if object and 'name' not in params: params['name'] = param_name(object.name) super(Param, self).__init__(object, **params) @@ -216,17 +221,28 @@ def _update_widgets(self, *events): for event in sorted(events, key=lambda x: x.name): if event.name == 'object': if isinstance(event.new, param.parameterized.Parameters): + # Setting object will trigger this method a second time self.object = event.new.cls if event.new.self is None else event.new.self return - if event.new is None: + + if self._explicit_parameters: + parameters = self.parameters + elif event.new is None: parameters = [] else: parameters = [p for p in event.new.param if p != 'name'] self.name = param_name(event.new.name) if event.name == 'parameters': - parameters = [] if event.new == [] else event.new + if event.new is None: + self._explicit_parameters = False + if self.object is not None: + parameters = [p for p in self.object.param if p != 'name'] + else: + self._explicit_parameters = True + parameters = [] if event.new == [] else event.new if parameters != [] and parameters != self.parameters: + # Setting parameters will trigger this method a second time self.parameters = parameters return diff --git a/panel/tests/test_param.py b/panel/tests/test_param.py index e647c7571a..30eefb1264 100644 --- a/panel/tests/test_param.py +++ b/panel/tests/test_param.py @@ -1097,3 +1097,34 @@ class Test(param.Parameterized): assert test.a == 2 del os.environ['PARAM_JSON_INIT'] + +def test_change_object_and_keep_parameters(): + """Test that https://github.com/holoviz/panel/issues/1581 is solved""" + # Given + class TextModel(param.Parameterized): + text = param.String() + param2 = param.String() + + class TextView(param.Parameterized): + text = param.ClassSelector(class_=TextModel) + text_pane = param.Parameter() + + def __init__(self, **params): + params["text"] = TextModel(text="Original Text") + super().__init__(**params) + + self.text_pane = Param( + self.text, parameters=["text"] + ) + + @param.depends("text", watch=True) + def _update_text_pane(self, *_): + self.text_pane.object = self.text + + view = TextView() + assert view.text_pane.parameters==["text"] + + # When + view.text = TextModel(text="New TextModel") + # Then + assert view.text_pane.parameters==["text"]