diff --git a/src/wled/models.py b/src/wled/models.py index c068c7d8..aee514eb 100644 --- a/src/wled/models.py +++ b/src/wled/models.py @@ -887,13 +887,14 @@ def __pre_deserialize__(cls, d: dict[Any, Any]) -> dict[Any, Any]: d["effects"] = { effect_id: {"effect_id": effect_id, "name": name} for effect_id, name in enumerate(_effects) - if "RSVD" not in name + if isinstance(name, str) and "RSVD" not in name } if _palettes := d.get("palettes"): built_in_palettes = { palette_id: {"palette_id": palette_id, "name": name} for palette_id, name in enumerate(_palettes) + if isinstance(name, str) } info = d.get("info", {}) cpalcount = info.get("cpalcount", 0) @@ -957,13 +958,14 @@ def update_from_dict(self, data: dict[str, Any]) -> Device: self.effects = { effect_id: Effect(effect_id=effect_id, name=name) for effect_id, name in enumerate(_effects) - if "RSVD" not in name + if isinstance(name, str) and "RSVD" not in name } if _palettes := data.get("palettes"): built_in_palettes = { palette_id: Palette(palette_id=palette_id, name=name) for palette_id, name in enumerate(_palettes) + if isinstance(name, str) } custom_palettes = self._build_custom_palettes( self.info.custom_palette_count, self.info.version diff --git a/tests/test_models.py b/tests/test_models.py index 4ec6397d..c32bbb79 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -688,6 +688,17 @@ def test_device_update_from_dict_effects() -> None: assert device.effects[2].name == "NewEffect2" +def test_device_update_from_dict_filters_null_effects() -> None: + """Test update_from_dict filters null effects.""" + data = full_device_data() + device = Device.from_dict(data) + device.update_from_dict({"effects": ["NewEffect1", None, "NewEffect2"]}) + assert len(device.effects) == 2 + assert 1 not in device.effects + assert device.effects[0].name == "NewEffect1" + assert device.effects[2].name == "NewEffect2" + + def test_device_filters_reserved_effects() -> None: """Test that RSVD placeholder effects are filtered out.""" data = full_device_data() @@ -700,6 +711,31 @@ def test_device_filters_reserved_effects() -> None: assert device.effects[2].name == "Breathe" +def test_device_filters_null_effects() -> None: + """Test that null effects are filtered out.""" + data = full_device_data() + data["effects"] = ["Solid", None, "Breathe"] + device = Device.from_dict(data) + assert len(device.effects) == 2 + assert 1 not in device.effects + assert device.effects[0].name == "Solid" + assert device.effects[2].name == "Breathe" + + +def test_device_filters_null_palettes() -> None: + """Test that null palettes are filtered out.""" + data = full_device_data() + data["info"]["cpalcount"] = 0 + data["info"]["umpalcount"] = 0 + data["info"]["umpalnames"] = [] + data["palettes"] = ["Default", None, "Party"] + device = Device.from_dict(data) + assert len(device.palettes) == 2 + assert 1 not in device.palettes + assert device.palettes[0].name == "Default" + assert device.palettes[2].name == "Party" + + @pytest.mark.parametrize( ("version", "expected_palette_ids"), [ @@ -748,6 +784,20 @@ def test_device_update_from_dict_palettes( assert device.palettes[expected_custom_ids[1]].custom is True +def test_device_update_from_dict_filters_null_palettes() -> None: + """Test update_from_dict filters null palettes.""" + data = full_device_data() + data["info"]["cpalcount"] = 0 + data["info"]["umpalcount"] = 0 + data["info"]["umpalnames"] = [] + device = Device.from_dict(data) + device.update_from_dict({"palettes": ["Default", None, "Party"]}) + assert len(device.palettes) == 2 + assert 1 not in device.palettes + assert device.palettes[0].name == "Default" + assert device.palettes[2].name == "Party" + + def test_device_usermod_palettes() -> None: """Test usermod palettes are correctly added to device palettes.""" data = full_device_data()