Suez_water: fix yesterday sensor extra_state invalid typing (#133425)

This commit is contained in:
jb101010-2 2024-12-22 23:21:52 +01:00 committed by GitHub
parent 74b425a06e
commit a3657a0fef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 38 additions and 27 deletions

View File

@ -1,9 +1,7 @@
"""Suez water update coordinator.""" """Suez water update coordinator."""
from collections.abc import Mapping
from dataclasses import dataclass from dataclasses import dataclass
from datetime import date from datetime import date
from typing import Any
from pysuez import PySuezError, SuezClient from pysuez import PySuezError, SuezClient
@ -20,11 +18,11 @@ from .const import CONF_COUNTER_ID, DATA_REFRESH_INTERVAL, DOMAIN
class SuezWaterAggregatedAttributes: class SuezWaterAggregatedAttributes:
"""Class containing aggregated sensor extra attributes.""" """Class containing aggregated sensor extra attributes."""
this_month_consumption: dict[date, float] this_month_consumption: dict[str, float]
previous_month_consumption: dict[date, float] previous_month_consumption: dict[str, float]
last_year_overall: dict[str, float] last_year_overall: dict[str, float]
this_year_overall: dict[str, float] this_year_overall: dict[str, float]
history: dict[date, float] history: dict[str, float]
highest_monthly_consumption: float highest_monthly_consumption: float
@ -33,7 +31,7 @@ class SuezWaterData:
"""Class used to hold all fetch data from suez api.""" """Class used to hold all fetch data from suez api."""
aggregated_value: float aggregated_value: float
aggregated_attr: Mapping[str, Any] aggregated_attr: SuezWaterAggregatedAttributes
price: float price: float
@ -68,18 +66,22 @@ class SuezWaterCoordinator(DataUpdateCoordinator[SuezWaterData]):
async def _async_update_data(self) -> SuezWaterData: async def _async_update_data(self) -> SuezWaterData:
"""Fetch data from API endpoint.""" """Fetch data from API endpoint."""
def map_dict(param: dict[date, float]) -> dict[str, float]:
return {str(key): value for key, value in param.items()}
try: try:
aggregated = await self._suez_client.fetch_aggregated_data() aggregated = await self._suez_client.fetch_aggregated_data()
data = SuezWaterData( data = SuezWaterData(
aggregated_value=aggregated.value, aggregated_value=aggregated.value,
aggregated_attr={ aggregated_attr=SuezWaterAggregatedAttributes(
"this_month_consumption": aggregated.current_month, this_month_consumption=map_dict(aggregated.current_month),
"previous_month_consumption": aggregated.previous_month, previous_month_consumption=map_dict(aggregated.previous_month),
"highest_monthly_consumption": aggregated.highest_monthly_consumption, highest_monthly_consumption=aggregated.highest_monthly_consumption,
"last_year_overall": aggregated.previous_year, last_year_overall=aggregated.previous_year,
"this_year_overall": aggregated.current_year, this_year_overall=aggregated.current_year,
"history": aggregated.history, history=map_dict(aggregated.history),
}, ),
price=(await self._suez_client.get_price()).price, price=(await self._suez_client.get_price()).price,
) )
except PySuezError as err: except PySuezError as err:

View File

@ -2,8 +2,8 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable, Mapping from collections.abc import Callable
from dataclasses import dataclass from dataclasses import asdict, dataclass
from typing import Any from typing import Any
from pysuez.const import ATTRIBUTION from pysuez.const import ATTRIBUTION
@ -28,7 +28,7 @@ class SuezWaterSensorEntityDescription(SensorEntityDescription):
"""Describes Suez water sensor entity.""" """Describes Suez water sensor entity."""
value_fn: Callable[[SuezWaterData], float | str | None] value_fn: Callable[[SuezWaterData], float | str | None]
attr_fn: Callable[[SuezWaterData], Mapping[str, Any] | None] = lambda _: None attr_fn: Callable[[SuezWaterData], dict[str, Any] | None] = lambda _: None
SENSORS: tuple[SuezWaterSensorEntityDescription, ...] = ( SENSORS: tuple[SuezWaterSensorEntityDescription, ...] = (
@ -38,7 +38,7 @@ SENSORS: tuple[SuezWaterSensorEntityDescription, ...] = (
native_unit_of_measurement=UnitOfVolume.LITERS, native_unit_of_measurement=UnitOfVolume.LITERS,
device_class=SensorDeviceClass.WATER, device_class=SensorDeviceClass.WATER,
value_fn=lambda suez_data: suez_data.aggregated_value, value_fn=lambda suez_data: suez_data.aggregated_value,
attr_fn=lambda suez_data: suez_data.aggregated_attr, attr_fn=lambda suez_data: asdict(suez_data.aggregated_attr),
), ),
SuezWaterSensorEntityDescription( SuezWaterSensorEntityDescription(
key="water_price", key="water_price",
@ -93,6 +93,6 @@ class SuezWaterSensor(CoordinatorEntity[SuezWaterCoordinator], SensorEntity):
return self.entity_description.value_fn(self.coordinator.data) return self.entity_description.value_fn(self.coordinator.data)
@property @property
def extra_state_attributes(self) -> Mapping[str, Any] | None: def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return extra state of the sensor.""" """Return extra state of the sensor."""
return self.entity_description.attr_fn(self.coordinator.data) return self.entity_description.attr_fn(self.coordinator.data)

View File

@ -1,6 +1,7 @@
"""Common fixtures for the Suez Water tests.""" """Common fixtures for the Suez Water tests."""
from collections.abc import Generator from collections.abc import Generator
from datetime import date
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from pysuez import AggregatedData, PriceResult from pysuez import AggregatedData, PriceResult
@ -56,22 +57,22 @@ def mock_suez_client() -> Generator[AsyncMock]:
result = AggregatedData( result = AggregatedData(
value=160, value=160,
current_month={ current_month={
"2024-01-01": 130, date.fromisoformat("2024-01-01"): 130,
"2024-01-02": 145, date.fromisoformat("2024-01-02"): 145,
}, },
previous_month={ previous_month={
"2024-12-01": 154, date.fromisoformat("2024-12-01"): 154,
"2024-12-02": 166, date.fromisoformat("2024-12-02"): 166,
}, },
current_year=1500, current_year=1500,
previous_year=1000, previous_year=1000,
attribution=ATTRIBUTION, attribution=ATTRIBUTION,
highest_monthly_consumption=2558, highest_monthly_consumption=2558,
history={ history={
"2024-01-01": 130, date.fromisoformat("2024-01-01"): 130,
"2024-01-02": 145, date.fromisoformat("2024-01-02"): 145,
"2024-12-01": 154, date.fromisoformat("2024-12-01"): 154,
"2024-12-02": 166, date.fromisoformat("2024-12-02"): 166,
}, },
) )

View File

@ -1,5 +1,6 @@
"""Test Suez_water sensor platform.""" """Test Suez_water sensor platform."""
from datetime import date
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
@ -32,6 +33,13 @@ async def test_sensors_valid_state(
assert mock_config_entry.state is ConfigEntryState.LOADED assert mock_config_entry.state is ConfigEntryState.LOADED
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
state = hass.states.get("sensor.suez_mock_device_water_usage_yesterday")
assert state
previous: dict = state.attributes["previous_month_consumption"]
assert previous
assert previous.get(date.fromisoformat("2024-12-01")) is None
assert previous.get(str(date.fromisoformat("2024-12-01"))) == 154
@pytest.mark.parametrize("method", [("fetch_aggregated_data"), ("get_price")]) @pytest.mark.parametrize("method", [("fetch_aggregated_data"), ("get_price")])
async def test_sensors_failed_update( async def test_sensors_failed_update(