Add strict typing for radarr (#79242)

This commit is contained in:
Marc Mueller 2022-10-07 20:53:34 +02:00 committed by GitHub
parent 5981864992
commit a809f645a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 37 deletions

View file

@ -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.*

View file

@ -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

View file

@ -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

View file

@ -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()))

View file

@ -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)

View file

@ -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