From f9ac89779c0b55882fa6c42b03a953ef0fc329cf Mon Sep 17 00:00:00 2001 From: Maxime Liquet <35924738+maximlt@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:19:00 +0100 Subject: [PATCH] Ensure edit_constant resets class and instance level parameters (#1015) --- param/parameterized.py | 20 ++++++++++++++------ tests/testparameterizedobject.py | 12 ++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 48855b7d..763a826a 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -340,15 +340,23 @@ def edit_constant(parameterized): Temporarily set parameters on Parameterized object to constant=False to allow editing them. """ - params = parameterized.param.objects('existing').values() - constants = [p.constant for p in params] - for p in params: - p.constant = False + kls_params = parameterized.param.objects(instance=False) + inst_params = parameterized._param__private.params + updated = [] + for pname, pobj in (kls_params | inst_params).items(): + if pobj.constant: + pobj.constant = False + updated.append(pname) try: yield finally: - for (p, const) in zip(params, constants): - p.constant = const + 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: + type(parameterized).param[pname].constant=True + if pname in inst_params: + parameterized.param[pname].constant = True @contextmanager diff --git a/tests/testparameterizedobject.py b/tests/testparameterizedobject.py index 9bb85d00..206f8048 100644 --- a/tests/testparameterizedobject.py +++ b/tests/testparameterizedobject.py @@ -19,6 +19,7 @@ ParamOverrides, Undefined, default_label_formatter, + edit_constant, no_instance_params, shared_parameters, ) @@ -313,6 +314,17 @@ def test_constant_parameter(self): testpo = TestPO() self.assertEqual(testpo.const,9) + def test_edit_constant(self): + testpo = TestPO(const=670) + # Checking no parameter was already instantiated + assert not testpo._param__private.params + with edit_constant(testpo): + testpo.const = 891 + assert testpo.const == 891 + assert testpo.param['const'].constant + assert TestPO.param['const'].constant + assert TestPO.param['const'].default not in (670, 891) + def test_readonly_parameter(self): """Test that you can't set a read-only parameter on construction or as an attribute.""" testpo = TestPO()