None optional hass typing in base entity and notify (#47528)

This commit is contained in:
Franck Nijhof 2021-03-15 15:11:41 +01:00 committed by GitHub
parent b9a26cf539
commit 5d5a110a20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 18 additions and 57 deletions

View file

@ -517,14 +517,14 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
if self._trigger_variables: if self._trigger_variables:
try: try:
variables = self._trigger_variables.async_render( variables = self._trigger_variables.async_render(
cast(HomeAssistant, self.hass), None, limited=True self.hass, None, limited=True
) )
except template.TemplateError as err: except template.TemplateError as err:
self._logger.error("Error rendering trigger variables: %s", err) self._logger.error("Error rendering trigger variables: %s", err)
return None return None
return await async_initialize_triggers( return await async_initialize_triggers(
cast(HomeAssistant, self.hass), self.hass,
self._trigger_config, self._trigger_config,
self.async_trigger, self.async_trigger,
DOMAIN, DOMAIN,

View file

@ -158,7 +158,6 @@ class BondEntity(Entity):
await super().async_added_to_hass() await super().async_added_to_hass()
self._update_lock = Lock() self._update_lock = Lock()
self._bpup_subs.subscribe(self._device_id, self._async_bpup_callback) self._bpup_subs.subscribe(self._device_id, self._async_bpup_callback)
assert self.hass is not None
self.async_on_remove( self.async_on_remove(
async_track_time_interval( async_track_time_interval(
self.hass, self._async_update_if_bpup_not_alive, _FALLBACK_SCAN_INTERVAL self.hass, self._async_update_if_bpup_not_alive, _FALLBACK_SCAN_INTERVAL

View file

@ -110,7 +110,6 @@ class ClimaCellConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: Dict[str, Any] = None self, user_input: Dict[str, Any] = None
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Handle the initial step.""" """Handle the initial step."""
assert self.hass
errors = {} errors = {}
if user_input is not None: if user_input is not None:
await self.async_set_unique_id( await self.async_set_unique_id(

View file

@ -395,7 +395,6 @@ class GroupEntity(Entity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register listeners.""" """Register listeners."""
assert self.hass is not None
async def _update_at_start(_): async def _update_at_start(_):
await self.async_update() await self.async_update()
@ -405,8 +404,6 @@ class GroupEntity(Entity):
async def async_defer_or_update_ha_state(self) -> None: async def async_defer_or_update_ha_state(self) -> None:
"""Only update once at start.""" """Only update once at start."""
assert self.hass is not None
if self.hass.state != CoreState.running: if self.hass.state != CoreState.running:
return return

View file

@ -155,7 +155,6 @@ class CoverGroup(GroupEntity, CoverEntity):
await self.async_update_supported_features( await self.async_update_supported_features(
entity_id, new_state, update_state=False entity_id, new_state, update_state=False
) )
assert self.hass is not None
self.async_on_remove( self.async_on_remove(
async_track_state_change_event( async_track_state_change_event(
self.hass, self._entities, self._update_supported_features_event self.hass, self._entities, self._update_supported_features_event

View file

@ -103,7 +103,6 @@ class LightGroup(GroupEntity, light.LightEntity):
self.async_set_context(event.context) self.async_set_context(event.context)
await self.async_defer_or_update_ha_state() await self.async_defer_or_update_ha_state()
assert self.hass
self.async_on_remove( self.async_on_remove(
async_track_state_change_event( async_track_state_change_event(
self.hass, self._entity_ids, async_state_changed_listener self.hass, self._entity_ids, async_state_changed_listener

View file

@ -636,7 +636,6 @@ class HuaweiLteBaseEntity(Entity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Connect to update signals.""" """Connect to update signals."""
assert self.hass is not None
self._unsub_handlers.append( self._unsub_handlers.append(
async_dispatcher_connect(self.hass, UPDATE_SIGNAL, self._async_maybe_update) async_dispatcher_connect(self.hass, UPDATE_SIGNAL, self._async_maybe_update)
) )

View file

@ -397,7 +397,6 @@ class HyperionBaseLight(LightEntity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register callbacks when entity added to hass.""" """Register callbacks when entity added to hass."""
assert self.hass
self.async_on_remove( self.async_on_remove(
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,

View file

@ -193,7 +193,6 @@ class HyperionComponentSwitch(SwitchEntity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register callbacks when entity added to hass.""" """Register callbacks when entity added to hass."""
assert self.hass
self.async_on_remove( self.async_on_remove(
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,

View file

@ -2,7 +2,7 @@
import asyncio import asyncio
from functools import partial from functools import partial
import logging import logging
from typing import Any, Dict, Optional, cast from typing import Any, Dict, cast
import voluptuous as vol import voluptuous as vol
@ -114,7 +114,11 @@ def _async_integration_has_notify_services(
class BaseNotificationService: class BaseNotificationService:
"""An abstract class for notification services.""" """An abstract class for notification services."""
hass: Optional[HomeAssistantType] = None # While not purely typed, it makes typehinting more useful for us
# and removes the need for constant None checks or asserts.
# Ignore types: https://github.com/PyCQA/pylint/issues/3167
hass: HomeAssistantType = None # type: ignore
# Name => target # Name => target
registered_targets: Dict[str, str] registered_targets: Dict[str, str]
@ -130,7 +134,9 @@ class BaseNotificationService:
kwargs can contain ATTR_TITLE to specify a title. kwargs can contain ATTR_TITLE to specify a title.
""" """
await self.hass.async_add_executor_job(partial(self.send_message, message, **kwargs)) # type: ignore await self.hass.async_add_executor_job(
partial(self.send_message, message, **kwargs)
)
async def _async_notify_message_service(self, service: ServiceCall) -> None: async def _async_notify_message_service(self, service: ServiceCall) -> None:
"""Handle sending notification message service calls.""" """Handle sending notification message service calls."""
@ -175,8 +181,6 @@ class BaseNotificationService:
async def async_register_services(self) -> None: async def async_register_services(self) -> None:
"""Create or update the notify services.""" """Create or update the notify services."""
assert self.hass
if hasattr(self, "targets"): if hasattr(self, "targets"):
stale_targets = set(self.registered_targets) stale_targets = set(self.registered_targets)
@ -232,8 +236,6 @@ class BaseNotificationService:
async def async_unregister_services(self) -> None: async def async_unregister_services(self) -> None:
"""Unregister the notify services.""" """Unregister the notify services."""
assert self.hass
if self.registered_targets: if self.registered_targets:
remove_targets = set(self.registered_targets) remove_targets = set(self.registered_targets)
for remove_target_name in remove_targets: for remove_target_name in remove_targets:

View file

@ -110,5 +110,4 @@ class NumberEntity(Entity):
async def async_set_value(self, value: float) -> None: async def async_set_value(self, value: float) -> None:
"""Set new value.""" """Set new value."""
assert self.hass is not None
await self.hass.async_add_executor_job(self.set_value, value) await self.hass.async_add_executor_job(self.set_value, value)

View file

@ -173,7 +173,6 @@ class RemoteEntity(ToggleEntity):
async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None: async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None:
"""Send commands to a device.""" """Send commands to a device."""
assert self.hass is not None
await self.hass.async_add_executor_job( await self.hass.async_add_executor_job(
ft.partial(self.send_command, command, **kwargs) ft.partial(self.send_command, command, **kwargs)
) )
@ -184,7 +183,6 @@ class RemoteEntity(ToggleEntity):
async def async_learn_command(self, **kwargs: Any) -> None: async def async_learn_command(self, **kwargs: Any) -> None:
"""Learn a command from a device.""" """Learn a command from a device."""
assert self.hass is not None
await self.hass.async_add_executor_job(ft.partial(self.learn_command, **kwargs)) await self.hass.async_add_executor_job(ft.partial(self.learn_command, **kwargs))
def delete_command(self, **kwargs: Any) -> None: def delete_command(self, **kwargs: Any) -> None:
@ -193,7 +191,6 @@ class RemoteEntity(ToggleEntity):
async def async_delete_command(self, **kwargs: Any) -> None: async def async_delete_command(self, **kwargs: Any) -> None:
"""Delete commands from the database.""" """Delete commands from the database."""
assert self.hass is not None
await self.hass.async_add_executor_job( await self.hass.async_add_executor_job(
ft.partial(self.delete_command, **kwargs) ft.partial(self.delete_command, **kwargs)
) )

View file

@ -104,7 +104,6 @@ class Scene(Entity):
async def async_activate(self, **kwargs: Any) -> None: async def async_activate(self, **kwargs: Any) -> None:
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
assert self.hass
task = self.hass.async_add_job(ft.partial(self.activate, **kwargs)) task = self.hass.async_add_job(ft.partial(self.activate, **kwargs))
if task: if task:
await task await task

View file

@ -120,13 +120,11 @@ class LightSwitch(LightEntity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register callbacks.""" """Register callbacks."""
assert self.hass is not None
self._switch_state = self.hass.states.get(self._switch_entity_id) self._switch_state = self.hass.states.get(self._switch_entity_id)
@callback @callback
def async_state_changed_listener(*_: Any) -> None: def async_state_changed_listener(*_: Any) -> None:
"""Handle child updates.""" """Handle child updates."""
assert self.hass is not None
self._switch_state = self.hass.states.get(self._switch_entity_id) self._switch_state = self.hass.states.get(self._switch_entity_id)
self.async_write_ha_state() self.async_write_ha_state()

View file

@ -373,7 +373,6 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
async def async_set_temperature(self, **kwargs: Any) -> None: async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature.""" """Set new target temperature."""
assert self.hass
hvac_mode: Optional[str] = kwargs.get(ATTR_HVAC_MODE) hvac_mode: Optional[str] = kwargs.get(ATTR_HVAC_MODE)
if hvac_mode is not None: if hvac_mode is not None:

View file

@ -89,7 +89,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: Optional[Dict[str, Any]] = None self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Handle the initial step.""" """Handle the initial step."""
assert self.hass # typing
if is_hassio(self.hass): # type: ignore # no-untyped-call if is_hassio(self.hass): # type: ignore # no-untyped-call
return await self.async_step_on_supervisor() return await self.async_step_on_supervisor()
@ -266,7 +265,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self, user_input: Optional[Dict[str, Any]] = None self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Start Z-Wave JS add-on.""" """Start Z-Wave JS add-on."""
assert self.hass
if not self.start_task: if not self.start_task:
self.start_task = self.hass.async_create_task(self._async_start_addon()) self.start_task = self.hass.async_create_task(self._async_start_addon())
return self.async_show_progress( return self.async_show_progress(
@ -289,7 +287,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def _async_start_addon(self) -> None: async def _async_start_addon(self) -> None:
"""Start the Z-Wave JS add-on.""" """Start the Z-Wave JS add-on."""
assert self.hass
addon_manager: AddonManager = get_addon_manager(self.hass) addon_manager: AddonManager = get_addon_manager(self.hass)
try: try:
await addon_manager.async_schedule_start_addon() await addon_manager.async_schedule_start_addon()
@ -327,7 +324,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
Get add-on discovery info and server version info. Get add-on discovery info and server version info.
Set unique id and abort if already configured. Set unique id and abort if already configured.
""" """
assert self.hass
if not self.ws_address: if not self.ws_address:
discovery_info = await self._async_get_addon_discovery_info() discovery_info = await self._async_get_addon_discovery_info()
self.ws_address = f"ws://{discovery_info['host']}:{discovery_info['port']}" self.ws_address = f"ws://{discovery_info['host']}:{discovery_info['port']}"

View file

@ -46,7 +46,6 @@ class ZWaveBaseEntity(Entity):
async def async_poll_value(self, refresh_all_values: bool) -> None: async def async_poll_value(self, refresh_all_values: bool) -> None:
"""Poll a value.""" """Poll a value."""
assert self.hass
if not refresh_all_values: if not refresh_all_values:
self.hass.async_create_task( self.hass.async_create_task(
self.info.node.async_poll_value(self.info.primary_value) self.info.node.async_poll_value(self.info.primary_value)
@ -75,7 +74,6 @@ class ZWaveBaseEntity(Entity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Call when entity is added.""" """Call when entity is added."""
assert self.hass # typing
# Add value_changed callbacks. # Add value_changed callbacks.
self.async_on_remove( self.async_on_remove(
self.info.node.on(EVENT_VALUE_UPDATED, self._value_changed) self.info.node.on(EVENT_VALUE_UPDATED, self._value_changed)

View file

@ -59,7 +59,6 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
return self.async_abort(reason="no_devices_found") return self.async_abort(reason="no_devices_found")
# Cancel the discovered one. # Cancel the discovered one.
assert self.hass is not None
for flow in in_progress: for flow in in_progress:
self.hass.config_entries.flow.async_abort(flow["flow_id"]) self.hass.config_entries.flow.async_abort(flow["flow_id"])
@ -91,7 +90,6 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")
# Cancel other flows. # Cancel other flows.
assert self.hass is not None
in_progress = self._async_in_progress() in_progress = self._async_in_progress()
for flow in in_progress: for flow in in_progress:
self.hass.config_entries.flow.async_abort(flow["flow_id"]) self.hass.config_entries.flow.async_abort(flow["flow_id"])
@ -144,7 +142,6 @@ class WebhookFlowHandler(config_entries.ConfigFlow):
if user_input is None: if user_input is None:
return self.async_show_form(step_id="user") return self.async_show_form(step_id="user")
assert self.hass is not None
webhook_id = self.hass.components.webhook.async_generate_id() webhook_id = self.hass.components.webhook.async_generate_id()
if ( if (

View file

@ -234,7 +234,6 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
self, user_input: Optional[dict] = None self, user_input: Optional[dict] = None
) -> dict: ) -> dict:
"""Handle a flow start.""" """Handle a flow start."""
assert self.hass
implementations = await async_get_implementations(self.hass, self.DOMAIN) implementations = await async_get_implementations(self.hass, self.DOMAIN)
if user_input is not None: if user_input is not None:
@ -318,7 +317,6 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
"""Handle a flow initialized by discovery.""" """Handle a flow initialized by discovery."""
await self.async_set_unique_id(self.DOMAIN) await self.async_set_unique_id(self.DOMAIN)
assert self.hass is not None
if self.hass.config_entries.async_entries(self.DOMAIN): if self.hass.config_entries.async_entries(self.DOMAIN):
return self.async_abort(reason="already_configured") return self.async_abort(reason="already_configured")

View file

@ -89,10 +89,13 @@ class Entity(ABC):
# SAFE TO OVERWRITE # SAFE TO OVERWRITE
# The properties and methods here are safe to overwrite when inheriting # The properties and methods here are safe to overwrite when inheriting
# this class. These may be used to customize the behavior of the entity. # this class. These may be used to customize the behavior of the entity.
entity_id = None # type: str entity_id: str = None # type: ignore
# Owning hass instance. Will be set by EntityPlatform # Owning hass instance. Will be set by EntityPlatform
hass: Optional[HomeAssistant] = None # While not purely typed, it makes typehinting more useful for us
# and removes the need for constant None checks or asserts.
# Ignore types: https://github.com/PyCQA/pylint/issues/3167
hass: HomeAssistant = None # type: ignore
# Owning platform instance. Will be set by EntityPlatform # Owning platform instance. Will be set by EntityPlatform
platform: Optional[EntityPlatform] = None platform: Optional[EntityPlatform] = None
@ -391,7 +394,6 @@ class Entity(ABC):
) )
# Overwrite properties that have been set in the config file. # Overwrite properties that have been set in the config file.
assert self.hass is not None
if DATA_CUSTOMIZE in self.hass.data: if DATA_CUSTOMIZE in self.hass.data:
attr.update(self.hass.data[DATA_CUSTOMIZE].get(self.entity_id)) attr.update(self.hass.data[DATA_CUSTOMIZE].get(self.entity_id))
@ -432,7 +434,6 @@ class Entity(ABC):
If state is changed more than once before the ha state change task has If state is changed more than once before the ha state change task has
been executed, the intermediate state transitions will be missed. been executed, the intermediate state transitions will be missed.
""" """
assert self.hass is not None
self.hass.add_job(self.async_update_ha_state(force_refresh)) # type: ignore self.hass.add_job(self.async_update_ha_state(force_refresh)) # type: ignore
@callback @callback
@ -448,7 +449,6 @@ class Entity(ABC):
been executed, the intermediate state transitions will be missed. been executed, the intermediate state transitions will be missed.
""" """
if force_refresh: if force_refresh:
assert self.hass is not None
self.hass.async_create_task(self.async_update_ha_state(force_refresh)) self.hass.async_create_task(self.async_update_ha_state(force_refresh))
else: else:
self.async_write_ha_state() self.async_write_ha_state()
@ -532,7 +532,7 @@ class Entity(ABC):
@callback @callback
def add_to_platform_abort(self) -> None: def add_to_platform_abort(self) -> None:
"""Abort adding an entity to a platform.""" """Abort adding an entity to a platform."""
self.hass = None self.hass = None # type: ignore
self.platform = None self.platform = None
self.parallel_updates = None self.parallel_updates = None
self._added = False self._added = False
@ -553,8 +553,6 @@ class Entity(ABC):
If the entity doesn't have a non disabled entry in the entity registry, If the entity doesn't have a non disabled entry in the entity registry,
or if force_remove=True, its state will be removed. or if force_remove=True, its state will be removed.
""" """
assert self.hass is not None
if self.platform and not self._added: if self.platform and not self._added:
raise HomeAssistantError( raise HomeAssistantError(
f"Entity {self.entity_id} async_remove called twice" f"Entity {self.entity_id} async_remove called twice"
@ -597,8 +595,6 @@ class Entity(ABC):
Not to be extended by integrations. Not to be extended by integrations.
""" """
assert self.hass is not None
if self.platform: if self.platform:
info = {"domain": self.platform.platform_name} info = {"domain": self.platform.platform_name}
@ -628,7 +624,6 @@ class Entity(ABC):
Not to be extended by integrations. Not to be extended by integrations.
""" """
if self.platform: if self.platform:
assert self.hass is not None
self.hass.data[DATA_ENTITY_SOURCE].pop(self.entity_id) self.hass.data[DATA_ENTITY_SOURCE].pop(self.entity_id)
async def _async_registry_updated(self, event: Event) -> None: async def _async_registry_updated(self, event: Event) -> None:
@ -642,7 +637,6 @@ class Entity(ABC):
if data["action"] != "update": if data["action"] != "update":
return return
assert self.hass is not None
ent_reg = await self.hass.helpers.entity_registry.async_get_registry() ent_reg = await self.hass.helpers.entity_registry.async_get_registry()
old = self.registry_entry old = self.registry_entry
self.registry_entry = ent_reg.async_get(data["entity_id"]) self.registry_entry = ent_reg.async_get(data["entity_id"])
@ -717,7 +711,6 @@ class ToggleEntity(Entity):
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on.""" """Turn the entity on."""
assert self.hass is not None
await self.hass.async_add_executor_job(ft.partial(self.turn_on, **kwargs)) await self.hass.async_add_executor_job(ft.partial(self.turn_on, **kwargs))
def turn_off(self, **kwargs: Any) -> None: def turn_off(self, **kwargs: Any) -> None:
@ -726,7 +719,6 @@ class ToggleEntity(Entity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off.""" """Turn the entity off."""
assert self.hass is not None
await self.hass.async_add_executor_job(ft.partial(self.turn_off, **kwargs)) await self.hass.async_add_executor_job(ft.partial(self.turn_off, **kwargs))
def toggle(self, **kwargs: Any) -> None: def toggle(self, **kwargs: Any) -> None:

View file

@ -235,7 +235,6 @@ class RestoreEntity(Entity):
async def async_internal_added_to_hass(self) -> None: async def async_internal_added_to_hass(self) -> None:
"""Register this entity as a restorable entity.""" """Register this entity as a restorable entity."""
assert self.hass is not None
_, data = await asyncio.gather( _, data = await asyncio.gather(
super().async_internal_added_to_hass(), super().async_internal_added_to_hass(),
RestoreStateData.async_get_instance(self.hass), RestoreStateData.async_get_instance(self.hass),
@ -244,7 +243,6 @@ class RestoreEntity(Entity):
async def async_internal_will_remove_from_hass(self) -> None: async def async_internal_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass.""" """Run when entity will be removed from hass."""
assert self.hass is not None
_, data = await asyncio.gather( _, data = await asyncio.gather(
super().async_internal_will_remove_from_hass(), super().async_internal_will_remove_from_hass(),
RestoreStateData.async_get_instance(self.hass), RestoreStateData.async_get_instance(self.hass),
@ -255,7 +253,7 @@ class RestoreEntity(Entity):
"""Get the entity state from the previous run.""" """Get the entity state from the previous run."""
if self.hass is None or self.entity_id is None: if self.hass is None or self.entity_id is None:
# Return None if this entity isn't added to hass yet # Return None if this entity isn't added to hass yet
_LOGGER.warning("Cannot get last state. Entity not added to hass") _LOGGER.warning("Cannot get last state. Entity not added to hass") # type: ignore[unreachable]
return None return None
data = await RestoreStateData.async_get_instance(self.hass) data = await RestoreStateData.async_get_instance(self.hass)
if self.entity_id not in data.last_states: if self.entity_id not in data.last_states:

View file

@ -425,8 +425,6 @@ class Template:
This method must be run in the event loop. This method must be run in the event loop.
""" """
assert self.hass
if self.is_static: if self.is_static:
return False return False