From 642864959ad40859b07904b6035f2bcdef3ae8d7 Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Sat, 28 Feb 2026 02:57:02 +0100 Subject: [PATCH] Update translatable exceptions for Powerfox integration (#164322) --- homeassistant/components/powerfox/__init__.py | 21 +++++++++++++--- .../components/powerfox/coordinator.py | 24 ++++++++++++------- .../components/powerfox/strings.json | 14 +++++++---- tests/components/powerfox/test_init.py | 11 ++++++--- tests/components/powerfox/test_sensor.py | 14 +++++++++-- 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/powerfox/__init__.py b/homeassistant/components/powerfox/__init__.py index 06ede9dc2c2..161b8c55e65 100644 --- a/homeassistant/components/powerfox/__init__.py +++ b/homeassistant/components/powerfox/__init__.py @@ -4,13 +4,19 @@ from __future__ import annotations import asyncio -from powerfox import DeviceType, Powerfox, PowerfoxConnectionError +from powerfox import ( + DeviceType, + Powerfox, + PowerfoxAuthenticationError, + PowerfoxConnectionError, +) from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, Platform from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession +from .const import DOMAIN from .coordinator import ( PowerfoxConfigEntry, PowerfoxDataUpdateCoordinator, @@ -30,9 +36,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: PowerfoxConfigEntry) -> try: devices = await client.all_devices() + except PowerfoxAuthenticationError as err: + await client.close() + raise ConfigEntryAuthFailed( + translation_domain=DOMAIN, + translation_key="auth_failed", + ) from err except PowerfoxConnectionError as err: await client.close() - raise ConfigEntryNotReady from err + raise ConfigEntryNotReady( + translation_domain=DOMAIN, + translation_key="connection_error", + ) from err coordinators: list[ PowerfoxDataUpdateCoordinator | PowerfoxReportDataUpdateCoordinator diff --git a/homeassistant/components/powerfox/coordinator.py b/homeassistant/components/powerfox/coordinator.py index 318f643b73a..ae0de87d3ee 100644 --- a/homeassistant/components/powerfox/coordinator.py +++ b/homeassistant/components/powerfox/coordinator.py @@ -59,18 +59,24 @@ class PowerfoxBaseCoordinator[T](DataUpdateCoordinator[T]): except PowerfoxAuthenticationError as err: raise ConfigEntryAuthFailed( translation_domain=DOMAIN, - translation_key="invalid_auth", - translation_placeholders={"error": str(err)}, + translation_key="auth_failed", ) from err - except ( - PowerfoxConnectionError, - PowerfoxNoDataError, - PowerfoxPrivacyError, - ) as err: + except PowerfoxConnectionError as err: raise UpdateFailed( translation_domain=DOMAIN, - translation_key="update_failed", - translation_placeholders={"error": str(err)}, + translation_key="connection_error", + ) from err + except PowerfoxNoDataError as err: + raise UpdateFailed( + translation_domain=DOMAIN, + translation_key="no_data_error", + translation_placeholders={"device_name": self.device.name}, + ) from err + except PowerfoxPrivacyError as err: + raise UpdateFailed( + translation_domain=DOMAIN, + translation_key="privacy_error", + translation_placeholders={"device_name": self.device.name}, ) from err async def _async_fetch_data(self) -> T: diff --git a/homeassistant/components/powerfox/strings.json b/homeassistant/components/powerfox/strings.json index be8169def68..6b98677cf19 100644 --- a/homeassistant/components/powerfox/strings.json +++ b/homeassistant/components/powerfox/strings.json @@ -116,11 +116,17 @@ } }, "exceptions": { - "invalid_auth": { - "message": "Error while authenticating with the Powerfox service: {error}" + "auth_failed": { + "message": "Authentication with the Powerfox service failed. Please re-authenticate your account." }, - "update_failed": { - "message": "Error while updating the Powerfox service: {error}" + "connection_error": { + "message": "Could not connect to the Powerfox service. Please check your network connection." + }, + "no_data_error": { + "message": "No data available for device \"{device_name}\". The device may not have reported data yet." + }, + "privacy_error": { + "message": "Data for device \"{device_name}\" is restricted due to privacy settings in the Powerfox app." } } } diff --git a/tests/components/powerfox/test_init.py b/tests/components/powerfox/test_init.py index 1ad60babc04..377140c338c 100644 --- a/tests/components/powerfox/test_init.py +++ b/tests/components/powerfox/test_init.py @@ -5,6 +5,7 @@ from __future__ import annotations from unittest.mock import AsyncMock from powerfox import PowerfoxAuthenticationError, PowerfoxConnectionError +import pytest from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant @@ -45,16 +46,20 @@ async def test_config_entry_not_ready( assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY -async def test_setup_entry_exception( +@pytest.mark.parametrize("method", ["all_devices", "device"]) +async def test_config_entry_auth_failed( hass: HomeAssistant, mock_powerfox_client: AsyncMock, mock_config_entry: MockConfigEntry, + method: str, ) -> None: - """Test ConfigEntryNotReady when API raises an exception during entry setup.""" + """Test ConfigEntryAuthFailed when authentication fails.""" + getattr(mock_powerfox_client, method).side_effect = PowerfoxAuthenticationError mock_config_entry.add_to_hass(hass) - mock_powerfox_client.device.side_effect = PowerfoxAuthenticationError await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR flows = hass.config_entries.flow.async_progress() diff --git a/tests/components/powerfox/test_sensor.py b/tests/components/powerfox/test_sensor.py index 459e8c61c1a..b2fb40a44b8 100644 --- a/tests/components/powerfox/test_sensor.py +++ b/tests/components/powerfox/test_sensor.py @@ -6,7 +6,12 @@ from datetime import timedelta from unittest.mock import AsyncMock, patch from freezegun.api import FrozenDateTimeFactory -from powerfox import DeviceReport, PowerfoxConnectionError +from powerfox import ( + DeviceReport, + PowerfoxConnectionError, + PowerfoxNoDataError, + PowerfoxPrivacyError, +) import pytest from syrupy.assertion import SnapshotAssertion @@ -35,11 +40,16 @@ async def test_all_sensors( await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) +@pytest.mark.parametrize( + "exception", + [PowerfoxConnectionError, PowerfoxNoDataError, PowerfoxPrivacyError], +) async def test_update_failed( hass: HomeAssistant, mock_powerfox_client: AsyncMock, mock_config_entry: MockConfigEntry, freezer: FrozenDateTimeFactory, + exception: Exception, ) -> None: """Test entities become unavailable after failed update.""" await setup_integration(hass, mock_config_entry) @@ -47,7 +57,7 @@ async def test_update_failed( assert hass.states.get("sensor.poweropti_energy_usage").state is not None - mock_powerfox_client.device.side_effect = PowerfoxConnectionError + mock_powerfox_client.device.side_effect = exception freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done()