From 2abe551eef7ba9db719dbebb9be5afba19a8e8b5 Mon Sep 17 00:00:00 2001 From: Glenn Waters Date: Wed, 20 Apr 2022 15:04:11 -0400 Subject: [PATCH] Complete strict typing for ElkM1 integration (#70334) --- .strict-typing | 9 +-- homeassistant/components/elkm1/sensor.py | 86 +++++++++++++++--------- mypy.ini | 79 +--------------------- 3 files changed, 55 insertions(+), 119 deletions(-) diff --git a/.strict-typing b/.strict-typing index 6dc1ac57b44..81e754f9f00 100644 --- a/.strict-typing +++ b/.strict-typing @@ -94,14 +94,7 @@ homeassistant.components.dsmr.* homeassistant.components.dunehd.* homeassistant.components.efergy.* homeassistant.components.elgato.* -homeassistant.components.elkm1.__init__ -homeassistant.components.elkm1.alarm_control_panel -homeassistant.components.elkm1.climate -homeassistant.components.elkm1.config_flow -homeassistant.components.elkm1.discovery -homeassistant.components.elkm1.light -homeassistant.components.elkm1.scene -homeassistant.components.elkm1.switch +homeassistant.components.elkm1.* homeassistant.components.esphome.* homeassistant.components.energy.* homeassistant.components.evil_genius_labs.* diff --git a/homeassistant/components/elkm1/sensor.py b/homeassistant/components/elkm1/sensor.py index 12f7d96af62..e41d09e2e76 100644 --- a/homeassistant/components/elkm1/sensor.py +++ b/homeassistant/components/elkm1/sensor.py @@ -1,13 +1,22 @@ """Support for control of ElkM1 sensors.""" from __future__ import annotations +from typing import Any + from elkm1_lib.const import ( SettingFormat, ZoneLogicalStatus, ZonePhysicalStatus, ZoneType, ) +from elkm1_lib.counters import Counter +from elkm1_lib.elements import Element +from elkm1_lib.elk import Elk +from elkm1_lib.keypads import Keypad +from elkm1_lib.panel import Panel +from elkm1_lib.settings import Setting from elkm1_lib.util import pretty_const +from elkm1_lib.zones import Zone import voluptuous as vol from homeassistant.components.sensor import SensorEntity @@ -73,43 +82,45 @@ async def async_setup_entry( ) -def temperature_to_state(temperature, undefined_temperature): +def temperature_to_state(temperature: int, undefined_temperature: int) -> str | None: """Convert temperature to a state.""" - return temperature if temperature > undefined_temperature else None + return f"{temperature}" if temperature > undefined_temperature else None class ElkSensor(ElkAttachedEntity, SensorEntity): """Base representation of Elk-M1 sensor.""" - def __init__(self, element, elk, elk_data): + def __init__(self, element: Element, elk: Elk, elk_data: dict[str, Any]) -> None: """Initialize the base of all Elk sensors.""" super().__init__(element, elk, elk_data) - self._state = None + self._state: str | None = None @property - def native_value(self): + def native_value(self) -> str | None: """Return the state of the sensor.""" return self._state - async def async_counter_refresh(self): + async def async_counter_refresh(self) -> None: """Refresh the value of a counter from the panel.""" if not isinstance(self, ElkCounter): raise HomeAssistantError("supported only on ElkM1 Counter sensors") self._element.get() - async def async_counter_set(self, value=None): + async def async_counter_set(self, value: int | None = None) -> None: """Set the value of a counter on the panel.""" if not isinstance(self, ElkCounter): raise HomeAssistantError("supported only on ElkM1 Counter sensors") - self._element.set(value) + if value is not None: + self._element.set(value) - async def async_zone_bypass(self, code=None): + async def async_zone_bypass(self, code: int | None = None) -> None: """Bypass zone.""" if not isinstance(self, ElkZone): raise HomeAssistantError("supported only on ElkM1 Zone sensors") - self._element.bypass(code) + if code is not None: + self._element.bypass(code) - async def async_zone_trigger(self): + async def async_zone_trigger(self) -> None: """Trigger zone.""" if not isinstance(self, ElkZone): raise HomeAssistantError("supported only on ElkM1 Zone sensors") @@ -119,37 +130,41 @@ class ElkSensor(ElkAttachedEntity, SensorEntity): class ElkCounter(ElkSensor): """Representation of an Elk-M1 Counter.""" + _element: Counter + @property - def icon(self): + def icon(self) -> str: """Icon to use in the frontend.""" return "mdi:numeric" - def _element_changed(self, element, changeset): + def _element_changed(self, _: Element, changeset: Any) -> None: self._state = self._element.value class ElkKeypad(ElkSensor): """Representation of an Elk-M1 Keypad.""" + _element: Keypad + @property - def temperature_unit(self): + def temperature_unit(self) -> str: """Return the temperature unit.""" return self._temperature_unit @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str: """Return the unit of measurement.""" return self._temperature_unit @property - def icon(self): + def icon(self) -> str: """Icon to use in the frontend.""" return "mdi:thermometer-lines" @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Attributes of the sensor.""" - attrs = self.initial_attrs() + attrs: dict[str, Any] = self.initial_attrs() attrs["area"] = self._element.area + 1 attrs["temperature"] = self._state attrs["last_user_time"] = self._element.last_user_time.isoformat() @@ -159,7 +174,7 @@ class ElkKeypad(ElkSensor): attrs["last_keypress"] = self._element.last_keypress return attrs - def _element_changed(self, element, changeset): + def _element_changed(self, _: Element, changeset: Any) -> None: self._state = temperature_to_state( self._element.temperature, UNDEFINED_TEMPERATURE ) @@ -169,20 +184,21 @@ class ElkPanel(ElkSensor): """Representation of an Elk-M1 Panel.""" _attr_entity_category = EntityCategory.DIAGNOSTIC + _element: Panel @property - def icon(self): + def icon(self) -> str: """Icon to use in the frontend.""" return "mdi:home" @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Attributes of the sensor.""" attrs = self.initial_attrs() attrs["system_trouble_status"] = self._element.system_trouble_status return attrs - def _element_changed(self, element, changeset): + def _element_changed(self, _: Element, changeset: Any) -> None: if self._elk.is_connected(): self._state = ( "Paused" if self._element.remote_programming_status else "Connected" @@ -194,18 +210,20 @@ class ElkPanel(ElkSensor): class ElkSetting(ElkSensor): """Representation of an Elk-M1 Setting.""" + _element: Setting + @property - def icon(self): + def icon(self) -> str: """Icon to use in the frontend.""" return "mdi:numeric" - def _element_changed(self, element, changeset): + def _element_changed(self, _: Element, changeset: Any) -> None: self._state = self._element.value @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Attributes of the sensor.""" - attrs = self.initial_attrs() + attrs: dict[str, Any] = self.initial_attrs() attrs["value_format"] = SettingFormat(self._element.value_format).name.lower() return attrs @@ -213,8 +231,10 @@ class ElkSetting(ElkSensor): class ElkZone(ElkSensor): """Representation of an Elk-M1 Zone.""" + _element: Zone + @property - def icon(self): + def icon(self) -> str: """Icon to use in the frontend.""" zone_icons = { ZoneType.FIRE_ALARM.value: "fire", @@ -240,9 +260,9 @@ class ElkZone(ElkSensor): return f"mdi:{zone_icons.get(self._element.definition, 'alarm-bell')}" @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Attributes of the sensor.""" - attrs = self.initial_attrs() + attrs: dict[str, Any] = self.initial_attrs() attrs["physical_status"] = ZonePhysicalStatus( self._element.physical_status ).name.lower() @@ -255,14 +275,14 @@ class ElkZone(ElkSensor): return attrs @property - def temperature_unit(self): + def temperature_unit(self) -> str | None: """Return the temperature unit.""" if self._element.definition == ZoneType.TEMPERATURE.value: return self._temperature_unit return None @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str | None: """Return the unit of measurement.""" if self._element.definition == ZoneType.TEMPERATURE.value: return self._temperature_unit @@ -270,13 +290,13 @@ class ElkZone(ElkSensor): return ELECTRIC_POTENTIAL_VOLT return None - def _element_changed(self, element, changeset): + def _element_changed(self, _: Element, changeset: Any) -> None: if self._element.definition == ZoneType.TEMPERATURE.value: self._state = temperature_to_state( self._element.temperature, UNDEFINED_TEMPERATURE ) elif self._element.definition == ZoneType.ANALOG_ZONE.value: - self._state = self._element.voltage + self._state = f"{self._element.voltage}" else: self._state = pretty_const( ZoneLogicalStatus(self._element.logical_status).name diff --git a/mypy.ini b/mypy.ini index 3966ae1ee35..2b08aa0cd1e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -836,84 +836,7 @@ no_implicit_optional = true warn_return_any = true warn_unreachable = true -[mypy-homeassistant.components.elkm1.__init__] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.alarm_control_panel] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.climate] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.config_flow] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.discovery] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.light] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.scene] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -no_implicit_optional = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.elkm1.switch] +[mypy-homeassistant.components.elkm1.*] check_untyped_defs = true disallow_incomplete_defs = true disallow_subclassing_any = true