diff --git a/param/parameterized.py b/param/parameterized.py index 5c30af6a..bf190301 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -428,6 +428,7 @@ def edit_constant(parameterized: 'Parameterized') -> Generator[None, None, None] """ kls_params = parameterized.param.objects(instance=False) inst_params = parameterized._param__private.params + init_inst_params = list(inst_params) updated = [] for pname, pobj in (kls_params | inst_params).items(): if pobj.constant: @@ -439,7 +440,7 @@ def edit_constant(parameterized: 'Parameterized') -> Generator[None, None, None] for pname in updated: # Some operations trigger a parameter instantiation (copy), # we ensure both the class and instance parameters are reset. - if pname in kls_params: + if pname in kls_params and pname not in init_inst_params: type(parameterized).param[pname].constant=True if pname in inst_params: parameterized.param[pname].constant = True diff --git a/tests/testparameterizedobject.py b/tests/testparameterizedobject.py index 07943a41..61134c15 100644 --- a/tests/testparameterizedobject.py +++ b/tests/testparameterizedobject.py @@ -329,6 +329,26 @@ def test_edit_constant(self): assert TestPO.param['const'].constant assert TestPO.param['const'].default not in (670, 891) + def test_edit_constant_does_not_mutate_cls_value_if_not_constant(self): + # Regression https://github.com/holoviz/param/issues/1100 + class P(param.Parameterized): + a = param.Number() + + + p = P() + + # Manually set p.param.a.constant to True + p.param.a.constant = True + + assert p.param.a.constant is True + assert P.param.a.constant is False + + with param.parameterized.edit_constant(p): + pass + + assert p.param.a.constant is True + assert P.param.a.constant is False + def test_readonly_parameter(self): """Test that you can't set a read-only parameter on construction or as an attribute.""" testpo = TestPO()