-
Notifications
You must be signed in to change notification settings - Fork 322
[WIP] Add convenience methods to DelegateParameter #6832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
568b0be
87a0e79
4ed8c91
972d1c3
17794cd
40c5dd6
0c3d2e2
af26314
d044bcb
fb665d5
605c7db
d3d58bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
``DelegateParameter`` now includes validators of its source Parameter into its validators. This ensures that a ``DelegateParameter`` | ||
with a non numeric source parameter is registered correctly in a measurement when the ``DelegateParameter`` it self does not | ||
set a validator. Furthermore `DelegateParameter`` has gained ``root_source`` and ``root_delegate`` attributes that makes it easier to get the | ||
root source or ``DelegateParameter`` of a ``DelegateParameter`` that delegates to another ``DelegateParameter`` in a chain. |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -8,6 +8,8 @@ | |||||
from collections.abc import Sequence | ||||||
from datetime import datetime | ||||||
|
||||||
from qcodes.validators.validators import Validator | ||||||
|
||||||
from .parameter_base import ParamDataType, ParamRawDataType | ||||||
|
||||||
|
||||||
|
@@ -200,6 +202,40 @@ def source(self) -> Parameter | None: | |||||
def source(self, source: Parameter | None) -> None: | ||||||
self._source: Parameter | None = source | ||||||
|
||||||
@property | ||||||
def root_source(self) -> Parameter | None: | ||||||
""" | ||||||
The root source parameter that this :class:`DelegateParameter` is bound to | ||||||
or ``None`` if this :class:`DelegateParameter` is unbound. If | ||||||
the source is it self a DelegateParameter it will recursively return that Parameter's | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
source until a non DelegateParameter is found. For a non DelegateParameter source | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
this behaves the same as ``self.source`` | ||||||
|
||||||
:getter: Returns the current source. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
:setter: Sets the source of the first parameter in the tree that has a non-DelegateParameter source. | ||||||
""" | ||||||
if isinstance(self.source, DelegateParameter): | ||||||
return self.source.root_source | ||||||
else: | ||||||
return self.source | ||||||
|
||||||
@root_source.setter | ||||||
def root_source(self, source: Parameter | None) -> None: | ||||||
self.root_delegate.source = source | ||||||
|
||||||
@property | ||||||
def root_delegate(self) -> DelegateParameter: | ||||||
""" | ||||||
If this parameter is part of a chain of DelegateParameters return | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
the first Parameter in the chain that has a non DelegateParameter source | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
else return self. | ||||||
""" | ||||||
|
||||||
if not isinstance(self.source, DelegateParameter): | ||||||
return self | ||||||
else: | ||||||
return self.source.root_delegate | ||||||
|
||||||
@property | ||||||
def snapshot_value(self) -> bool: | ||||||
if self.source is None: | ||||||
|
@@ -314,3 +350,18 @@ 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)) | ||||||
|
||||||
@property | ||||||
def validators(self) -> tuple[Validator, ...]: | ||||||
""" | ||||||
Tuple of all validators associated with the parameter. Note that this | ||||||
includes validators of the source parameter if source parameter is set | ||||||
and has any validators. | ||||||
|
||||||
:getter: All validators associated with the parameter. | ||||||
""" | ||||||
source_validators: tuple[Validator, ...] = ( | ||||||
self.source.validators if self.source is not None else () | ||||||
) | ||||||
|
||||||
return tuple(self._vals) + source_validators | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just wonder, if it's cleaner (and even possible) to use super here?
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,8 +24,14 @@ | |
from qcodes.dataset.export_config import DataExportType | ||
from qcodes.dataset.measurements import Measurement | ||
from qcodes.dataset.sqlite.connection import atomic_transaction | ||
from qcodes.parameters import ManualParameter, Parameter, expand_setpoints_helper | ||
from qcodes.parameters import ( | ||
DelegateParameter, | ||
ManualParameter, | ||
Parameter, | ||
expand_setpoints_helper, | ||
) | ||
from qcodes.station import Station | ||
from qcodes.validators import ComplexNumbers | ||
from tests.common import retry_until_does_not_throw | ||
|
||
|
||
|
@@ -201,6 +207,43 @@ def test_register_custom_parameter(DAC) -> None: | |
) | ||
|
||
|
||
def test_register_delegate_parameters(): | ||
x_param = Parameter("x", set_cmd=None, get_cmd=None) | ||
|
||
complex_param = Parameter( | ||
"complex_param", get_cmd=None, set_cmd=None, vals=ComplexNumbers() | ||
) | ||
delegate_param = DelegateParameter("delegate", source=complex_param) | ||
jenshnielsen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
meas = Measurement() | ||
|
||
meas.register_parameter(x_param) | ||
meas.register_parameter(delegate_param, setpoints=(x_param,)) | ||
assert len(meas.parameters) == 2 | ||
assert meas.parameters["delegate"].type == "complex" | ||
assert meas.parameters["x"].type == "numeric" | ||
|
||
|
||
def test_register_delegate_parameters_with_late_source(): | ||
x_param = Parameter("x", set_cmd=None, get_cmd=None) | ||
|
||
complex_param = Parameter( | ||
"complex_param", get_cmd=None, set_cmd=None, vals=ComplexNumbers() | ||
) | ||
delegate_param = DelegateParameter("delegate", source=None) | ||
|
||
meas = Measurement() | ||
|
||
meas.register_parameter(x_param) | ||
|
||
delegate_param.source = complex_param | ||
|
||
meas.register_parameter(delegate_param, setpoints=(x_param,)) | ||
assert len(meas.parameters) == 2 | ||
assert meas.parameters["delegate"].type == "complex" | ||
assert meas.parameters["x"].type == "numeric" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets also add a test for delegate of delegate of complex There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A -> B -> C -> None Add source to C verify that A has the correct validator. |
||
|
||
|
||
def test_unregister_parameter(DAC, DMM) -> None: | ||
""" | ||
Test the unregistering of parameters. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,66 @@ 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_validator_delegates_as_expected() -> None: | ||
source_param = Parameter("source", set_cmd=None, get_cmd=None) | ||
delegate_param = DelegateParameter("delegate", source=source_param) | ||
some_validator = vals.Numbers(-10, 10) | ||
source_param.vals = some_validator | ||
delegate_param.vals = None | ||
delegate_param.validate(1) | ||
with pytest.raises(ValueError): | ||
delegate_param.validate(11) | ||
assert delegate_param.validators == (some_validator,) | ||
assert delegate_param.vals == some_validator | ||
|
||
|
||
def test_validator_delegates_and_source() -> None: | ||
source_param = Parameter("source", set_cmd=None, get_cmd=None) | ||
delegate_param = DelegateParameter("delegate", source=source_param) | ||
some_validator = vals.Numbers(-10, 10) | ||
some_other_validator = vals.Numbers(-5, 5) | ||
source_param.vals = some_validator | ||
delegate_param.vals = some_other_validator | ||
delegate_param.validate(1) | ||
with pytest.raises(ValueError): | ||
delegate_param.validate(6) | ||
assert delegate_param.validators == (some_other_validator, some_validator) | ||
assert delegate_param.vals == some_other_validator | ||
|
||
assert delegate_param.source is not None | ||
delegate_param.source.vals = None | ||
|
||
assert delegate_param.validators == (some_other_validator,) | ||
assert delegate_param.vals == some_other_validator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extend to 2 delegate parameters too |
||
|
||
|
||
def test_value_validation_with_offset_and_scale() -> None: | ||
source_param = Parameter( | ||
|
@@ -639,7 +704,7 @@ def test_value_validation_with_offset_and_scale() -> None: | |
delegate_param.set(1) | ||
|
||
|
||
def test_delegate_of_delegate_updates_settable_gettable(): | ||
def test_delegate_of_delegate_updates_settable_gettable() -> None: | ||
gettable_settable_source_param = Parameter( | ||
"source", set_cmd=None, get_cmd=None, vals=vals.Numbers(-5, 5) | ||
) | ||
|
@@ -672,6 +737,93 @@ def test_delegate_of_delegate_updates_settable_gettable(): | |
assert not delegate_param_outer.settable | ||
|
||
|
||
def test_delegate_of_delegate_root_source() -> None: | ||
gettable_settable_source_param = Parameter( | ||
"source", set_cmd=None, get_cmd=None, vals=vals.Numbers(-5, 5) | ||
) | ||
|
||
delegate_param_inner = DelegateParameter( | ||
"delegate_inner", source=None, vals=vals.Numbers(-10, 10) | ||
) | ||
delegate_param_outer = DelegateParameter( | ||
"delegate_outer", source=None, vals=vals.Numbers(-10, 10) | ||
) | ||
delegate_param_outer.source = delegate_param_inner | ||
delegate_param_inner.source = gettable_settable_source_param | ||
|
||
assert delegate_param_outer.root_source == gettable_settable_source_param | ||
assert delegate_param_outer.source is not None | ||
assert delegate_param_outer.source.source == gettable_settable_source_param | ||
assert delegate_param_outer.root_delegate == delegate_param_inner | ||
|
||
assert delegate_param_inner.root_source == gettable_settable_source_param | ||
assert delegate_param_inner.source == gettable_settable_source_param | ||
assert delegate_param_inner.root_delegate == delegate_param_inner | ||
|
||
delegate_param_outer.root_source = None | ||
|
||
assert delegate_param_outer.root_source is None | ||
assert delegate_param_outer.source is not None | ||
assert delegate_param_outer.source.source is None | ||
assert delegate_param_outer.root_delegate == delegate_param_inner | ||
|
||
assert delegate_param_inner.root_source is None | ||
assert delegate_param_inner.source is None | ||
assert delegate_param_inner.root_delegate == delegate_param_inner | ||
|
||
|
||
def test_delegate_chain_root_source() -> None: | ||
gettable_settable_source_param = Parameter( | ||
"source", set_cmd=None, get_cmd=None, vals=vals.Numbers(-5, 5) | ||
) | ||
|
||
delegate_param_inner = DelegateParameter( | ||
"delegate_inner", source=None, vals=vals.Numbers(-10, 10) | ||
) | ||
delegate_param_middle = DelegateParameter( | ||
"delegate_inner", source=None, vals=vals.Numbers(-10, 10) | ||
) | ||
delegate_param_outer = DelegateParameter( | ||
"delegate_outer", source=None, vals=vals.Numbers(-10, 10) | ||
) | ||
delegate_param_outer.source = delegate_param_middle | ||
delegate_param_middle.source = delegate_param_inner | ||
delegate_param_inner.source = gettable_settable_source_param | ||
|
||
assert delegate_param_outer.root_source == gettable_settable_source_param | ||
assert delegate_param_outer.source is not None | ||
assert delegate_param_outer.source.source == delegate_param_inner | ||
assert isinstance(delegate_param_outer.source.source, DelegateParameter) | ||
assert delegate_param_outer.source.source.source == gettable_settable_source_param | ||
assert delegate_param_outer.root_delegate == delegate_param_inner | ||
|
||
assert delegate_param_middle.root_source == gettable_settable_source_param | ||
assert delegate_param_middle.source == delegate_param_inner | ||
assert delegate_param_middle.source.source == gettable_settable_source_param | ||
assert delegate_param_middle.root_delegate == delegate_param_inner | ||
|
||
assert delegate_param_inner.root_source == gettable_settable_source_param | ||
assert delegate_param_inner.source == gettable_settable_source_param | ||
assert delegate_param_inner.root_delegate == delegate_param_inner | ||
|
||
delegate_param_outer.root_source = None | ||
|
||
assert delegate_param_outer.root_source is None | ||
assert delegate_param_outer.source is not None | ||
assert delegate_param_outer.source.source is not None | ||
assert delegate_param_outer.source.source.source is None | ||
assert delegate_param_outer.root_delegate == delegate_param_inner | ||
|
||
assert delegate_param_middle.root_source is None | ||
assert delegate_param_middle.source is not None | ||
assert delegate_param_middle.source.source is None | ||
assert delegate_param_outer.root_delegate == delegate_param_inner | ||
|
||
assert delegate_param_inner.root_source is None | ||
assert delegate_param_inner.source is None | ||
assert delegate_param_inner.root_delegate == delegate_param_inner | ||
|
||
|
||
def test_delegate_parameter_context() -> None: | ||
gettable_settable_source_param = Parameter( | ||
"source", set_cmd=None, get_cmd=None, vals=vals.Numbers(-5, 5) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.