Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/pymmcore_widgets/control/_presets_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ def _on_cfg_set(self, group: str, preset: str) -> None:

@Slot(str, str, object)
def _on_property_changed(self, device: str, property: str, value: str) -> None:
if not device:
return
if (device, property) not in self.dev_prop:
if self._mmc.getDeviceType(device) != DeviceType.StateDevice:
return
Expand Down
15 changes: 15 additions & 0 deletions tests/test_presets_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,18 @@ def test_preset_widget(qtbot: QtBot, global_mmcore: CMMCorePlus) -> None:

global_mmcore.deleteConfigGroup("Camera")
assert "Camera" not in global_mmcore.getAvailableConfigGroups()


def test_preset_widget_ignores_empty_device(
qtbot: QtBot, global_mmcore: CMMCorePlus
) -> None:
"""propertyChanged with empty device label must not raise RuntimeError.

The C++ core can emit propertyChanged("", ...) for internal state changes
with no associated device (e.g. during MDA teardown). The widget must
guard against calling getDeviceType("") in that case.
"""
wdg = PresetsWidget("Channel")
qtbot.addWidget(wdg)
# Should not raise RuntimeError: No device with label ""
global_mmcore.events.propertyChanged.emit("", "State", "1")
Loading