From 636fd02413952b70aae9c010d56fa059b0f7448c Mon Sep 17 00:00:00 2001 From: Charvin-Admin Date: Sat, 23 May 2026 09:42:20 +0200 Subject: [PATCH] fix: prevent preset combo refresh from applying configs --- .../control/_presets_widget.py | 39 ++++++++++--------- tests/test_presets_widget.py | 23 +++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/pymmcore_widgets/control/_presets_widget.py b/src/pymmcore_widgets/control/_presets_widget.py index dc4b97b5c..1c664b45a 100644 --- a/src/pymmcore_widgets/control/_presets_widget.py +++ b/src/pymmcore_widgets/control/_presets_widget.py @@ -106,26 +106,29 @@ def _on_combo_changed(self, text: str) -> None: def _update_if_props_not_match_preset(self) -> None: if not self._mmc.getAvailableConfigs(self._group): return - for preset in self._presets: - _set_combo = True - for dev, prop, value in self._mmc.getConfigData(self._group, preset): - cache_value = self._mmc.getPropertyFromCache(dev, prop) - if cache_value != value: - _set_combo = False - break - if _set_combo: - # remove NO_MATCH if it exists - if (no_match_index := self._combo.findText(NO_MATCH)) >= 0: - self._combo.removeItem(no_match_index) - with signals_blocked(self._combo): + + with signals_blocked(self._combo): + for preset in self._presets: + _set_combo = True + for dev, prop, value in self._mmc.getConfigData(self._group, preset): + cache_value = self._mmc.getPropertyFromCache(dev, prop) + if cache_value != value: + _set_combo = False + break + if _set_combo: + # remove NO_MATCH if it exists + if (no_match_index := self._combo.findText(NO_MATCH)) >= 0: + self._combo.removeItem(no_match_index) self._combo.setCurrentText(preset) return - # if None of the presets match the current system state - # add NO_MATCH to combo if not already there - current_items = [self._combo.itemText(i) for i in range(self._combo.count())] - if NO_MATCH not in current_items: - self._combo.addItem(NO_MATCH) - with signals_blocked(self._combo): + + # if None of the presets match the current system state + # add NO_MATCH to combo if not already there + current_items = [ + self._combo.itemText(i) for i in range(self._combo.count()) + ] + if NO_MATCH not in current_items: + self._combo.addItem(NO_MATCH) self._combo.setCurrentText(NO_MATCH) @Slot(str, str) diff --git a/tests/test_presets_widget.py b/tests/test_presets_widget.py index e26a3a6d0..695f79b1c 100644 --- a/tests/test_presets_widget.py +++ b/tests/test_presets_widget.py @@ -91,3 +91,26 @@ def test_preset_widget_ignores_empty_device( qtbot.addWidget(wdg) # Should not raise RuntimeError: No device with label "" global_mmcore.events.propertyChanged.emit("", "State", "1") + + +def test_preset_widget_no_match_removal_does_not_apply_preset( + qtbot: QtBot, global_mmcore: CMMCorePlus +) -> None: + """Internal combo refreshes must not call ``setConfig``.""" + global_mmcore.setConfig("Camera", "HighRes") + wdg = PresetsWidget("Camera", mmcore=global_mmcore) + qtbot.addWidget(wdg) + + global_mmcore.setProperty("Camera", "Binning", "8") + assert wdg.value() == "" + + config_set_events: list[tuple[str, str]] = [] + global_mmcore.events.configSet.connect( + lambda group, preset: config_set_events.append((group, preset)) + ) + + global_mmcore.setProperty("Camera", "Binning", "1") + + assert wdg.value() == "HighRes" + assert global_mmcore.getCurrentConfig("Camera") == "HighRes" + assert config_set_events == []