Fix swallowed exceptions in mochad action handlers (#181869)

This commit is contained in:
Abdellatif Anaflous
2026-09-13 14:14:42 +02:00
committed by GitHub
parent 862adee33c
commit 7830a1f466
5 changed files with 76 additions and 10 deletions
+11 -4
View File
@@ -15,6 +15,7 @@ from homeassistant.components.light import (
)
from homeassistant.const import CONF_ADDRESS, CONF_DEVICES, CONF_NAME, CONF_PLATFORM
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@@ -119,9 +120,12 @@ class MochadLight(LightEntity):
self._adjust_brightness(brightness)
self._attr_brightness = brightness
self._attr_is_on = True
# pylint: disable-next=home-assistant-action-swallowed-exception
except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="turn_on_failed",
translation_placeholders={"error": str(exc)},
) from exc
@override
def turn_off(self, **kwargs: Any) -> None:
@@ -138,6 +142,9 @@ class MochadLight(LightEntity):
if self._brightness_levels == 31:
self._attr_brightness = 0
self._attr_is_on = False
# pylint: disable-next=home-assistant-action-swallowed-exception
except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="turn_off_failed",
translation_placeholders={"error": str(exc)},
) from exc
@@ -0,0 +1,10 @@
{
"exceptions": {
"turn_off_failed": {
"message": "Failed to turn off X10 device: {error}"
},
"turn_on_failed": {
"message": "Failed to turn on X10 device: {error}"
}
}
}
+11 -4
View File
@@ -10,6 +10,7 @@ import voluptuous as vol
from homeassistant.components.switch import SwitchEntity
from homeassistant.const import CONF_ADDRESS, CONF_DEVICES, CONF_NAME, CONF_PLATFORM
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@@ -79,9 +80,12 @@ class MochadSwitch(SwitchEntity):
if self._comm_type == "pl":
self._controller.read_data()
self._attr_is_on = True
# pylint: disable-next=home-assistant-action-swallowed-exception
except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="turn_on_failed",
translation_placeholders={"error": str(exc)},
) from exc
@override
def turn_off(self, **kwargs: Any) -> None:
@@ -97,9 +101,12 @@ class MochadSwitch(SwitchEntity):
if self._comm_type == "pl":
self._controller.read_data()
self._attr_is_on = False
# pylint: disable-next=home-assistant-action-swallowed-exception
except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc)
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="turn_off_failed",
translation_placeholders={"error": str(exc)},
) from exc
def _get_device_status(self) -> bool:
"""Get the status of the switch from mochad."""
+20 -1
View File
@@ -2,11 +2,13 @@
from unittest import mock
from pymochad.exceptions import MochadException
import pytest
from homeassistant.components import light
from homeassistant.components.mochad import light as mochad
from homeassistant.components.mochad import DOMAIN, light as mochad
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.setup import async_setup_component
@@ -65,3 +67,20 @@ async def test_turn_off(light_mock) -> None:
"""Test turn_off."""
light_mock.turn_off()
light_mock.light.send_cmd.assert_called_once_with("off")
@pytest.mark.parametrize(
("brightness", "action", "translation_key"),
[(32, "turn_on", "turn_on_failed"), (32, "turn_off", "turn_off_failed")],
)
async def test_action_raises_on_communication_error(
light_mock: mochad.MochadLight, action: str, translation_key: str
) -> None:
"""Test that a failed action raises instead of being swallowed."""
light_mock.light.send_cmd.side_effect = MochadException("boom")
with pytest.raises(HomeAssistantError) as exc_info:
getattr(light_mock, action)()
assert exc_info.value.translation_domain == DOMAIN
assert exc_info.value.translation_key == translation_key
assert "error" in exc_info.value.translation_placeholders
+24 -1
View File
@@ -2,11 +2,13 @@
from unittest import mock
from pymochad.exceptions import MochadException
import pytest
from homeassistant.components import switch
from homeassistant.components.mochad import switch as mochad
from homeassistant.components.mochad import DOMAIN, switch as mochad
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.setup import async_setup_component
from tests.common import MockEntityPlatform
@@ -59,3 +61,24 @@ async def test_turn_off(switch_mock) -> None:
"""Test turn_off."""
switch_mock.turn_off()
switch_mock.switch.send_cmd.assert_called_once_with("off")
@pytest.mark.parametrize(
("action", "translation_key"),
[("turn_on", "turn_on_failed"), ("turn_off", "turn_off_failed")],
)
async def test_action_raises_on_communication_error(
switch_mock: mochad.MochadSwitch, action: str, translation_key: str
) -> None:
"""Test that a failed action raises instead of being swallowed."""
with mock.patch(
"homeassistant.components.mochad.switch.MochadException",
MochadException,
):
switch_mock.switch.send_cmd.side_effect = MochadException("boom")
with pytest.raises(HomeAssistantError) as exc_info:
getattr(switch_mock, action)()
assert exc_info.value.translation_domain == DOMAIN
assert exc_info.value.translation_key == translation_key
assert "error" in exc_info.value.translation_placeholders