From 47d6f75c1762846410c2d48173d971181af6423c Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Thu, 10 Feb 2022 10:59:54 +0100 Subject: [PATCH] Enable basic type checking in template (#66222) * Fix binary_sensor * Adjust button * Adjust fan * Adjust select * Adjust template_entity * Adjust trigger_entity * Adjust weather * Adjust init * Adjust number * Adjust None check --- homeassistant/components/template/__init__.py | 4 ++-- .../components/template/binary_sensor.py | 8 +++---- homeassistant/components/template/button.py | 3 ++- homeassistant/components/template/fan.py | 20 +++++----------- homeassistant/components/template/number.py | 1 + homeassistant/components/template/select.py | 3 ++- .../components/template/template_entity.py | 16 ++++++++----- .../components/template/trigger_entity.py | 6 +++-- mypy.ini | 24 ------------------- script/hassfest/mypy_config.py | 8 ------- 10 files changed, 31 insertions(+), 62 deletions(-) diff --git a/homeassistant/components/template/__init__.py b/homeassistant/components/template/__init__.py index 318b457c24b..a1231708b91 100644 --- a/homeassistant/components/template/__init__.py +++ b/homeassistant/components/template/__init__.py @@ -61,7 +61,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: return True -async def _process_config(hass, hass_config): +async def _process_config(hass: HomeAssistant, hass_config: ConfigType) -> None: """Process config.""" coordinators: list[TriggerUpdateCoordinator] | None = hass.data.pop(DOMAIN, None) @@ -126,7 +126,7 @@ class TriggerUpdateCoordinator(update_coordinator.DataUpdateCoordinator): if self._unsub_trigger: self._unsub_trigger() - async def async_setup(self: HomeAssistant, hass_config: ConfigType) -> bool: + async def async_setup(self, hass_config: ConfigType) -> None: """Set up the trigger and create entities.""" if self.hass.state == CoreState.running: await self._attach_triggers() diff --git a/homeassistant/components/template/binary_sensor.py b/homeassistant/components/template/binary_sensor.py index d2578468886..4c080c736d0 100644 --- a/homeassistant/components/template/binary_sensor.py +++ b/homeassistant/components/template/binary_sensor.py @@ -31,7 +31,7 @@ from homeassistant.const import ( CONF_UNIT_OF_MEASUREMENT, CONF_VALUE_TEMPLATE, ) -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback from homeassistant.exceptions import TemplateError from homeassistant.helpers import template import homeassistant.helpers.config_validation as cv @@ -300,12 +300,12 @@ class TriggerBinarySensorEntity(TriggerEntity, BinarySensorEntity): self._to_render_simple.append(key) self._parse_result.add(key) - self._delay_cancel = None + self._delay_cancel: CALLBACK_TYPE | None = None self._auto_off_cancel = None - self._state = None + self._state: bool | None = None @property - def is_on(self) -> bool: + def is_on(self) -> bool | None: """Return state of the sensor.""" return self._state diff --git a/homeassistant/components/template/button.py b/homeassistant/components/template/button.py index 86f481d7032..d6f41649734 100644 --- a/homeassistant/components/template/button.py +++ b/homeassistant/components/template/button.py @@ -63,7 +63,7 @@ async def async_setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the template button.""" - if "coordinator" in discovery_info: + if not discovery_info or "coordinator" in discovery_info: raise PlatformNotReady( "The template button platform doesn't support trigger entities" ) @@ -86,6 +86,7 @@ class TemplateButtonEntity(TemplateEntity, ButtonEntity): ) -> None: """Initialize the button.""" super().__init__(hass, config=config, unique_id=unique_id) + assert self._attr_name is not None self._command_press = Script(hass, config[CONF_PRESS], self._attr_name, DOMAIN) self._attr_device_class = config.get(CONF_DEVICE_CLASS) self._attr_state = None diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index 9d0a32f3edd..1ddd37ba7bc 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -2,6 +2,7 @@ from __future__ import annotations import logging +from typing import Any import voluptuous as vol @@ -63,7 +64,6 @@ CONF_SET_DIRECTION_ACTION = "set_direction" CONF_SET_PRESET_MODE_ACTION = "set_preset_mode" _VALID_STATES = [STATE_ON, STATE_OFF] -_VALID_OSC = [True, False] _VALID_DIRECTIONS = [DIRECTION_FORWARD, DIRECTION_REVERSE] FAN_SCHEMA = vol.All( @@ -273,8 +273,7 @@ class TemplateFan(TemplateEntity, FanEntity): elif speed is not None: await self.async_set_speed(speed) - # pylint: disable=arguments-differ - async def async_turn_off(self) -> None: + async def async_turn_off(self, **kwargs: Any) -> None: """Turn off the fan.""" await self._off_script.async_run(context=self._context) self._state = STATE_OFF @@ -316,17 +315,10 @@ class TemplateFan(TemplateEntity, FanEntity): if self._set_oscillating_script is None: return - if oscillating in _VALID_OSC: - self._oscillating = oscillating - await self._set_oscillating_script.async_run( - {ATTR_OSCILLATING: oscillating}, context=self._context - ) - else: - _LOGGER.error( - "Received invalid oscillating value: %s. Expected: %s", - oscillating, - ", ".join(_VALID_OSC), - ) + self._oscillating = oscillating + await self._set_oscillating_script.async_run( + {ATTR_OSCILLATING: oscillating}, context=self._context + ) async def async_set_direction(self, direction: str) -> None: """Set the direction of the fan.""" diff --git a/homeassistant/components/template/number.py b/homeassistant/components/template/number.py index 036485cd363..89adb45a6d0 100644 --- a/homeassistant/components/template/number.py +++ b/homeassistant/components/template/number.py @@ -108,6 +108,7 @@ class TemplateNumber(TemplateEntity, NumberEntity): ) -> None: """Initialize the number.""" super().__init__(hass, config=config, unique_id=unique_id) + assert self._attr_name is not None self._value_template = config[CONF_STATE] self._command_set_value = Script( hass, config[CONF_SET_VALUE], self._attr_name, DOMAIN diff --git a/homeassistant/components/template/select.py b/homeassistant/components/template/select.py index 28295835318..fa2668c1e81 100644 --- a/homeassistant/components/template/select.py +++ b/homeassistant/components/template/select.py @@ -102,13 +102,14 @@ class TemplateSelect(TemplateEntity, SelectEntity): ) -> None: """Initialize the select.""" super().__init__(hass, config=config, unique_id=unique_id) + assert self._attr_name is not None self._value_template = config[CONF_STATE] self._command_select_option = Script( hass, config[CONF_SELECT_OPTION], self._attr_name, DOMAIN ) self._options_template = config[ATTR_OPTIONS] self._attr_assumed_state = self._optimistic = config[CONF_OPTIMISTIC] - self._attr_options = None + self._attr_options = [] self._attr_current_option = None async def async_added_to_hass(self) -> None: diff --git a/homeassistant/components/template/template_entity.py b/homeassistant/components/template/template_entity.py index ee4b6244757..5e592e5d717 100644 --- a/homeassistant/components/template/template_entity.py +++ b/homeassistant/components/template/template_entity.py @@ -16,13 +16,13 @@ from homeassistant.const import ( CONF_ICON, CONF_ICON_TEMPLATE, CONF_NAME, + EVENT_HOMEASSISTANT_START, ) -from homeassistant.core import EVENT_HOMEASSISTANT_START, CoreState, callback +from homeassistant.core import CoreState, Event, callback from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import ( - Event, TrackTemplate, TrackTemplateResult, async_track_template_result, @@ -94,7 +94,7 @@ LEGACY_FIELDS = { def rewrite_common_legacy_to_modern_conf( entity_cfg: dict[str, Any], extra_legacy_fields: dict[str, str] = None -) -> list[dict]: +) -> dict[str, Any]: """Rewrite legacy config.""" entity_cfg = {**entity_cfg} if extra_legacy_fields is None: @@ -176,10 +176,12 @@ class _TemplateAttribute: if self.none_on_template_error: self._default_update(result) else: + assert self.on_update self.on_update(result) return if not self.validator: + assert self.on_update self.on_update(result) return @@ -197,9 +199,11 @@ class _TemplateAttribute: self._entity.entity_id, ex.msg, ) + assert self.on_update self.on_update(None) return + assert self.on_update self.on_update(validated) return @@ -321,11 +325,11 @@ class TemplateEntity(Entity): """ assert self.hass is not None, "hass cannot be None" template.hass = self.hass - attribute = _TemplateAttribute( + template_attribute = _TemplateAttribute( self, attribute, template, validator, on_update, none_on_template_error ) self._template_attrs.setdefault(template, []) - self._template_attrs[template].append(attribute) + self._template_attrs[template].append(template_attribute) @callback def _handle_results( @@ -362,7 +366,7 @@ class TemplateEntity(Entity): self.async_write_ha_state() async def _async_template_startup(self, *_) -> None: - template_var_tups = [] + template_var_tups: list[TrackTemplate] = [] has_availability_template = False for template, attributes in self._template_attrs.items(): template_var_tup = TrackTemplate(template, None) diff --git a/homeassistant/components/template/trigger_entity.py b/homeassistant/components/template/trigger_entity.py index d4bc96e43bf..2768609e65d 100644 --- a/homeassistant/components/template/trigger_entity.py +++ b/homeassistant/components/template/trigger_entity.py @@ -12,6 +12,7 @@ from homeassistant.const import ( CONF_UNIT_OF_MEASUREMENT, ) from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import TemplateError from homeassistant.helpers import template, update_coordinator from . import TriggerUpdateCoordinator @@ -36,6 +37,7 @@ class TriggerEntity(update_coordinator.CoordinatorEntity): entity_unique_id = config.get(CONF_UNIQUE_ID) + self._unique_id: str | None if entity_unique_id and coordinator.unique_id: self._unique_id = f"{coordinator.unique_id}-{entity_unique_id}" else: @@ -45,7 +47,7 @@ class TriggerEntity(update_coordinator.CoordinatorEntity): self._static_rendered = {} self._to_render_simple = [] - self._to_render_complex = [] + self._to_render_complex: list[str] = [] for itm in ( CONF_NAME, @@ -148,7 +150,7 @@ class TriggerEntity(update_coordinator.CoordinatorEntity): ) self._rendered = rendered - except template.TemplateError as err: + except TemplateError as err: logging.getLogger(f"{__package__}.{self.entity_id.split('.')[0]}").error( "Error rendering %s template for %s: %s", key, self.entity_id, err ) diff --git a/mypy.ini b/mypy.ini index 2ad49bfdc4c..d4db04e8e82 100644 --- a/mypy.ini +++ b/mypy.ini @@ -2619,36 +2619,12 @@ ignore_errors = true [mypy-homeassistant.components.telegram_bot.polling] ignore_errors = true -[mypy-homeassistant.components.template] -ignore_errors = true - -[mypy-homeassistant.components.template.binary_sensor] -ignore_errors = true - -[mypy-homeassistant.components.template.button] -ignore_errors = true - -[mypy-homeassistant.components.template.fan] -ignore_errors = true - [mypy-homeassistant.components.template.number] ignore_errors = true -[mypy-homeassistant.components.template.select] -ignore_errors = true - [mypy-homeassistant.components.template.sensor] ignore_errors = true -[mypy-homeassistant.components.template.template_entity] -ignore_errors = true - -[mypy-homeassistant.components.template.trigger_entity] -ignore_errors = true - -[mypy-homeassistant.components.template.weather] -ignore_errors = true - [mypy-homeassistant.components.toon] ignore_errors = true diff --git a/script/hassfest/mypy_config.py b/script/hassfest/mypy_config.py index f776f1b635b..99104702f26 100644 --- a/script/hassfest/mypy_config.py +++ b/script/hassfest/mypy_config.py @@ -179,16 +179,8 @@ IGNORED_MODULES: Final[list[str]] = [ "homeassistant.components.sonos.statistics", "homeassistant.components.system_health", "homeassistant.components.telegram_bot.polling", - "homeassistant.components.template", - "homeassistant.components.template.binary_sensor", - "homeassistant.components.template.button", - "homeassistant.components.template.fan", "homeassistant.components.template.number", - "homeassistant.components.template.select", "homeassistant.components.template.sensor", - "homeassistant.components.template.template_entity", - "homeassistant.components.template.trigger_entity", - "homeassistant.components.template.weather", "homeassistant.components.toon", "homeassistant.components.toon.config_flow", "homeassistant.components.toon.models",