Add strict typing for radarr (#79242)
This commit is contained in:
parent
5981864992
commit
a809f645a7
6 changed files with 55 additions and 37 deletions
|
@ -210,6 +210,7 @@ homeassistant.components.pvoutput.*
|
|||
homeassistant.components.qnap_qsw.*
|
||||
homeassistant.components.rainmachine.*
|
||||
homeassistant.components.rdw.*
|
||||
homeassistant.components.radarr.*
|
||||
homeassistant.components.recollect_waste.*
|
||||
homeassistant.components.recorder.*
|
||||
homeassistant.components.remote.*
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""The Radarr component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from aiopyarr.models.host_configuration import PyArrHostConfiguration
|
||||
from aiopyarr.radarr_client import RadarrClient
|
||||
|
||||
|
@ -29,6 +31,7 @@ from .coordinator import (
|
|||
MoviesDataUpdateCoordinator,
|
||||
RadarrDataUpdateCoordinator,
|
||||
StatusDataUpdateCoordinator,
|
||||
T,
|
||||
)
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
|
@ -65,7 +68,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
host_configuration=host_configuration,
|
||||
session=async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL]),
|
||||
)
|
||||
coordinators: dict[str, RadarrDataUpdateCoordinator] = {
|
||||
coordinators: dict[str, RadarrDataUpdateCoordinator[Any]] = {
|
||||
"status": StatusDataUpdateCoordinator(hass, host_configuration, radarr),
|
||||
"disk_space": DiskSpaceDataUpdateCoordinator(hass, host_configuration, radarr),
|
||||
"health": HealthDataUpdateCoordinator(hass, host_configuration, radarr),
|
||||
|
@ -86,15 +89,15 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
return unload_ok
|
||||
|
||||
|
||||
class RadarrEntity(CoordinatorEntity[RadarrDataUpdateCoordinator]):
|
||||
class RadarrEntity(CoordinatorEntity[RadarrDataUpdateCoordinator[T]]):
|
||||
"""Defines a base Radarr entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
coordinator: RadarrDataUpdateCoordinator
|
||||
coordinator: RadarrDataUpdateCoordinator[T]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: RadarrDataUpdateCoordinator,
|
||||
coordinator: RadarrDataUpdateCoordinator[T],
|
||||
description: EntityDescription,
|
||||
) -> None:
|
||||
"""Create Radarr entity."""
|
||||
|
@ -113,5 +116,7 @@ class RadarrEntity(CoordinatorEntity[RadarrDataUpdateCoordinator]):
|
|||
name=self.coordinator.config_entry.title,
|
||||
)
|
||||
if isinstance(self.coordinator, StatusDataUpdateCoordinator):
|
||||
device_info[ATTR_SW_VERSION] = self.coordinator.data.version
|
||||
device_info[ATTR_SW_VERSION] = cast(
|
||||
StatusDataUpdateCoordinator, self.coordinator
|
||||
).data.version
|
||||
return device_info
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""Support for Radarr binary sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from aiopyarr import Health
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntity,
|
||||
|
@ -32,7 +34,7 @@ async def async_setup_entry(
|
|||
async_add_entities([RadarrBinarySensor(coordinator, BINARY_SENSOR_TYPE)])
|
||||
|
||||
|
||||
class RadarrBinarySensor(RadarrEntity, BinarySensorEntity):
|
||||
class RadarrBinarySensor(RadarrEntity[list[Health]], BinarySensorEntity):
|
||||
"""Implementation of a Radarr binary sensor."""
|
||||
|
||||
@property
|
||||
|
|
|
@ -3,9 +3,9 @@ from __future__ import annotations
|
|||
|
||||
from abc import abstractmethod
|
||||
from datetime import timedelta
|
||||
from typing import Generic, TypeVar, cast
|
||||
from typing import Generic, TypeVar, Union, cast
|
||||
|
||||
from aiopyarr import Health, RootFolder, SystemStatus, exceptions
|
||||
from aiopyarr import Health, RadarrMovie, RootFolder, SystemStatus, exceptions
|
||||
from aiopyarr.models.host_configuration import PyArrHostConfiguration
|
||||
from aiopyarr.radarr_client import RadarrClient
|
||||
|
||||
|
@ -16,10 +16,10 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
|||
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
T = TypeVar("T", SystemStatus, list[RootFolder], list[Health], int)
|
||||
T = TypeVar("T", bound=Union[SystemStatus, list[RootFolder], list[Health], int])
|
||||
|
||||
|
||||
class RadarrDataUpdateCoordinator(DataUpdateCoordinator, Generic[T]):
|
||||
class RadarrDataUpdateCoordinator(DataUpdateCoordinator[T], Generic[T]):
|
||||
"""Data update coordinator for the Radarr integration."""
|
||||
|
||||
config_entry: ConfigEntry
|
||||
|
@ -58,7 +58,7 @@ class RadarrDataUpdateCoordinator(DataUpdateCoordinator, Generic[T]):
|
|||
raise NotImplementedError
|
||||
|
||||
|
||||
class StatusDataUpdateCoordinator(RadarrDataUpdateCoordinator):
|
||||
class StatusDataUpdateCoordinator(RadarrDataUpdateCoordinator[SystemStatus]):
|
||||
"""Status update coordinator for Radarr."""
|
||||
|
||||
async def _fetch_data(self) -> SystemStatus:
|
||||
|
@ -66,15 +66,15 @@ class StatusDataUpdateCoordinator(RadarrDataUpdateCoordinator):
|
|||
return await self.api_client.async_get_system_status()
|
||||
|
||||
|
||||
class DiskSpaceDataUpdateCoordinator(RadarrDataUpdateCoordinator):
|
||||
class DiskSpaceDataUpdateCoordinator(RadarrDataUpdateCoordinator[list[RootFolder]]):
|
||||
"""Disk space update coordinator for Radarr."""
|
||||
|
||||
async def _fetch_data(self) -> list[RootFolder]:
|
||||
"""Fetch the data."""
|
||||
return cast(list, await self.api_client.async_get_root_folders())
|
||||
return cast(list[RootFolder], await self.api_client.async_get_root_folders())
|
||||
|
||||
|
||||
class HealthDataUpdateCoordinator(RadarrDataUpdateCoordinator):
|
||||
class HealthDataUpdateCoordinator(RadarrDataUpdateCoordinator[list[Health]]):
|
||||
"""Health update coordinator."""
|
||||
|
||||
async def _fetch_data(self) -> list[Health]:
|
||||
|
@ -82,9 +82,9 @@ class HealthDataUpdateCoordinator(RadarrDataUpdateCoordinator):
|
|||
return await self.api_client.async_get_failed_health_checks()
|
||||
|
||||
|
||||
class MoviesDataUpdateCoordinator(RadarrDataUpdateCoordinator):
|
||||
class MoviesDataUpdateCoordinator(RadarrDataUpdateCoordinator[int]):
|
||||
"""Movies update coordinator."""
|
||||
|
||||
async def _fetch_data(self) -> int:
|
||||
"""Fetch the movies data."""
|
||||
return len(cast(list, await self.api_client.async_get_movies()))
|
||||
return len(cast(list[RadarrMovie], await self.api_client.async_get_movies()))
|
||||
|
|
|
@ -4,10 +4,10 @@ from __future__ import annotations
|
|||
from collections.abc import Callable
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from datetime import timezone
|
||||
from typing import Generic
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Generic
|
||||
|
||||
from aiopyarr import Diskspace, RootFolder
|
||||
from aiopyarr import Diskspace, RootFolder, SystemStatus
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
|
@ -32,7 +32,7 @@ from homeassistant.core import HomeAssistant
|
|||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from . import RadarrEntity
|
||||
from .const import DOMAIN
|
||||
|
@ -50,8 +50,8 @@ def get_space(data: list[Diskspace], name: str) -> str:
|
|||
|
||||
|
||||
def get_modified_description(
|
||||
description: RadarrSensorEntityDescription, mount: RootFolder
|
||||
) -> tuple[RadarrSensorEntityDescription, str]:
|
||||
description: RadarrSensorEntityDescription[T], mount: RootFolder
|
||||
) -> tuple[RadarrSensorEntityDescription[T], str]:
|
||||
"""Return modified description and folder name."""
|
||||
desc = deepcopy(description)
|
||||
name = mount.path.rsplit("/")[-1].rsplit("\\")[-1]
|
||||
|
@ -64,7 +64,7 @@ def get_modified_description(
|
|||
class RadarrSensorEntityDescriptionMixIn(Generic[T]):
|
||||
"""Mixin for required keys."""
|
||||
|
||||
value_fn: Callable[[T, str], str]
|
||||
value_fn: Callable[[T, str], str | int | datetime]
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -74,12 +74,12 @@ class RadarrSensorEntityDescription(
|
|||
"""Class to describe a Radarr sensor."""
|
||||
|
||||
description_fn: Callable[
|
||||
[RadarrSensorEntityDescription, RootFolder],
|
||||
tuple[RadarrSensorEntityDescription, str] | None,
|
||||
] = lambda _, __: None
|
||||
[RadarrSensorEntityDescription[T], RootFolder],
|
||||
tuple[RadarrSensorEntityDescription[T], str] | None,
|
||||
] | None = None
|
||||
|
||||
|
||||
SENSOR_TYPES: dict[str, RadarrSensorEntityDescription] = {
|
||||
SENSOR_TYPES: dict[str, RadarrSensorEntityDescription[Any]] = {
|
||||
"disk_space": RadarrSensorEntityDescription(
|
||||
key="disk_space",
|
||||
name="Disk space",
|
||||
|
@ -88,7 +88,7 @@ SENSOR_TYPES: dict[str, RadarrSensorEntityDescription] = {
|
|||
value_fn=get_space,
|
||||
description_fn=get_modified_description,
|
||||
),
|
||||
"movie": RadarrSensorEntityDescription(
|
||||
"movie": RadarrSensorEntityDescription[int](
|
||||
key="movies",
|
||||
name="Movies",
|
||||
native_unit_of_measurement="Movies",
|
||||
|
@ -96,7 +96,7 @@ SENSOR_TYPES: dict[str, RadarrSensorEntityDescription] = {
|
|||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda data, _: data,
|
||||
),
|
||||
"status": RadarrSensorEntityDescription(
|
||||
"status": RadarrSensorEntityDescription[SystemStatus](
|
||||
key="start_time",
|
||||
name="Start time",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
|
@ -152,10 +152,10 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Radarr sensors based on a config entry."""
|
||||
coordinators: dict[str, RadarrDataUpdateCoordinator] = hass.data[DOMAIN][
|
||||
coordinators: dict[str, RadarrDataUpdateCoordinator[Any]] = hass.data[DOMAIN][
|
||||
entry.entry_id
|
||||
]
|
||||
entities = []
|
||||
entities: list[RadarrSensor[Any]] = []
|
||||
for coordinator_type, description in SENSOR_TYPES.items():
|
||||
coordinator = coordinators[coordinator_type]
|
||||
if coordinator_type != "disk_space":
|
||||
|
@ -169,16 +169,16 @@ async def async_setup_entry(
|
|||
async_add_entities(entities)
|
||||
|
||||
|
||||
class RadarrSensor(RadarrEntity, SensorEntity):
|
||||
class RadarrSensor(RadarrEntity[T], SensorEntity):
|
||||
"""Implementation of the Radarr sensor."""
|
||||
|
||||
coordinator: RadarrDataUpdateCoordinator
|
||||
entity_description: RadarrSensorEntityDescription
|
||||
coordinator: RadarrDataUpdateCoordinator[T]
|
||||
entity_description: RadarrSensorEntityDescription[T]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: RadarrDataUpdateCoordinator,
|
||||
description: RadarrSensorEntityDescription,
|
||||
coordinator: RadarrDataUpdateCoordinator[T],
|
||||
description: RadarrSensorEntityDescription[T],
|
||||
folder_name: str = "",
|
||||
) -> None:
|
||||
"""Create Radarr entity."""
|
||||
|
@ -186,6 +186,6 @@ class RadarrSensor(RadarrEntity, SensorEntity):
|
|||
self.folder_name = folder_name
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
def native_value(self) -> str | int | datetime:
|
||||
"""Return the state of the sensor."""
|
||||
return self.entity_description.value_fn(self.coordinator.data, self.folder_name)
|
||||
|
|
10
mypy.ini
10
mypy.ini
|
@ -1852,6 +1852,16 @@ disallow_untyped_defs = true
|
|||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.radarr.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_subclassing_any = true
|
||||
disallow_untyped_calls = true
|
||||
disallow_untyped_decorators = true
|
||||
disallow_untyped_defs = true
|
||||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.recollect_waste.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
|
|
Loading…
Add table
Reference in a new issue