From 4207da03921b80b083de3894a34408a514fcdf22 Mon Sep 17 00:00:00 2001 From: Esben Bork Hansen Date: Thu, 23 Jan 2025 11:10:48 +0100 Subject: [PATCH 1/6] add vals property and setter to delegate_parameter --- src/qcodes/parameters/delegate_parameter.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/qcodes/parameters/delegate_parameter.py b/src/qcodes/parameters/delegate_parameter.py index b4c6ecfedf68..625c03a80ed3 100644 --- a/src/qcodes/parameters/delegate_parameter.py +++ b/src/qcodes/parameters/delegate_parameter.py @@ -8,6 +8,8 @@ from collections.abc import Sequence from datetime import datetime + from qcodes.validators import Validator + from .parameter_base import ParamDataType, ParamRawDataType @@ -223,6 +225,23 @@ def unit(self) -> str: def unit(self, unit: str | None) -> None: self._unit_override = unit + @property + def vals(self) -> Validator | None: + """ + The validator of the parameter. Read from source if not explicitly overwritten. + Set to None to disable overwrite. + """ + if self._vals_override is not None: + return self._vals_override + elif self.source is not None: + return self.source.vals + else: + return None + + @vals.setter + def vals(self, vals: Validator | None) -> None: + self._vals_override = vals + @property def label(self) -> str: """ From b1db7abbcda3dc9ad183004b697d90cc378892f3 Mon Sep 17 00:00:00 2001 From: Esben Bork Hansen Date: Thu, 23 Jan 2025 11:46:46 +0100 Subject: [PATCH 2/6] added change.newsfragments file --- docs/changes/newsfragments/6796.improved | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/changes/newsfragments/6796.improved diff --git a/docs/changes/newsfragments/6796.improved b/docs/changes/newsfragments/6796.improved new file mode 100644 index 000000000000..7a7ad7ee0ee9 --- /dev/null +++ b/docs/changes/newsfragments/6796.improved @@ -0,0 +1 @@ +Add vals property and @vals.setter to qcodes.parameters.delegate_parameter.DelegateParameter to propagate the Validator from source to DelegateParameter. From 734c585d69facd21935e2315f8bbc8fb4e0f3be9 Mon Sep 17 00:00:00 2001 From: Esben Bork Hansen Date: Thu, 23 Jan 2025 12:05:50 +0100 Subject: [PATCH 3/6] create self.vals in __init__ --- src/qcodes/parameters/delegate_parameter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qcodes/parameters/delegate_parameter.py b/src/qcodes/parameters/delegate_parameter.py index 625c03a80ed3..f28f75a35fa8 100644 --- a/src/qcodes/parameters/delegate_parameter.py +++ b/src/qcodes/parameters/delegate_parameter.py @@ -176,6 +176,7 @@ def __init__( super().__init__(name, *args, **kwargs) self.label = kwargs.get("label", None) self.unit = kwargs.get("unit", None) + self.vals = kwargs.get("vals", None) # Hack While we inherit the settable status from the parent parameter # we do allow param.set_to to temporary override _settable in a From 1ad1a775a079403b898dfaedbf1b4be543b504ef Mon Sep 17 00:00:00 2001 From: Esben Bork Hansen Date: Thu, 23 Jan 2025 13:40:18 +0100 Subject: [PATCH 4/6] set self._vals_override in __init__ --- src/qcodes/parameters/delegate_parameter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qcodes/parameters/delegate_parameter.py b/src/qcodes/parameters/delegate_parameter.py index f28f75a35fa8..28094ce62d48 100644 --- a/src/qcodes/parameters/delegate_parameter.py +++ b/src/qcodes/parameters/delegate_parameter.py @@ -173,6 +173,7 @@ def __init__( initial_cache_value = kwargs.pop("initial_cache_value", None) self.source = source + self._vals_override = None super().__init__(name, *args, **kwargs) self.label = kwargs.get("label", None) self.unit = kwargs.get("unit", None) @@ -334,3 +335,5 @@ def validate(self, value: ParamDataType) -> None: super().validate(value) if self.source is not None: self.source.validate(self._from_value_to_raw_value(value)) + if self.vals is not None: + self.vals.validate(value) From 1e5adfa2d5066014874387279aae21bf3b245cef Mon Sep 17 00:00:00 2001 From: Esben Bork Hansen Date: Thu, 23 Jan 2025 13:40:48 +0100 Subject: [PATCH 5/6] extend test_value_validation to cover more cases --- tests/parameter/test_delegate_parameter.py | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/parameter/test_delegate_parameter.py b/tests/parameter/test_delegate_parameter.py index 07b7d093c0f2..4e8bdb2580c5 100644 --- a/tests/parameter/test_delegate_parameter.py +++ b/tests/parameter/test_delegate_parameter.py @@ -574,18 +574,23 @@ def test_value_validation() -> None: source_param = Parameter("source", set_cmd=None, get_cmd=None) delegate_param = DelegateParameter("delegate", source=source_param) + # Test case where source parameter validator is None and delegate parameter validator is + # specified. delegate_param.vals = vals.Numbers(-10, 10) source_param.vals = None delegate_param.validate(1) with pytest.raises(ValueError): delegate_param.validate(11) + # Test where delegate parameter validator is None and source parameter validator is + # specified. delegate_param.vals = None source_param.vals = vals.Numbers(-5, 5) delegate_param.validate(1) with pytest.raises(ValueError): delegate_param.validate(6) + # Test case where source parameter validator is more restricted than delegate parameter. delegate_param.vals = vals.Numbers(-10, 10) source_param.vals = vals.Numbers(-5, 5) delegate_param.validate(1) @@ -594,6 +599,33 @@ def test_value_validation() -> None: with pytest.raises(ValueError): delegate_param.validate(11) + # Test case that the order of setting validator on source and delegate parameters does not matter. + source_param.vals = vals.Numbers(-5, 5) + delegate_param.vals = vals.Numbers(-10, 10) + delegate_param.validate(1) + with pytest.raises(ValueError): + delegate_param.validate(6) + with pytest.raises(ValueError): + delegate_param.validate(11) + + # Test case where delegate parameter validator is more restricted than source parameter. + delegate_param.vals = vals.Numbers(-5, 5) + source_param.vals = vals.Numbers(-10, 10) + delegate_param.validate(1) + with pytest.raises(ValueError): + delegate_param.validate(6) + with pytest.raises(ValueError): + delegate_param.validate(11) + + # Test case that the order of setting validator on source and delegate parameters does not matter. + source_param.vals = vals.Numbers(-10, 10) + delegate_param.vals = vals.Numbers(-5, 5) + delegate_param.validate(1) + with pytest.raises(ValueError): + delegate_param.validate(6) + with pytest.raises(ValueError): + delegate_param.validate(11) + def test_value_validation_with_offset_and_scale() -> None: source_param = Parameter( From e5298b19b837763f0a36b98db3aa5b9851335d85 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Mon, 27 Jan 2025 11:06:25 +0100 Subject: [PATCH 6/6] Fix type checking with mypy --- src/qcodes/parameters/delegate_parameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qcodes/parameters/delegate_parameter.py b/src/qcodes/parameters/delegate_parameter.py index 28094ce62d48..46bb7333b36a 100644 --- a/src/qcodes/parameters/delegate_parameter.py +++ b/src/qcodes/parameters/delegate_parameter.py @@ -173,7 +173,7 @@ def __init__( initial_cache_value = kwargs.pop("initial_cache_value", None) self.source = source - self._vals_override = None + self._vals_override: Validator | None = None super().__init__(name, *args, **kwargs) self.label = kwargs.get("label", None) self.unit = kwargs.get("unit", None)