diff --git a/quam/core/quam_classes.py b/quam/core/quam_classes.py index 4263965..db2eb46 100644 --- a/quam/core/quam_classes.py +++ b/quam/core/quam_classes.py @@ -570,7 +570,13 @@ def set_at_reference(self, attr: str, value: Any): ) parent_obj = self._get_referenced_value(parent_reference) - setattr(parent_obj, ref_attr, value) + raw_referenced_value = parent_obj.get_unreferenced_value(ref_attr) + if string_reference.is_reference(raw_referenced_value) and isinstance( + parent_obj, QuamBase + ): + parent_obj.set_at_reference(ref_attr, value) + else: + setattr(parent_obj, ref_attr, value) # Type annotation for QuamRoot, can be replaced by typing.Self from Python 3.11 diff --git a/tests/quam_base/test_set_at_reference.py b/tests/quam_base/test_set_at_reference.py index 15d016d..e422a3d 100644 --- a/tests/quam_base/test_set_at_reference.py +++ b/tests/quam_base/test_set_at_reference.py @@ -1,5 +1,6 @@ import pytest from quam.core.quam_classes import QuamBase, QuamRoot, quam_dataclass +from typing import Optional @quam_dataclass @@ -76,3 +77,81 @@ def test_set_at_absolute_reference_invalid(): with pytest.raises(AttributeError): root.set_at_reference("abs_ref", 456) + + +@quam_dataclass +class DoubleChildQuam(ChildQuam): + value: int = 0 + child: Optional[ChildQuam] = None + +def test_set_double_reference(): + """Test setting a value through a double reference""" + double_child = DoubleChildQuam(child=ChildQuam(value=42), value="#./child/value") + parent = ParentQuam(child=double_child, ref_value="#./child/value") + + assert parent.ref_value == 42 + assert parent.get_unreferenced_value("ref_value") == "#./child/value" + assert parent.child.get_unreferenced_value("value") == "#./child/value" + + # Set value through double reference + parent.set_at_reference("ref_value", 789) + + # Check that the value was set correctly in the nested child + assert double_child.child.value == 789 + assert double_child.value == 789 + assert parent.ref_value == 789 + + # Reference string should remain unchanged + assert parent.get_unreferenced_value("ref_value") == "#./child/value" + assert double_child.get_unreferenced_value("value") == "#./child/value" + + +def test_set_nonexistent_double_reference(): + """Test setting a value where the double reference does not exist""" + double_child = DoubleChildQuam(child=ChildQuam(value=42), value="#./child/nonexistent") + parent = ParentQuam(child=double_child, ref_value="#./child/nonexistent") + + with pytest.raises(AttributeError): + parent.set_at_reference("ref_value", 789) + + +def test_set_double_reference_to_nonexistent_item(): + """Test setting a value through a double reference to a nonexistent item""" + double_child = DoubleChildQuam(child=ChildQuam(value=42), value="#./nonexistent/value") + parent = ParentQuam(child=double_child, ref_value="#./nonexistent/value") + + with pytest.raises(AttributeError): + parent.set_at_reference("ref_value", 789) + + +def test_set_double_reference_with_invalid_reference(): + """Test setting a value through a double reference with an invalid reference""" + double_child = DoubleChildQuam(child=ChildQuam(value=42), value="#./child/invalid") + parent = ParentQuam(child=double_child, ref_value="#./child/invalid") + + with pytest.raises(AttributeError): + parent.set_at_reference("ref_value", 789) + +def test_set_triple_reference(): + """Test setting a value through a triple reference""" + triple_child = DoubleChildQuam(child=DoubleChildQuam(child=ChildQuam(value=42), value="#./child/value"), value="#./child/value") + parent = ParentQuam(child=triple_child, ref_value="#./child/value") + + assert parent.ref_value == 42 + assert parent.get_unreferenced_value("ref_value") == "#./child/value" + assert parent.child.get_unreferenced_value("value") == "#./child/value" + assert parent.child.child.get_unreferenced_value("value") == "#./child/value" + + # Set value through triple reference + parent.set_at_reference("ref_value", 789) + + # Check that the value was set correctly in the nested child + assert triple_child.child.child.value == 789 + assert triple_child.child.value == 789 + assert triple_child.value == 789 + assert parent.ref_value == 789 + + # Reference string should remain unchanged + assert parent.get_unreferenced_value("ref_value") == "#./child/value" + assert triple_child.get_unreferenced_value("value") == "#./child/value" + assert triple_child.child.get_unreferenced_value("value") == "#./child/value"