From 5360e56d09b87870f06100cbabb6a663faa85f5f Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Sat, 9 Jul 2022 19:59:11 +0200 Subject: [PATCH] Remove xiaomi_miio from mypy ignore list (#74669) --- .../components/xiaomi_miio/__init__.py | 16 ++++++---- .../components/xiaomi_miio/air_quality.py | 3 +- .../components/xiaomi_miio/binary_sensor.py | 4 +-- .../components/xiaomi_miio/device.py | 4 +-- .../components/xiaomi_miio/device_tracker.py | 4 +-- homeassistant/components/xiaomi_miio/fan.py | 5 ++-- .../components/xiaomi_miio/humidifier.py | 6 +++- homeassistant/components/xiaomi_miio/light.py | 23 ++++++++++---- .../components/xiaomi_miio/sensor.py | 7 +++-- .../components/xiaomi_miio/switch.py | 20 +++++++++---- mypy.ini | 30 ------------------- script/hassfest/mypy_config.py | 10 ------- 12 files changed, 63 insertions(+), 69 deletions(-) diff --git a/homeassistant/components/xiaomi_miio/__init__.py b/homeassistant/components/xiaomi_miio/__init__.py index 17211474f97..9f0be1da528 100644 --- a/homeassistant/components/xiaomi_miio/__init__.py +++ b/homeassistant/components/xiaomi_miio/__init__.py @@ -18,6 +18,7 @@ from miio import ( CleaningDetails, CleaningSummary, ConsumableStatus, + Device as MiioDevice, DeviceException, DNDStatus, Fan, @@ -283,10 +284,10 @@ async def async_create_miio_device_and_coordinator( host = entry.data[CONF_HOST] token = entry.data[CONF_TOKEN] name = entry.title - device = None + device: MiioDevice | None = None migrate = False update_method = _async_update_data_default - coordinator_class = DataUpdateCoordinator + coordinator_class: type[DataUpdateCoordinator] = DataUpdateCoordinator if ( model not in MODELS_HUMIDIFIER @@ -345,10 +346,13 @@ async def async_create_miio_device_and_coordinator( if migrate: # Removing fan platform entity for humidifiers and migrate the name to the config entry for migration entity_registry = er.async_get(hass) + assert entry.unique_id entity_id = entity_registry.async_get_entity_id("fan", DOMAIN, entry.unique_id) if entity_id: # This check is entities that have a platform migration only and should be removed in the future - if migrate_entity_name := entity_registry.async_get(entity_id).name: + if (entity := entity_registry.async_get(entity_id)) and ( + migrate_entity_name := entity.name + ): hass.config_entries.async_update_entry(entry, title=migrate_entity_name) entity_registry.async_remove(entity_id) @@ -377,8 +381,10 @@ async def async_setup_gateway_entry(hass: HomeAssistant, entry: ConfigEntry) -> name = entry.title gateway_id = entry.unique_id + assert gateway_id + # For backwards compat - if entry.unique_id.endswith("-gateway"): + if gateway_id.endswith("-gateway"): hass.config_entries.async_update_entry(entry, unique_id=entry.data["mac"]) entry.async_on_unload(entry.add_update_listener(update_listener)) @@ -419,7 +425,7 @@ async def async_setup_gateway_entry(hass: HomeAssistant, entry: ConfigEntry) -> return async_update_data - coordinator_dict = {} + coordinator_dict: dict[str, DataUpdateCoordinator] = {} for sub_device in gateway.gateway_device.devices.values(): # Create update coordinator coordinator_dict[sub_device.sid] = DataUpdateCoordinator( diff --git a/homeassistant/components/xiaomi_miio/air_quality.py b/homeassistant/components/xiaomi_miio/air_quality.py index 10d6c6129d3..30fcaa5152a 100644 --- a/homeassistant/components/xiaomi_miio/air_quality.py +++ b/homeassistant/components/xiaomi_miio/air_quality.py @@ -1,4 +1,5 @@ """Support for Xiaomi Mi Air Quality Monitor (PM2.5).""" +from collections.abc import Callable import logging from miio import AirQualityMonitor, AirQualityMonitorCGDN1, DeviceException @@ -218,7 +219,7 @@ class AirMonitorCGDN1(XiaomiMiioEntity, AirQualityEntity): return self._particulate_matter_10 -DEVICE_MAP = { +DEVICE_MAP: dict[str, dict[str, Callable]] = { MODEL_AIRQUALITYMONITOR_S1: { "device_class": AirQualityMonitor, "entity_class": AirMonitorS1, diff --git a/homeassistant/components/xiaomi_miio/binary_sensor.py b/homeassistant/components/xiaomi_miio/binary_sensor.py index d2f00e9805c..a1e833f42de 100644 --- a/homeassistant/components/xiaomi_miio/binary_sensor.py +++ b/homeassistant/components/xiaomi_miio/binary_sensor.py @@ -1,7 +1,7 @@ """Support for Xiaomi Miio binary sensors.""" from __future__ import annotations -from collections.abc import Callable +from collections.abc import Callable, Iterable from dataclasses import dataclass import logging @@ -180,7 +180,7 @@ async def async_setup_entry( if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE: model = config_entry.data[CONF_MODEL] - sensors = [] + sensors: Iterable[str] = [] if model in MODEL_AIRFRESH_A1 or model in MODEL_AIRFRESH_T2017: sensors = AIRFRESH_A1_BINARY_SENSORS elif model in MODEL_FAN_ZA5: diff --git a/homeassistant/components/xiaomi_miio/device.py b/homeassistant/components/xiaomi_miio/device.py index dc1cf86f7df..f8b5e6bc45a 100644 --- a/homeassistant/components/xiaomi_miio/device.py +++ b/homeassistant/components/xiaomi_miio/device.py @@ -184,9 +184,9 @@ class XiaomiCoordinatedMiioEntity(CoordinatorEntity[_T]): return int(timedelta.total_seconds()) @staticmethod - def _parse_datetime_time(time: datetime.time) -> str: + def _parse_datetime_time(initial_time: datetime.time) -> str: time = datetime.datetime.now().replace( - hour=time.hour, minute=time.minute, second=0, microsecond=0 + hour=initial_time.hour, minute=initial_time.minute, second=0, microsecond=0 ) if time < datetime.datetime.now(): diff --git a/homeassistant/components/xiaomi_miio/device_tracker.py b/homeassistant/components/xiaomi_miio/device_tracker.py index 3f819d7ab7d..1ec914fc647 100644 --- a/homeassistant/components/xiaomi_miio/device_tracker.py +++ b/homeassistant/components/xiaomi_miio/device_tracker.py @@ -8,7 +8,7 @@ import voluptuous as vol from homeassistant.components.device_tracker import ( DOMAIN, - PLATFORM_SCHEMA, + PLATFORM_SCHEMA as BASE_PLATFORM_SCHEMA, DeviceScanner, ) from homeassistant.const import CONF_HOST, CONF_TOKEN @@ -18,7 +18,7 @@ from homeassistant.helpers.typing import ConfigType _LOGGER = logging.getLogger(__name__) -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = BASE_PLATFORM_SCHEMA.extend( { vol.Required(CONF_HOST): cv.string, vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)), diff --git a/homeassistant/components/xiaomi_miio/fan.py b/homeassistant/components/xiaomi_miio/fan.py index ac85955b347..8ce93933022 100644 --- a/homeassistant/components/xiaomi_miio/fan.py +++ b/homeassistant/components/xiaomi_miio/fan.py @@ -183,7 +183,8 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Fan from a config entry.""" - entities = [] + entities: list[FanEntity] = [] + entity: FanEntity if not config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE: return @@ -299,7 +300,7 @@ class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity): return self._preset_modes @property - def percentage(self) -> None: + def percentage(self) -> int | None: """Return the percentage based speed of the fan.""" return None diff --git a/homeassistant/components/xiaomi_miio/humidifier.py b/homeassistant/components/xiaomi_miio/humidifier.py index d5c829754d6..05c1eaf35bf 100644 --- a/homeassistant/components/xiaomi_miio/humidifier.py +++ b/homeassistant/components/xiaomi_miio/humidifier.py @@ -68,7 +68,8 @@ async def async_setup_entry( if not config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE: return - entities = [] + entities: list[HumidifierEntity] = [] + entity: HumidifierEntity model = config_entry.data[CONF_MODEL] unique_id = config_entry.unique_id coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR] @@ -112,6 +113,7 @@ class XiaomiGenericHumidifier(XiaomiCoordinatedMiioEntity, HumidifierEntity): _attr_device_class = HumidifierDeviceClass.HUMIDIFIER _attr_supported_features = HumidifierEntityFeature.MODES + supported_features: int def __init__(self, name, device, entry, unique_id, coordinator): """Initialize the generic Xiaomi device.""" @@ -169,6 +171,8 @@ class XiaomiGenericHumidifier(XiaomiCoordinatedMiioEntity, HumidifierEntity): class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity): """Representation of a Xiaomi Air Humidifier.""" + available_modes: list[str] + def __init__(self, name, device, entry, unique_id, coordinator): """Initialize the plug switch.""" super().__init__(name, device, entry, unique_id, coordinator) diff --git a/homeassistant/components/xiaomi_miio/light.py b/homeassistant/components/xiaomi_miio/light.py index 28feb23d93e..fd6af0d9560 100644 --- a/homeassistant/components/xiaomi_miio/light.py +++ b/homeassistant/components/xiaomi_miio/light.py @@ -1,4 +1,6 @@ """Support for Xiaomi Philips Lights.""" +from __future__ import annotations + import asyncio import datetime from datetime import timedelta @@ -6,7 +8,14 @@ from functools import partial import logging from math import ceil -from miio import Ceil, DeviceException, PhilipsBulb, PhilipsEyecare, PhilipsMoonlight +from miio import ( + Ceil, + Device as MiioDevice, + DeviceException, + PhilipsBulb, + PhilipsEyecare, + PhilipsMoonlight, +) from miio.gateway.gateway import ( GATEWAY_MODEL_AC_V1, GATEWAY_MODEL_AC_V2, @@ -115,7 +124,9 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Xiaomi light from a config entry.""" - entities = [] + entities: list[LightEntity] = [] + entity: LightEntity + light: MiioDevice if config_entry.data[CONF_FLOW_TYPE] == CONF_GATEWAY: gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY] @@ -195,7 +206,7 @@ async def async_setup_entry( async def async_service_handler(service: ServiceCall) -> None: """Map services to methods on Xiaomi Philips Lights.""" - method = SERVICE_TO_METHOD.get(service.service) + method = SERVICE_TO_METHOD[service.service] params = { key: value for key, value in service.data.items() @@ -372,7 +383,7 @@ class XiaomiPhilipsGenericLight(XiaomiPhilipsAbstractLight): @staticmethod def delayed_turn_off_timestamp( - countdown: int, current: datetime, previous: datetime + countdown: int, current: datetime.datetime, previous: datetime.datetime ): """Update the turn off timestamp only if necessary.""" if countdown is not None and countdown > 0: @@ -671,7 +682,7 @@ class XiaomiPhilipsEyecareLamp(XiaomiPhilipsGenericLight): @staticmethod def delayed_turn_off_timestamp( - countdown: int, current: datetime, previous: datetime + countdown: int, current: datetime.datetime, previous: datetime.datetime ): """Update the turn off timestamp only if necessary.""" if countdown is not None and countdown > 0: @@ -783,7 +794,7 @@ class XiaomiPhilipsMoonlightLamp(XiaomiPhilipsBulb): return 588 @property - def hs_color(self) -> tuple: + def hs_color(self) -> tuple[float, float] | None: """Return the hs color value.""" return self._hs_color diff --git a/homeassistant/components/xiaomi_miio/sensor.py b/homeassistant/components/xiaomi_miio/sensor.py index df0c953d62a..50feacf5da7 100644 --- a/homeassistant/components/xiaomi_miio/sensor.py +++ b/homeassistant/components/xiaomi_miio/sensor.py @@ -1,6 +1,7 @@ """Support for Xiaomi Mi Air Quality Monitor (PM2.5) and Humidifier.""" from __future__ import annotations +from collections.abc import Iterable from dataclasses import dataclass import logging @@ -470,7 +471,7 @@ FAN_V2_V3_SENSORS = ( FAN_ZA5_SENSORS = (ATTR_HUMIDITY, ATTR_TEMPERATURE) -MODEL_TO_SENSORS_MAP = { +MODEL_TO_SENSORS_MAP: dict[str, tuple[str, ...]] = { MODEL_AIRFRESH_A1: AIRFRESH_SENSORS_A1, MODEL_AIRFRESH_VA2: AIRFRESH_SENSORS, MODEL_AIRFRESH_T2017: AIRFRESH_SENSORS_T2017, @@ -661,7 +662,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Xiaomi sensor from a config entry.""" - entities = [] + entities: list[SensorEntity] = [] if config_entry.data[CONF_FLOW_TYPE] == CONF_GATEWAY: gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY] @@ -715,7 +716,7 @@ async def async_setup_entry( ) else: device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE] - sensors = [] + sensors: Iterable[str] = [] if model in MODEL_TO_SENSORS_MAP: sensors = MODEL_TO_SENSORS_MAP[model] elif model in MODELS_HUMIDIFIER_MIOT: diff --git a/homeassistant/components/xiaomi_miio/switch.py b/homeassistant/components/xiaomi_miio/switch.py index 05d6543e93d..e3d34e8c512 100644 --- a/homeassistant/components/xiaomi_miio/switch.py +++ b/homeassistant/components/xiaomi_miio/switch.py @@ -201,12 +201,20 @@ MODEL_TO_FEATURES_MAP = { @dataclass -class XiaomiMiioSwitchDescription(SwitchEntityDescription): +class XiaomiMiioSwitchRequiredKeyMixin: + """A class that describes switch entities.""" + + feature: int + method_on: str + method_off: str + + +@dataclass +class XiaomiMiioSwitchDescription( + SwitchEntityDescription, XiaomiMiioSwitchRequiredKeyMixin +): """A class that describes switch entities.""" - feature: int | None = None - method_on: str | None = None - method_off: str | None = None available_with_device_off: bool = True @@ -443,7 +451,7 @@ async def async_setup_other_entry(hass, config_entry, async_add_entities): async def async_service_handler(service: ServiceCall) -> None: """Map services to methods on XiaomiPlugGenericSwitch.""" - method = SERVICE_TO_METHOD.get(service.service) + method = SERVICE_TO_METHOD[service.service] params = { key: value for key, value in service.data.items() @@ -480,6 +488,8 @@ async def async_setup_other_entry(hass, config_entry, async_add_entities): class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity): """Representation of a Xiaomi Plug Generic.""" + entity_description: XiaomiMiioSwitchDescription + def __init__(self, name, device, entry, unique_id, coordinator, description): """Initialize the plug switch.""" super().__init__(name, device, entry, unique_id, coordinator) diff --git a/mypy.ini b/mypy.ini index 57544f298ab..53ebc8c74ce 100644 --- a/mypy.ini +++ b/mypy.ini @@ -2863,33 +2863,3 @@ ignore_errors = true [mypy-homeassistant.components.xbox.sensor] ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.air_quality] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.binary_sensor] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.device] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.device_tracker] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.fan] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.humidifier] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.light] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.sensor] -ignore_errors = true - -[mypy-homeassistant.components.xiaomi_miio.switch] -ignore_errors = true diff --git a/script/hassfest/mypy_config.py b/script/hassfest/mypy_config.py index 74a921c8351..fc3e26778a4 100644 --- a/script/hassfest/mypy_config.py +++ b/script/hassfest/mypy_config.py @@ -89,16 +89,6 @@ IGNORED_MODULES: Final[list[str]] = [ "homeassistant.components.xbox.browse_media", "homeassistant.components.xbox.media_source", "homeassistant.components.xbox.sensor", - "homeassistant.components.xiaomi_miio", - "homeassistant.components.xiaomi_miio.air_quality", - "homeassistant.components.xiaomi_miio.binary_sensor", - "homeassistant.components.xiaomi_miio.device", - "homeassistant.components.xiaomi_miio.device_tracker", - "homeassistant.components.xiaomi_miio.fan", - "homeassistant.components.xiaomi_miio.humidifier", - "homeassistant.components.xiaomi_miio.light", - "homeassistant.components.xiaomi_miio.sensor", - "homeassistant.components.xiaomi_miio.switch", ] # Component modules which should set no_implicit_reexport = true.