diff --git a/.strict-typing b/.strict-typing index 9e02dad19d2..3c409c85448 100644 --- a/.strict-typing +++ b/.strict-typing @@ -10,6 +10,7 @@ homeassistant.components.aftership.* homeassistant.components.air_quality.* homeassistant.components.airly.* homeassistant.components.aladdin_connect.* +homeassistant.components.alarm_control_panel.* homeassistant.components.amazon_polly.* homeassistant.components.ampio.* homeassistant.components.automation.* diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 7d9e47fbcbe..2d6d1f4d5b1 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -1,11 +1,14 @@ """Component to interface with an alarm control panel.""" +from __future__ import annotations + from abc import abstractmethod from datetime import timedelta import logging -from typing import final +from typing import Any, Final, final import voluptuous as vol +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_CODE, ATTR_CODE_FORMAT, @@ -16,14 +19,12 @@ from homeassistant.const import ( SERVICE_ALARM_DISARM, SERVICE_ALARM_TRIGGER, ) +from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.config_validation import ( # noqa: F401 - PLATFORM_SCHEMA, - PLATFORM_SCHEMA_BASE, - make_entity_service_schema, -) +from homeassistant.helpers.config_validation import make_entity_service_schema from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.typing import ConfigType from .const import ( SUPPORT_ALARM_ARM_AWAY, @@ -33,21 +34,26 @@ from .const import ( SUPPORT_ALARM_TRIGGER, ) -_LOGGER = logging.getLogger(__name__) +_LOGGER: Final = logging.getLogger(__name__) -DOMAIN = "alarm_control_panel" -SCAN_INTERVAL = timedelta(seconds=30) -ATTR_CHANGED_BY = "changed_by" -FORMAT_TEXT = "text" -FORMAT_NUMBER = "number" -ATTR_CODE_ARM_REQUIRED = "code_arm_required" +DOMAIN: Final = "alarm_control_panel" +SCAN_INTERVAL: Final = timedelta(seconds=30) +ATTR_CHANGED_BY: Final = "changed_by" +FORMAT_TEXT: Final = "text" +FORMAT_NUMBER: Final = "number" +ATTR_CODE_ARM_REQUIRED: Final = "code_arm_required" -ENTITY_ID_FORMAT = DOMAIN + ".{}" +ENTITY_ID_FORMAT: Final = DOMAIN + ".{}" -ALARM_SERVICE_SCHEMA = make_entity_service_schema({vol.Optional(ATTR_CODE): cv.string}) +ALARM_SERVICE_SCHEMA: Final = make_entity_service_schema( + {vol.Optional(ATTR_CODE): cv.string} +) + +PLATFORM_SCHEMA: Final = cv.PLATFORM_SCHEMA +PLATFORM_SCHEMA_BASE: Final = cv.PLATFORM_SCHEMA_BASE -async def async_setup(hass, config): +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Track states and offer events for sensors.""" component = hass.data[DOMAIN] = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL @@ -92,79 +98,81 @@ async def async_setup(hass, config): return True -async def async_setup_entry(hass, entry): +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up a config entry.""" - return await hass.data[DOMAIN].async_setup_entry(entry) + component: EntityComponent = hass.data[DOMAIN] + return await component.async_setup_entry(entry) -async def async_unload_entry(hass, entry): +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" - return await hass.data[DOMAIN].async_unload_entry(entry) + component: EntityComponent = hass.data[DOMAIN] + return await component.async_unload_entry(entry) class AlarmControlPanelEntity(Entity): """An abstract class for alarm control entities.""" @property - def code_format(self): + def code_format(self) -> str | None: """Regex for code format or None if no code is required.""" return None @property - def changed_by(self): + def changed_by(self) -> str | None: """Last change triggered by.""" return None @property - def code_arm_required(self): + def code_arm_required(self) -> bool: """Whether the code is required for arm actions.""" return True - def alarm_disarm(self, code=None): + def alarm_disarm(self, code: str | None = None) -> None: """Send disarm command.""" raise NotImplementedError() - async def async_alarm_disarm(self, code=None): + async def async_alarm_disarm(self, code: str | None = None) -> None: """Send disarm command.""" await self.hass.async_add_executor_job(self.alarm_disarm, code) - def alarm_arm_home(self, code=None): + def alarm_arm_home(self, code: str | None = None) -> None: """Send arm home command.""" raise NotImplementedError() - async def async_alarm_arm_home(self, code=None): + async def async_alarm_arm_home(self, code: str | None = None) -> None: """Send arm home command.""" await self.hass.async_add_executor_job(self.alarm_arm_home, code) - def alarm_arm_away(self, code=None): + def alarm_arm_away(self, code: str | None = None) -> None: """Send arm away command.""" raise NotImplementedError() - async def async_alarm_arm_away(self, code=None): + async def async_alarm_arm_away(self, code: str | None = None) -> None: """Send arm away command.""" await self.hass.async_add_executor_job(self.alarm_arm_away, code) - def alarm_arm_night(self, code=None): + def alarm_arm_night(self, code: str | None = None) -> None: """Send arm night command.""" raise NotImplementedError() - async def async_alarm_arm_night(self, code=None): + async def async_alarm_arm_night(self, code: str | None = None) -> None: """Send arm night command.""" await self.hass.async_add_executor_job(self.alarm_arm_night, code) - def alarm_trigger(self, code=None): + def alarm_trigger(self, code: str | None = None) -> None: """Send alarm trigger command.""" raise NotImplementedError() - async def async_alarm_trigger(self, code=None): + async def async_alarm_trigger(self, code: str | None = None) -> None: """Send alarm trigger command.""" await self.hass.async_add_executor_job(self.alarm_trigger, code) - def alarm_arm_custom_bypass(self, code=None): + def alarm_arm_custom_bypass(self, code: str | None = None) -> None: """Send arm custom bypass command.""" raise NotImplementedError() - async def async_alarm_arm_custom_bypass(self, code=None): + async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None: """Send arm custom bypass command.""" await self.hass.async_add_executor_job(self.alarm_arm_custom_bypass, code) @@ -175,7 +183,7 @@ class AlarmControlPanelEntity(Entity): @final @property - def state_attributes(self): + def state_attributes(self) -> dict[str, Any] | None: """Return the state attributes.""" return { ATTR_CODE_FORMAT: self.code_format, @@ -187,9 +195,9 @@ class AlarmControlPanelEntity(Entity): class AlarmControlPanel(AlarmControlPanelEntity): """An abstract class for alarm control entities (for backwards compatibility).""" - def __init_subclass__(cls, **kwargs): + def __init_subclass__(cls, **kwargs: Any) -> None: """Print deprecation warning.""" - super().__init_subclass__(**kwargs) + super().__init_subclass__(**kwargs) # type: ignore[call-arg] _LOGGER.warning( "AlarmControlPanel is deprecated, modify %s to extend AlarmControlPanelEntity", cls.__name__, diff --git a/homeassistant/components/alarm_control_panel/const.py b/homeassistant/components/alarm_control_panel/const.py index 2844cb286ab..36e3b6a13eb 100644 --- a/homeassistant/components/alarm_control_panel/const.py +++ b/homeassistant/components/alarm_control_panel/const.py @@ -1,14 +1,16 @@ """Provides the constants needed for component.""" -SUPPORT_ALARM_ARM_HOME = 1 -SUPPORT_ALARM_ARM_AWAY = 2 -SUPPORT_ALARM_ARM_NIGHT = 4 -SUPPORT_ALARM_TRIGGER = 8 -SUPPORT_ALARM_ARM_CUSTOM_BYPASS = 16 +from typing import Final -CONDITION_TRIGGERED = "is_triggered" -CONDITION_DISARMED = "is_disarmed" -CONDITION_ARMED_HOME = "is_armed_home" -CONDITION_ARMED_AWAY = "is_armed_away" -CONDITION_ARMED_NIGHT = "is_armed_night" -CONDITION_ARMED_CUSTOM_BYPASS = "is_armed_custom_bypass" +SUPPORT_ALARM_ARM_HOME: Final = 1 +SUPPORT_ALARM_ARM_AWAY: Final = 2 +SUPPORT_ALARM_ARM_NIGHT: Final = 4 +SUPPORT_ALARM_TRIGGER: Final = 8 +SUPPORT_ALARM_ARM_CUSTOM_BYPASS: Final = 16 + +CONDITION_TRIGGERED: Final = "is_triggered" +CONDITION_DISARMED: Final = "is_disarmed" +CONDITION_ARMED_HOME: Final = "is_armed_home" +CONDITION_ARMED_AWAY: Final = "is_armed_away" +CONDITION_ARMED_NIGHT: Final = "is_armed_night" +CONDITION_ARMED_CUSTOM_BYPASS: Final = "is_armed_custom_bypass" diff --git a/homeassistant/components/alarm_control_panel/device_action.py b/homeassistant/components/alarm_control_panel/device_action.py index 9a55998e929..506552f8a50 100644 --- a/homeassistant/components/alarm_control_panel/device_action.py +++ b/homeassistant/components/alarm_control_panel/device_action.py @@ -1,6 +1,8 @@ """Provides device automations for Alarm control panel.""" from __future__ import annotations +from typing import Final + import voluptuous as vol from homeassistant.const import ( @@ -21,6 +23,7 @@ from homeassistant.const import ( from homeassistant.core import Context, HomeAssistant from homeassistant.helpers import entity_registry import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.typing import ConfigType from . import ATTR_CODE_ARM_REQUIRED, DOMAIN from .const import ( @@ -30,9 +33,15 @@ from .const import ( SUPPORT_ALARM_TRIGGER, ) -ACTION_TYPES = {"arm_away", "arm_home", "arm_night", "disarm", "trigger"} +ACTION_TYPES: Final[set[str]] = { + "arm_away", + "arm_home", + "arm_night", + "disarm", + "trigger", +} -ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( +ACTION_SCHEMA: Final = cv.DEVICE_ACTION_BASE_SCHEMA.extend( { vol.Required(CONF_TYPE): vol.In(ACTION_TYPES), vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN), @@ -41,7 +50,9 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( ) -async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]: +async def async_get_actions( + hass: HomeAssistant, device_id: str +) -> list[dict[str, str]]: """List device actions for Alarm control panel devices.""" registry = await entity_registry.async_get_registry(hass) actions = [] @@ -109,7 +120,7 @@ async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]: async def async_call_action_from_config( - hass: HomeAssistant, config: dict, variables: dict, context: Context | None + hass: HomeAssistant, config: ConfigType, variables: dict, context: Context | None ) -> None: """Execute a device action.""" service_data = {ATTR_ENTITY_ID: config[CONF_ENTITY_ID]} @@ -132,7 +143,9 @@ async def async_call_action_from_config( ) -async def async_get_action_capabilities(hass, config): +async def async_get_action_capabilities( + hass: HomeAssistant, config: ConfigType +) -> dict[str, vol.Schema]: """List action capabilities.""" state = hass.states.get(config[CONF_ENTITY_ID]) code_required = state.attributes.get(ATTR_CODE_ARM_REQUIRED) if state else False diff --git a/homeassistant/components/alarm_control_panel/device_condition.py b/homeassistant/components/alarm_control_panel/device_condition.py index 3817cf37b45..fa4f903f2e5 100644 --- a/homeassistant/components/alarm_control_panel/device_condition.py +++ b/homeassistant/components/alarm_control_panel/device_condition.py @@ -1,6 +1,8 @@ """Provide the device automations for Alarm control panel.""" from __future__ import annotations +from typing import Final + import voluptuous as vol from homeassistant.components.alarm_control_panel.const import ( @@ -39,7 +41,7 @@ from .const import ( CONDITION_TRIGGERED, ) -CONDITION_TYPES = { +CONDITION_TYPES: Final[set[str]] = { CONDITION_TRIGGERED, CONDITION_DISARMED, CONDITION_ARMED_HOME, @@ -48,7 +50,7 @@ CONDITION_TYPES = { CONDITION_ARMED_CUSTOM_BYPASS, } -CONDITION_SCHEMA = DEVICE_CONDITION_BASE_SCHEMA.extend( +CONDITION_SCHEMA: Final = DEVICE_CONDITION_BASE_SCHEMA.extend( { vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Required(CONF_TYPE): vol.In(CONDITION_TYPES), diff --git a/homeassistant/components/alarm_control_panel/device_trigger.py b/homeassistant/components/alarm_control_panel/device_trigger.py index b24716bb43e..477a0c0fe6d 100644 --- a/homeassistant/components/alarm_control_panel/device_trigger.py +++ b/homeassistant/components/alarm_control_panel/device_trigger.py @@ -1,6 +1,8 @@ """Provides device automations for Alarm control panel.""" from __future__ import annotations +from typing import Final + import voluptuous as vol from homeassistant.components.alarm_control_panel.const import ( @@ -32,10 +34,14 @@ from homeassistant.helpers.typing import ConfigType from . import DOMAIN -BASIC_TRIGGER_TYPES = {"triggered", "disarmed", "arming"} -TRIGGER_TYPES = BASIC_TRIGGER_TYPES | {"armed_home", "armed_away", "armed_night"} +BASIC_TRIGGER_TYPES: Final[set[str]] = {"triggered", "disarmed", "arming"} +TRIGGER_TYPES: Final[set[str]] = BASIC_TRIGGER_TYPES | { + "armed_home", + "armed_away", + "armed_night", +} -TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend( +TRIGGER_SCHEMA: Final = TRIGGER_BASE_SCHEMA.extend( { vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES), @@ -44,10 +50,12 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend( ) -async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]: +async def async_get_triggers( + hass: HomeAssistant, device_id: str +) -> list[dict[str, str]]: """List device triggers for Alarm control panel devices.""" registry = await entity_registry.async_get_registry(hass) - triggers = [] + triggers: list[dict[str, str]] = [] # Get all the integrations entities for this device for entry in entity_registry.async_entries_for_device(registry, device_id): @@ -102,7 +110,9 @@ async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]: return triggers -async def async_get_trigger_capabilities(hass: HomeAssistant, config: dict) -> dict: +async def async_get_trigger_capabilities( + hass: HomeAssistant, config: ConfigType +) -> dict[str, vol.Schema]: """List trigger capabilities.""" return { "extra_fields": vol.Schema( diff --git a/homeassistant/components/alarm_control_panel/reproduce_state.py b/homeassistant/components/alarm_control_panel/reproduce_state.py index e7e4c07b8ad..019ba35c013 100644 --- a/homeassistant/components/alarm_control_panel/reproduce_state.py +++ b/homeassistant/components/alarm_control_panel/reproduce_state.py @@ -4,7 +4,7 @@ from __future__ import annotations import asyncio from collections.abc import Iterable import logging -from typing import Any +from typing import Any, Final from homeassistant.const import ( ATTR_ENTITY_ID, @@ -25,9 +25,9 @@ from homeassistant.core import Context, HomeAssistant, State from . import DOMAIN -_LOGGER = logging.getLogger(__name__) +_LOGGER: Final = logging.getLogger(__name__) -VALID_STATES = { +VALID_STATES: Final[set[str]] = { STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, diff --git a/homeassistant/components/arlo/alarm_control_panel.py b/homeassistant/components/arlo/alarm_control_panel.py index dd899cbd04f..91fb2a6a33e 100644 --- a/homeassistant/components/arlo/alarm_control_panel.py +++ b/homeassistant/components/arlo/alarm_control_panel.py @@ -4,7 +4,7 @@ import logging import voluptuous as vol from homeassistant.components.alarm_control_panel import ( - PLATFORM_SCHEMA, + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, AlarmControlPanelEntity, ) from homeassistant.components.alarm_control_panel.const import ( @@ -37,7 +37,7 @@ DISARMED = "disarmed" ICON = "mdi:security" -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Optional(CONF_HOME_MODE_NAME, default=ARMED): cv.string, vol.Optional(CONF_AWAY_MODE_NAME, default=ARMED): cv.string, diff --git a/homeassistant/components/concord232/alarm_control_panel.py b/homeassistant/components/concord232/alarm_control_panel.py index f502e805c85..a936c199e61 100644 --- a/homeassistant/components/concord232/alarm_control_panel.py +++ b/homeassistant/components/concord232/alarm_control_panel.py @@ -7,7 +7,9 @@ import requests import voluptuous as vol import homeassistant.components.alarm_control_panel as alarm -from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA +from homeassistant.components.alarm_control_panel import ( + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, +) from homeassistant.components.alarm_control_panel.const import ( SUPPORT_ALARM_ARM_AWAY, SUPPORT_ALARM_ARM_HOME, @@ -33,7 +35,7 @@ DEFAULT_MODE = "audible" SCAN_INTERVAL = datetime.timedelta(seconds=10) -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, diff --git a/homeassistant/components/ifttt/alarm_control_panel.py b/homeassistant/components/ifttt/alarm_control_panel.py index 519c2e42764..a4240dba177 100644 --- a/homeassistant/components/ifttt/alarm_control_panel.py +++ b/homeassistant/components/ifttt/alarm_control_panel.py @@ -7,7 +7,7 @@ import voluptuous as vol from homeassistant.components.alarm_control_panel import ( FORMAT_NUMBER, FORMAT_TEXT, - PLATFORM_SCHEMA, + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, AlarmControlPanelEntity, ) from homeassistant.components.alarm_control_panel.const import ( @@ -54,7 +54,7 @@ DEFAULT_EVENT_DISARM = "alarm_disarm" CONF_CODE_ARM_REQUIRED = "code_arm_required" -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_CODE): cv.string, diff --git a/homeassistant/components/nx584/alarm_control_panel.py b/homeassistant/components/nx584/alarm_control_panel.py index d5cdce5d64b..12f47de7060 100644 --- a/homeassistant/components/nx584/alarm_control_panel.py +++ b/homeassistant/components/nx584/alarm_control_panel.py @@ -7,7 +7,9 @@ import requests import voluptuous as vol import homeassistant.components.alarm_control_panel as alarm -from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA +from homeassistant.components.alarm_control_panel import ( + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, +) from homeassistant.components.alarm_control_panel.const import ( SUPPORT_ALARM_ARM_AWAY, SUPPORT_ALARM_ARM_HOME, @@ -35,7 +37,7 @@ SERVICE_BYPASS_ZONE = "bypass_zone" SERVICE_UNBYPASS_ZONE = "unbypass_zone" ATTR_ZONE = "zone" -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, diff --git a/homeassistant/components/template/alarm_control_panel.py b/homeassistant/components/template/alarm_control_panel.py index 4c72c5094ef..2706b2d433d 100644 --- a/homeassistant/components/template/alarm_control_panel.py +++ b/homeassistant/components/template/alarm_control_panel.py @@ -6,7 +6,7 @@ import voluptuous as vol from homeassistant.components.alarm_control_panel import ( ENTITY_ID_FORMAT, FORMAT_NUMBER, - PLATFORM_SCHEMA, + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, AlarmControlPanelEntity, ) from homeassistant.components.alarm_control_panel.const import ( @@ -68,7 +68,7 @@ ALARM_CONTROL_PANEL_SCHEMA = vol.Schema( } ) -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Required(CONF_ALARM_CONTROL_PANELS): cv.schema_with_slug_keys( ALARM_CONTROL_PANEL_SCHEMA diff --git a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py index d3504bcc6da..13433086879 100644 --- a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py +++ b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py @@ -11,7 +11,7 @@ from yalesmartalarmclient.client import ( ) from homeassistant.components.alarm_control_panel import ( - PLATFORM_SCHEMA, + PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, AlarmControlPanelEntity, ) from homeassistant.components.alarm_control_panel.const import ( @@ -36,7 +36,7 @@ DEFAULT_AREA_ID = "1" _LOGGER = logging.getLogger(__name__) -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( +PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( { vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, diff --git a/mypy.ini b/mypy.ini index 2cb4d318962..cda4ff75ac3 100644 --- a/mypy.ini +++ b/mypy.ini @@ -121,6 +121,17 @@ no_implicit_optional = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.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.amazon_polly.*] check_untyped_defs = true disallow_incomplete_defs = true