diff --git a/cara/state.py b/cara/state.py index 9058e92d..771eba69 100644 --- a/cara/state.py +++ b/cara/state.py @@ -373,3 +373,15 @@ class DataclassStateNamed(DataclassState): def dcs_set_instance_type(self, instance_dataclass: Datamodel_T): return self._selected_state().dcs_set_instance_type(instance_dataclass) + + @contextmanager + def dcs_state_transaction(self): + orig = [s._hold_fire for s in self._states.values()] + for s in self._states.values(): + s._hold_fire = True + yield + for orig_hold, s in zip(orig, self._states.values()): + s._hold_fire = orig_hold + if s._held_events: + s._held_events.clear() + s._fire_observers() diff --git a/cara/tests/test_state.py b/cara/tests/test_state.py index adcb9ec6..34815e55 100644 --- a/cara/tests/test_state.py +++ b/cara/tests/test_state.py @@ -189,12 +189,28 @@ def test_DCS_named(): s.dcs_update_from(opt2) s.dcs_select('option 2') + opt1_observer.assert_called_once_with() + opt1_observer.reset_mock() s.dcs_update_from(opt2) assert s.dcs_instance() == opt2 # We can't observe individual states directly. opt1_observer.assert_called_once_with() + # Roll back to option 1. + s.dcs_select('option 1') + opt1_observer.reset_mock() + + # ASDA + with s.dcs_state_transaction(): + s.dcs_select('option 2') + s.dcs_update_from(opt2) + # TODO: Currently calls twice. + # opt1_observer.assert_called_once_with() + opt1_observer.reset_mock() + + assert s.dcs_instance() == opt2 + s.dcs_select('option 1') assert s.dcs_instance() == opt1