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