diff --git a/docs/changes/newsfragments/4655.improved b/docs/changes/newsfragments/4655.improved new file mode 100644 index 00000000000..c373d503bda --- /dev/null +++ b/docs/changes/newsfragments/4655.improved @@ -0,0 +1 @@ +InstrumentBase and ParameterBase now call snapshot() on _meta_attrs attributes that inherit from Metadatable. diff --git a/qcodes/instrument/instrument_base.py b/qcodes/instrument/instrument_base.py index f8e5dd4d996..67d04576083 100644 --- a/qcodes/instrument/instrument_base.py +++ b/qcodes/instrument/instrument_base.py @@ -293,8 +293,13 @@ def snapshot_base( snap["parameters"][name] = param.snapshot(update=False) for attr in set(self._meta_attrs): - if hasattr(self, attr): - snap[attr] = getattr(self, attr) + val = getattr(self, attr, None) + if val is not None: + if isinstance(val, Metadatable): + snap[attr] = val.snapshot(update=update) + else: + snap[attr] = val + return snap def print_readable_snapshot( diff --git a/qcodes/parameters/parameter_base.py b/qcodes/parameters/parameter_base.py index 05d866e92c6..982353f563c 100644 --- a/qcodes/parameters/parameter_base.py +++ b/qcodes/parameters/parameter_base.py @@ -451,6 +451,8 @@ def snapshot_base( attr_strip = attr.lstrip("_") # strip leading underscores if isinstance(val, Validator): state[attr_strip] = repr(val) + elif isinstance(val, Metadatable): + state[attr_strip] = val.snapshot(update=update) else: state[attr_strip] = val diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py index 868ffe17ff3..8b232d49a1b 100644 --- a/qcodes/tests/test_instrument.py +++ b/qcodes/tests/test_instrument.py @@ -10,6 +10,7 @@ from qcodes.instrument import Instrument, InstrumentBase, find_or_create_instrument from qcodes.parameters import Function, Parameter +from qcodes.utils.metadata import Metadatable from .instrument_mocks import ( DummyChannelInstrument, @@ -424,3 +425,47 @@ def test_snapshot_and_meta_attrs(): assert '__class__' in snapshot assert 'InstrumentBase' in snapshot['__class__'] + + +class TestSnapshotType(Metadatable): + def __init__(self, sample_value: int) -> None: + super().__init__() + self.sample_value = sample_value + + def snapshot_base(self, update=True, params_to_skip_update=None): + return {"sample_key": self.sample_value} + + +class TestInstrument(InstrumentBase): + def __init__(self, name, label) -> None: + super().__init__(name, label=label) + self._meta_attrs.extend(["test_attribute"]) + self._test_attribute = TestSnapshotType(12) + + @property + def test_attribute(self) -> TestSnapshotType: + return self._test_attribute + + +def test_snapshot_and_meta_attrs2(): + """Test snapshot of child of InstrumentBase which contains _meta_attrs attribute that is itself Metadatable""" + instr = TestInstrument("instr", label="Label") + + assert instr.name == "instr" + + assert hasattr(instr, "_meta_attrs") + assert instr._meta_attrs == ["name", "label", "test_attribute"] + + snapshot = instr.snapshot() + + assert "name" in snapshot + assert "instr" == snapshot["name"] + + assert "label" in snapshot + assert "Label" == snapshot["label"] + + assert "__class__" in snapshot + assert "TestInstrument" in snapshot["__class__"] + + assert "test_attribute" in snapshot + assert {"sample_key": 12} == snapshot["test_attribute"]