diff --git a/homeassistant/block_async_io.py b/homeassistant/block_async_io.py index cd33a4207a88516f72de264ab6f80e61686d2ce5..ec56b7467064ccabf2f05d873d97f5b81656e485 100644 --- a/homeassistant/block_async_io.py +++ b/homeassistant/block_async_io.py @@ -7,7 +7,7 @@ from homeassistant.util.async_ import protect_loop def enable() -> None: """Enable the detection of I/O in the event loop.""" # Prevent urllib3 and requests doing I/O in event loop - HTTPConnection.putrequest = protect_loop(HTTPConnection.putrequest) + HTTPConnection.putrequest = protect_loop(HTTPConnection.putrequest) # type: ignore # Currently disabled. pytz doing I/O when getting timezone. # Prevent files being opened inside the event loop diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 77efc3824dfb69db102ce3bf0a77f5b3bd3bce6b..f36e2c6accb3a5eac3bbdc4f8a35abb2b7fc5cf8 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -10,7 +10,7 @@ import weakref import attr from homeassistant import data_entry_flow, loader -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError from homeassistant.helpers import entity_registry from homeassistant.helpers.event import Event @@ -96,6 +96,9 @@ class OperationNotAllowed(ConfigError): """Raised when a config entry operation is not allowed.""" +UpdateListenerType = Callable[[HomeAssistant, "ConfigEntry"], Any] + + class ConfigEntry: """Hold a configuration entry.""" @@ -165,7 +168,7 @@ class ConfigEntry: self.unique_id = unique_id # Listeners to call on update - self.update_listeners: List = [] + self.update_listeners: List[weakref.ReferenceType[UpdateListenerType]] = [] # Function to cancel a scheduled retry self._async_cancel_retry_setup: Optional[Callable[[], Any]] = None @@ -398,11 +401,9 @@ class ConfigEntry: ) return False - def add_update_listener(self, listener: Callable) -> Callable: + def add_update_listener(self, listener: UpdateListenerType) -> CALLBACK_TYPE: """Listen for when entry is updated. - Listener: Callback function(hass, entry) - Returns function to unlisten. """ weak_listener = weakref.ref(listener) @@ -768,7 +769,8 @@ class ConfigEntries: for listener_ref in entry.update_listeners: listener = listener_ref() - self.hass.async_create_task(listener(self.hass, entry)) + if listener is not None: + self.hass.async_create_task(listener(self.hass, entry)) self._async_schedule_save() diff --git a/homeassistant/helpers/area_registry.py b/homeassistant/helpers/area_registry.py index 72f4b2c5e6dfac5d4f216f89b86df95ababdf2b2..5def290766ff32de8e8286b38127a71b42828b91 100644 --- a/homeassistant/helpers/area_registry.py +++ b/homeassistant/helpers/area_registry.py @@ -2,7 +2,7 @@ from asyncio import Event from collections import OrderedDict import logging -from typing import Iterable, MutableMapping, Optional, cast +from typing import Dict, Iterable, List, MutableMapping, Optional, cast import uuid import attr @@ -132,7 +132,7 @@ class AreaRegistry: self._store.async_delay_save(self._data_to_save, SAVE_DELAY) @callback - def _data_to_save(self) -> dict: + def _data_to_save(self) -> Dict[str, List[Dict[str, Optional[str]]]]: """Return data of area registry to store in a file.""" data = {} diff --git a/homeassistant/helpers/entityfilter.py b/homeassistant/helpers/entityfilter.py index dfcbbeb4cd03532a341f57c7187729189f97da01..608fae0242ef98d8e297eb7d2f8d25775b9afd3b 100644 --- a/homeassistant/helpers/entityfilter.py +++ b/homeassistant/helpers/entityfilter.py @@ -102,12 +102,12 @@ INCLUDE_EXCLUDE_FILTER_SCHEMA = vol.All( ) -def _glob_to_re(glob: str) -> Pattern: +def _glob_to_re(glob: str) -> Pattern[str]: """Translate and compile glob string into pattern.""" return re.compile(fnmatch.translate(glob)) -def _test_against_patterns(patterns: List[Pattern], entity_id: str) -> bool: +def _test_against_patterns(patterns: List[Pattern[str]], entity_id: str) -> bool: """Test entity against list of patterns, true if any match.""" for pattern in patterns: if pattern.match(entity_id): diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 1ca13e22e9faaa63895cc7a6b2db644327b4b951..32a22fab9e50f22aff1742d52758f503fce4df33 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -49,7 +49,7 @@ from homeassistant.helpers.service import ( CONF_SERVICE_DATA, async_prepare_call_from_config, ) -from homeassistant.helpers.typing import ConfigType +from homeassistant.helpers.typing import ConfigType, TemplateVarsType from homeassistant.util import slugify from homeassistant.util.dt import utcnow @@ -134,7 +134,7 @@ class _ScriptRun: self, hass: HomeAssistant, script: "Script", - variables: Optional[Sequence], + variables: TemplateVarsType, context: Optional[Context], log_exceptions: bool, ) -> None: @@ -724,14 +724,16 @@ class Script: self._referenced_entities = referenced return referenced - def run(self, variables=None, context=None): + def run( + self, variables: TemplateVarsType = None, context: Optional[Context] = None + ) -> None: """Run script.""" asyncio.run_coroutine_threadsafe( self.async_run(variables, context), self._hass.loop ).result() async def async_run( - self, variables: Optional[Sequence] = None, context: Optional[Context] = None + self, variables: TemplateVarsType = None, context: Optional[Context] = None ) -> None: """Run script.""" if self.is_running: diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index d2b4c334937a343aee066baedcd001b780c82c6f..13525b4dab195430a2b130249d4e4728baecd2fd 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -95,8 +95,7 @@ class Store: the second call will wait and return the result of the first call. """ if self._load_task is None: - self._load_task = self.hass.async_add_job(self._async_load()) - assert self._load_task is not None + self._load_task = self.hass.async_create_task(self._async_load()) return await self._load_task diff --git a/homeassistant/helpers/system_info.py b/homeassistant/helpers/system_info.py index 855b6153ba02e621bad7fc5e554c3b701f900bd1..12fc07dfbd87ff57d1e443290cfdc6755ff284d0 100644 --- a/homeassistant/helpers/system_info.py +++ b/homeassistant/helpers/system_info.py @@ -1,7 +1,7 @@ """Helper to gather system info.""" import os import platform -from typing import Dict +from typing import Any, Dict from homeassistant.const import __version__ as current_version from homeassistant.loader import bind_hass @@ -11,7 +11,7 @@ from .typing import HomeAssistantType @bind_hass -async def async_get_system_info(hass: HomeAssistantType) -> Dict: +async def async_get_system_info(hass: HomeAssistantType) -> Dict[str, Any]: """Return info about the system.""" info_object = { "installation_type": "Unknown", diff --git a/homeassistant/runner.py b/homeassistant/runner.py index ae68727daf5e9fe73bfc0623a86bb415104c8f06..26e7bab761610682fbe5d70ae73e7361b2bf02e0 100644 --- a/homeassistant/runner.py +++ b/homeassistant/runner.py @@ -37,7 +37,7 @@ else: PolicyBase = asyncio.DefaultEventLoopPolicy # pylint: disable=invalid-name -class HassEventLoopPolicy(PolicyBase): +class HassEventLoopPolicy(PolicyBase): # type: ignore """Event loop policy for Home Assistant.""" def __init__(self, debug: bool) -> None: @@ -48,11 +48,11 @@ class HassEventLoopPolicy(PolicyBase): @property def loop_name(self) -> str: """Return name of the loop.""" - return self._loop_factory.__name__ + return self._loop_factory.__name__ # type: ignore - def new_event_loop(self): + def new_event_loop(self) -> asyncio.AbstractEventLoop: """Get the event loop.""" - loop = super().new_event_loop() + loop: asyncio.AbstractEventLoop = super().new_event_loop() loop.set_exception_handler(_async_loop_exception_handler) if self.debug: loop.set_debug(True) @@ -68,14 +68,14 @@ class HassEventLoopPolicy(PolicyBase): return loop # Copied from Python 3.9 source - def _do_shutdown(future): + def _do_shutdown(future: asyncio.Future) -> None: try: executor.shutdown(wait=True) loop.call_soon_threadsafe(future.set_result, None) except Exception as ex: # pylint: disable=broad-except loop.call_soon_threadsafe(future.set_exception, ex) - async def shutdown_default_executor(): + async def shutdown_default_executor() -> None: """Schedule the shutdown of the default executor.""" future = loop.create_future() thread = threading.Thread(target=_do_shutdown, args=(future,)) @@ -85,7 +85,7 @@ class HassEventLoopPolicy(PolicyBase): finally: thread.join() - loop.shutdown_default_executor = shutdown_default_executor + setattr(loop, "shutdown_default_executor", shutdown_default_executor) return loop diff --git a/setup.cfg b/setup.cfg index 7df396df528e66627ca3610643870c13b1a38ca9..6dace4932dbda727685890d44336412fe7226ef4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -64,7 +64,7 @@ warn_incomplete_stub = true warn_redundant_casts = true warn_unused_configs = true -[mypy-homeassistant.bootstrap,homeassistant.components,homeassistant.config_entries,homeassistant.config,homeassistant.const,homeassistant.core,homeassistant.data_entry_flow,homeassistant.exceptions,homeassistant.loader,homeassistant.__main__,homeassistant.requirements,homeassistant.setup,homeassistant.util,homeassistant.auth.*,homeassistant.components.automation.*,homeassistant.components.binary_sensor.*,homeassistant.components.calendar.*,homeassistant.components.cover.*,homeassistant.components.device_automation.*,homeassistant.components.frontend.*,homeassistant.components.geo_location.*,homeassistant.components.group.*,homeassistant.components.history.*,homeassistant.components.http.*,homeassistant.components.image_processing.*,homeassistant.components.integration.*,homeassistant.components.light.*,homeassistant.components.lock.*,homeassistant.components.mailbox.*,homeassistant.components.media_player.*,homeassistant.components.notify.*,homeassistant.components.persistent_notification.*,homeassistant.components.proximity.*,homeassistant.components.remote.*,homeassistant.components.scene.*,homeassistant.components.sensor.*,homeassistant.components.sun.*,homeassistant.components.switch.*,homeassistant.components.systemmonitor.*,homeassistant.components.tts.*,homeassistant.components.vacuum.*,homeassistant.components.water_heater.*,homeassistant.components.weather.*,homeassistant.components.websocket_api.*,homeassistant.components.zone.*,homeassistant.helpers.*,homeassistant.scripts.*,homeassistant.util.*] +[mypy-homeassistant.block_async_io,homeassistant.bootstrap,homeassistant.components,homeassistant.config_entries,homeassistant.config,homeassistant.const,homeassistant.core,homeassistant.data_entry_flow,homeassistant.exceptions,homeassistant.__init__,homeassistant.loader,homeassistant.__main__,homeassistant.requirements,homeassistant.runner,homeassistant.setup,homeassistant.util,homeassistant.auth.*,homeassistant.components.automation.*,homeassistant.components.binary_sensor.*,homeassistant.components.calendar.*,homeassistant.components.cover.*,homeassistant.components.device_automation.*,homeassistant.components.frontend.*,homeassistant.components.geo_location.*,homeassistant.components.group.*,homeassistant.components.history.*,homeassistant.components.http.*,homeassistant.components.image_processing.*,homeassistant.components.integration.*,homeassistant.components.light.*,homeassistant.components.lock.*,homeassistant.components.mailbox.*,homeassistant.components.media_player.*,homeassistant.components.notify.*,homeassistant.components.persistent_notification.*,homeassistant.components.proximity.*,homeassistant.components.remote.*,homeassistant.components.scene.*,homeassistant.components.sensor.*,homeassistant.components.sun.*,homeassistant.components.switch.*,homeassistant.components.systemmonitor.*,homeassistant.components.tts.*,homeassistant.components.vacuum.*,homeassistant.components.water_heater.*,homeassistant.components.weather.*,homeassistant.components.websocket_api.*,homeassistant.components.zone.*,homeassistant.helpers.*,homeassistant.scripts.*,homeassistant.util.*] strict = true ignore_errors = false warn_unreachable = true