diff --git a/.strict-typing b/.strict-typing index e5de22ce608..ff2bd9800e7 100644 --- a/.strict-typing +++ b/.strict-typing @@ -122,6 +122,7 @@ homeassistant.components.climate.* homeassistant.components.cloud.* homeassistant.components.co2signal.* homeassistant.components.command_line.* +homeassistant.components.config.* homeassistant.components.configurator.* homeassistant.components.counter.* homeassistant.components.cover.* diff --git a/homeassistant/components/config/__init__.py b/homeassistant/components/config/__init__.py index 84a1c2eaa17..05e5d3b9a2d 100644 --- a/homeassistant/components/config/__init__.py +++ b/homeassistant/components/config/__init__.py @@ -1,9 +1,14 @@ """Component to configure Home Assistant via an API.""" +from __future__ import annotations + import asyncio +from collections.abc import Callable, Coroutine from http import HTTPStatus import importlib import os +from typing import Any, Generic, TypeVar, cast +from aiohttp import web import voluptuous as vol from homeassistant.components import frontend @@ -16,6 +21,9 @@ from homeassistant.helpers.typing import ConfigType from homeassistant.setup import ATTR_COMPONENT from homeassistant.util.file import write_utf8_file_atomic from homeassistant.util.yaml import dump, load_yaml +from homeassistant.util.yaml.loader import JSON_TYPE + +_DataT = TypeVar("_DataT", dict[str, dict[str, Any]], list[dict[str, Any]]) DOMAIN = "config" SECTIONS = ( @@ -42,7 +50,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass, "config", "config", "hass:cog", require_admin=True ) - async def setup_panel(panel_name): + async def setup_panel(panel_name: str) -> None: """Set up a panel.""" panel = importlib.import_module(f".{panel_name}", __name__) @@ -63,20 +71,24 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: return True -class BaseEditConfigView(HomeAssistantView): +class BaseEditConfigView(HomeAssistantView, Generic[_DataT]): """Configure a Group endpoint.""" def __init__( self, - component, - config_type, - path, - key_schema, - data_schema, + component: str, + config_type: str, + path: str, + key_schema: Callable[[Any], str], + data_schema: Callable[[dict[str, Any]], Any], *, - post_write_hook=None, - data_validator=None, - ): + post_write_hook: Callable[[str, str], Coroutine[Any, Any, None]] | None = None, + data_validator: Callable[ + [HomeAssistant, str, dict[str, Any]], + Coroutine[Any, Any, dict[str, Any] | None], + ] + | None = None, + ) -> None: """Initialize a config view.""" self.url = f"/api/config/{component}/{config_type}/{{config_key}}" self.name = f"api:config:{component}:{config_type}" @@ -87,26 +99,36 @@ class BaseEditConfigView(HomeAssistantView): self.data_validator = data_validator self.mutation_lock = asyncio.Lock() - def _empty_config(self): + def _empty_config(self) -> _DataT: """Empty config if file not found.""" raise NotImplementedError - def _get_value(self, hass, data, config_key): + def _get_value( + self, hass: HomeAssistant, data: _DataT, config_key: str + ) -> dict[str, Any] | None: """Get value.""" raise NotImplementedError - def _write_value(self, hass, data, config_key, new_value): + def _write_value( + self, + hass: HomeAssistant, + data: _DataT, + config_key: str, + new_value: dict[str, Any], + ) -> None: """Set value.""" raise NotImplementedError - def _delete_value(self, hass, data, config_key): + def _delete_value( + self, hass: HomeAssistant, data: _DataT, config_key: str + ) -> dict[str, Any] | None: """Delete value.""" raise NotImplementedError @require_admin - async def get(self, request, config_key): + async def get(self, request: web.Request, config_key: str) -> web.Response: """Fetch device specific config.""" - hass = request.app["hass"] + hass: HomeAssistant = request.app["hass"] async with self.mutation_lock: current = await self.read_config(hass) value = self._get_value(hass, current, config_key) @@ -117,7 +139,7 @@ class BaseEditConfigView(HomeAssistantView): return self.json(value) @require_admin - async def post(self, request, config_key): + async def post(self, request: web.Request, config_key: str) -> web.Response: """Validate config and return results.""" try: data = await request.json() @@ -129,7 +151,7 @@ class BaseEditConfigView(HomeAssistantView): except vol.Invalid as err: return self.json_message(f"Key malformed: {err}", HTTPStatus.BAD_REQUEST) - hass = request.app["hass"] + hass: HomeAssistant = request.app["hass"] try: # We just validate, we don't store that data because @@ -159,9 +181,9 @@ class BaseEditConfigView(HomeAssistantView): return self.json({"result": "ok"}) @require_admin - async def delete(self, request, config_key): + async def delete(self, request: web.Request, config_key: str) -> web.Response: """Remove an entry.""" - hass = request.app["hass"] + hass: HomeAssistant = request.app["hass"] async with self.mutation_lock: current = await self.read_config(hass) value = self._get_value(hass, current, config_key) @@ -178,46 +200,64 @@ class BaseEditConfigView(HomeAssistantView): return self.json({"result": "ok"}) - async def read_config(self, hass): + async def read_config(self, hass: HomeAssistant) -> _DataT: """Read the config.""" current = await hass.async_add_executor_job(_read, hass.config.path(self.path)) if not current: current = self._empty_config() - return current + return cast(_DataT, current) -class EditKeyBasedConfigView(BaseEditConfigView): +class EditKeyBasedConfigView(BaseEditConfigView[dict[str, dict[str, Any]]]): """Configure a list of entries.""" - def _empty_config(self): + def _empty_config(self) -> dict[str, Any]: """Return an empty config.""" return {} - def _get_value(self, hass, data, config_key): + def _get_value( + self, hass: HomeAssistant, data: dict[str, dict[str, Any]], config_key: str + ) -> dict[str, Any] | None: """Get value.""" return data.get(config_key) - def _write_value(self, hass, data, config_key, new_value): + def _write_value( + self, + hass: HomeAssistant, + data: dict[str, dict[str, Any]], + config_key: str, + new_value: dict[str, Any], + ) -> None: """Set value.""" data.setdefault(config_key, {}).update(new_value) - def _delete_value(self, hass, data, config_key): + def _delete_value( + self, hass: HomeAssistant, data: dict[str, dict[str, Any]], config_key: str + ) -> dict[str, Any]: """Delete value.""" return data.pop(config_key) -class EditIdBasedConfigView(BaseEditConfigView): +class EditIdBasedConfigView(BaseEditConfigView[list[dict[str, Any]]]): """Configure key based config entries.""" - def _empty_config(self): + def _empty_config(self) -> list[Any]: """Return an empty config.""" return [] - def _get_value(self, hass, data, config_key): + def _get_value( + self, hass: HomeAssistant, data: list[dict[str, Any]], config_key: str + ) -> dict[str, Any] | None: """Get value.""" return next((val for val in data if val.get(CONF_ID) == config_key), None) - def _write_value(self, hass, data, config_key, new_value): + def _write_value( + self, + hass: HomeAssistant, + data: list[dict[str, Any]], + config_key: str, + new_value: dict[str, Any], + ) -> None: """Set value.""" if (value := self._get_value(hass, data, config_key)) is None: value = {CONF_ID: config_key} @@ -225,7 +265,9 @@ class EditIdBasedConfigView(BaseEditConfigView): value.update(new_value) - def _delete_value(self, hass, data, config_key): + def _delete_value( + self, hass: HomeAssistant, data: list[dict[str, Any]], config_key: str + ) -> None: """Delete value.""" index = next( idx for idx, val in enumerate(data) if val.get(CONF_ID) == config_key @@ -233,7 +275,7 @@ class EditIdBasedConfigView(BaseEditConfigView): data.pop(index) -def _read(path): +def _read(path: str) -> JSON_TYPE | None: """Read YAML helper.""" if not os.path.isfile(path): return None @@ -241,7 +283,7 @@ def _read(path): return load_yaml(path) -def _write(path, data): +def _write(path: str, data: dict | list) -> None: """Write YAML helper.""" # Do it before opening file. If dump causes error it will now not # truncate the file. diff --git a/homeassistant/components/config/area_registry.py b/homeassistant/components/config/area_registry.py index d41c712dffb..88f619ee349 100644 --- a/homeassistant/components/config/area_registry.py +++ b/homeassistant/components/config/area_registry.py @@ -1,14 +1,16 @@ """HTTP views to interact with the area registry.""" +from __future__ import annotations + from typing import Any import voluptuous as vol from homeassistant.components import websocket_api from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers.area_registry import async_get +from homeassistant.helpers.area_registry import AreaEntry, async_get -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Enable the Area Registry views.""" websocket_api.async_register_command(hass, websocket_list_areas) websocket_api.async_register_command(hass, websocket_create_area) @@ -126,7 +128,7 @@ def websocket_update_area( @callback -def _entry_dict(entry): +def _entry_dict(entry: AreaEntry) -> dict[str, Any]: """Convert entry to API format.""" return { "aliases": entry.aliases, diff --git a/homeassistant/components/config/auth.py b/homeassistant/components/config/auth.py index 1699a4c8509..355dc739a9c 100644 --- a/homeassistant/components/config/auth.py +++ b/homeassistant/components/config/auth.py @@ -1,8 +1,11 @@ """Offer API to configure Home Assistant auth.""" +from __future__ import annotations + from typing import Any import voluptuous as vol +from homeassistant.auth.models import User from homeassistant.components import websocket_api from homeassistant.core import HomeAssistant @@ -17,7 +20,7 @@ SCHEMA_WS_DELETE = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend( ) -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Enable the Home Assistant views.""" websocket_api.async_register_command( hass, WS_TYPE_LIST, websocket_list, SCHEMA_WS_LIST @@ -151,7 +154,7 @@ async def websocket_update( ) -def _user_info(user): +def _user_info(user: User) -> dict[str, Any]: """Format a user.""" ha_username = next( diff --git a/homeassistant/components/config/auth_provider_homeassistant.py b/homeassistant/components/config/auth_provider_homeassistant.py index d0606a748a9..c8b7e91f5a7 100644 --- a/homeassistant/components/config/auth_provider_homeassistant.py +++ b/homeassistant/components/config/auth_provider_homeassistant.py @@ -1,4 +1,6 @@ """Offer API to configure the Home Assistant auth provider.""" +from __future__ import annotations + from typing import Any import voluptuous as vol @@ -9,7 +11,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import Unauthorized -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Enable the Home Assistant views.""" websocket_api.async_register_command(hass, websocket_create) websocket_api.async_register_command(hass, websocket_delete) @@ -115,7 +117,7 @@ async def websocket_change_password( ) -> None: """Change current user password.""" if (user := connection.user) is None: - connection.send_error(msg["id"], "user_not_found", "User not found") + connection.send_error(msg["id"], "user_not_found", "User not found") # type: ignore[unreachable] return provider = auth_ha.async_get_provider(hass) diff --git a/homeassistant/components/config/automation.py b/homeassistant/components/config/automation.py index 72a493f8c1f..b3c7b27dc70 100644 --- a/homeassistant/components/config/automation.py +++ b/homeassistant/components/config/automation.py @@ -1,4 +1,7 @@ """Provide configuration end points for Automations.""" +from __future__ import annotations + +from typing import Any import uuid from homeassistant.components.automation.config import ( @@ -8,15 +11,16 @@ from homeassistant.components.automation.config import ( ) from homeassistant.config import AUTOMATION_CONFIG_PATH from homeassistant.const import CONF_ID, SERVICE_RELOAD +from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_registry as er from . import ACTION_DELETE, EditIdBasedConfigView -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Set up the Automation config API.""" - async def hook(action, config_key): + async def hook(action: str, config_key: str) -> None: """post_write_hook for Config View that reloads automations.""" await hass.services.async_call(DOMAIN, SERVICE_RELOAD) @@ -49,7 +53,13 @@ async def async_setup(hass): class EditAutomationConfigView(EditIdBasedConfigView): """Edit automation config.""" - def _write_value(self, hass, data, config_key, new_value): + def _write_value( + self, + hass: HomeAssistant, + data: list[dict[str, Any]], + config_key: str, + new_value: dict[str, Any], + ) -> None: """Set value.""" updated_value = {CONF_ID: config_key} diff --git a/homeassistant/components/config/config_entries.py b/homeassistant/components/config/config_entries.py index 77e2548d424..c289459a2af 100644 --- a/homeassistant/components/config/config_entries.py +++ b/homeassistant/components/config/config_entries.py @@ -1,8 +1,9 @@ """Http views to control the config manager.""" from __future__ import annotations +from collections.abc import Callable from http import HTTPStatus -from typing import Any +from typing import Any, NoReturn from aiohttp import web import aiohttp.web_exceptions @@ -29,7 +30,7 @@ from homeassistant.loader import ( ) -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Enable the Home Assistant views.""" hass.http.register_view(ConfigManagerEntryIndexView) hass.http.register_view(ConfigManagerEntryResourceView) @@ -58,7 +59,7 @@ class ConfigManagerEntryIndexView(HomeAssistantView): url = "/api/config/config_entries/entry" name = "api:config:config_entries:entry" - async def get(self, request): + async def get(self, request: web.Request) -> web.Response: """List available config entries.""" hass: HomeAssistant = request.app["hass"] domain = None @@ -76,12 +77,12 @@ class ConfigManagerEntryResourceView(HomeAssistantView): url = "/api/config/config_entries/entry/{entry_id}" name = "api:config:config_entries:entry:resource" - async def delete(self, request, entry_id): + async def delete(self, request: web.Request, entry_id: str) -> web.Response: """Delete a config entry.""" if not request["hass_user"].is_admin: raise Unauthorized(config_entry_id=entry_id, permission="remove") - hass = request.app["hass"] + hass: HomeAssistant = request.app["hass"] try: result = await hass.config_entries.async_remove(entry_id) @@ -97,12 +98,12 @@ class ConfigManagerEntryResourceReloadView(HomeAssistantView): url = "/api/config/config_entries/entry/{entry_id}/reload" name = "api:config:config_entries:entry:resource:reload" - async def post(self, request, entry_id): + async def post(self, request: web.Request, entry_id: str) -> web.Response: """Reload a config entry.""" if not request["hass_user"].is_admin: raise Unauthorized(config_entry_id=entry_id, permission="remove") - hass = request.app["hass"] + hass: HomeAssistant = request.app["hass"] entry = hass.config_entries.async_get_entry(entry_id) if not entry: return self.json_message("Invalid entry specified", HTTPStatus.NOT_FOUND) @@ -116,7 +117,12 @@ class ConfigManagerEntryResourceReloadView(HomeAssistantView): return self.json({"require_restart": not entry.state.recoverable}) -def _prepare_config_flow_result_json(result, prepare_result_json): +def _prepare_config_flow_result_json( + result: data_entry_flow.FlowResult, + prepare_result_json: Callable[ + [data_entry_flow.FlowResult], data_entry_flow.FlowResult + ], +) -> data_entry_flow.FlowResult: """Convert result to JSON.""" if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY: return prepare_result_json(result) @@ -134,14 +140,14 @@ class ConfigManagerFlowIndexView(FlowManagerIndexView): url = "/api/config/config_entries/flow" name = "api:config:config_entries:flow" - async def get(self, request): + async def get(self, request: web.Request) -> NoReturn: """Not implemented.""" raise aiohttp.web_exceptions.HTTPMethodNotAllowed("GET", ["POST"]) @require_admin( error=Unauthorized(perm_category=CAT_CONFIG_ENTRIES, permission="add") ) - async def post(self, request): + async def post(self, request: web.Request) -> web.Response: """Handle a POST request.""" try: return await super().post(request) @@ -151,7 +157,9 @@ class ConfigManagerFlowIndexView(FlowManagerIndexView): status=HTTPStatus.BAD_REQUEST, ) - def _prepare_result_json(self, result): + def _prepare_result_json( + self, result: data_entry_flow.FlowResult + ) -> data_entry_flow.FlowResult: """Convert result to JSON.""" return _prepare_config_flow_result_json(result, super()._prepare_result_json) @@ -165,18 +173,20 @@ class ConfigManagerFlowResourceView(FlowManagerResourceView): @require_admin( error=Unauthorized(perm_category=CAT_CONFIG_ENTRIES, permission="add") ) - async def get(self, request, /, flow_id): + async def get(self, request: web.Request, /, flow_id: str) -> web.Response: """Get the current state of a data_entry_flow.""" return await super().get(request, flow_id) @require_admin( error=Unauthorized(perm_category=CAT_CONFIG_ENTRIES, permission="add") ) - async def post(self, request, flow_id): + async def post(self, request: web.Request, flow_id: str) -> web.Response: """Handle a POST request.""" return await super().post(request, flow_id) - def _prepare_result_json(self, result): + def _prepare_result_json( + self, result: data_entry_flow.FlowResult + ) -> data_entry_flow.FlowResult: """Convert result to JSON.""" return _prepare_config_flow_result_json(result, super()._prepare_result_json) @@ -187,10 +197,10 @@ class ConfigManagerAvailableFlowView(HomeAssistantView): url = "/api/config/config_entries/flow_handlers" name = "api:config:config_entries:flow_handlers" - async def get(self, request): + async def get(self, request: web.Request) -> web.Response: """List available flow handlers.""" - hass = request.app["hass"] - kwargs = {} + hass: HomeAssistant = request.app["hass"] + kwargs: dict[str, Any] = {} if "type" in request.query: kwargs["type_filter"] = request.query["type"] return self.json(await async_get_config_flows(hass, **kwargs)) @@ -205,7 +215,7 @@ class OptionManagerFlowIndexView(FlowManagerIndexView): @require_admin( error=Unauthorized(perm_category=CAT_CONFIG_ENTRIES, permission=POLICY_EDIT) ) - async def post(self, request): + async def post(self, request: web.Request) -> web.Response: """Handle a POST request. handler in request is entry_id. @@ -222,14 +232,14 @@ class OptionManagerFlowResourceView(FlowManagerResourceView): @require_admin( error=Unauthorized(perm_category=CAT_CONFIG_ENTRIES, permission=POLICY_EDIT) ) - async def get(self, request, /, flow_id): + async def get(self, request: web.Request, /, flow_id: str) -> web.Response: """Get the current state of a data_entry_flow.""" return await super().get(request, flow_id) @require_admin( error=Unauthorized(perm_category=CAT_CONFIG_ENTRIES, permission=POLICY_EDIT) ) - async def post(self, request, flow_id): + async def post(self, request: web.Request, flow_id: str) -> web.Response: """Handle a POST request.""" return await super().post(request, flow_id) @@ -535,7 +545,7 @@ async def async_matching_config_entries( @callback -def entry_json(entry: config_entries.ConfigEntry) -> dict: +def entry_json(entry: config_entries.ConfigEntry) -> dict[str, Any]: """Return JSON value of a config entry.""" handler = config_entries.HANDLERS.get(entry.domain) # work out if handler has support for options flow diff --git a/homeassistant/components/config/core.py b/homeassistant/components/config/core.py index 4c64028874d..e6eac5f6e8e 100644 --- a/homeassistant/components/config/core.py +++ b/homeassistant/components/config/core.py @@ -1,7 +1,9 @@ """Component to interact with Hassbian tools.""" +from __future__ import annotations from typing import Any +from aiohttp import web import voluptuous as vol from homeassistant.components import websocket_api @@ -13,7 +15,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.util import location, unit_system -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Set up the Hassbian config.""" hass.http.register_view(CheckConfigView) websocket_api.async_register_command(hass, websocket_update_config) @@ -28,7 +30,7 @@ class CheckConfigView(HomeAssistantView): name = "api:config:core:check_config" @require_admin - async def post(self, request): + async def post(self, request: web.Request) -> web.Response: """Validate configuration and return results.""" res = await check_config.async_check_ha_config_file(request.app["hass"]) diff --git a/homeassistant/components/config/device_registry.py b/homeassistant/components/config/device_registry.py index cbf3623e7a8..dfa55b02c30 100644 --- a/homeassistant/components/config/device_registry.py +++ b/homeassistant/components/config/device_registry.py @@ -17,7 +17,7 @@ from homeassistant.helpers.device_registry import ( ) -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Enable the Device Registry views.""" websocket_api.async_register_command(hass, websocket_list_devices) diff --git a/homeassistant/components/config/scene.py b/homeassistant/components/config/scene.py index 037cd55d6a0..efbfd73db05 100644 --- a/homeassistant/components/config/scene.py +++ b/homeassistant/components/config/scene.py @@ -1,19 +1,22 @@ """Provide configuration end points for Scenes.""" +from __future__ import annotations + +from typing import Any import uuid from homeassistant.components.scene import DOMAIN, PLATFORM_SCHEMA from homeassistant.config import SCENE_CONFIG_PATH from homeassistant.const import CONF_ID, SERVICE_RELOAD -from homeassistant.core import DOMAIN as HA_DOMAIN +from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant from homeassistant.helpers import config_validation as cv, entity_registry as er from . import ACTION_DELETE, EditIdBasedConfigView -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Set up the Scene config API.""" - async def hook(action, config_key): + async def hook(action: str, config_key: str) -> None: """post_write_hook for Config View that reloads scenes.""" if action != ACTION_DELETE: await hass.services.async_call(DOMAIN, SERVICE_RELOAD) @@ -44,7 +47,13 @@ async def async_setup(hass): class EditSceneConfigView(EditIdBasedConfigView): """Edit scene config.""" - def _write_value(self, hass, data, config_key, new_value): + def _write_value( + self, + hass: HomeAssistant, + data: list[dict[str, Any]], + config_key: str, + new_value: dict[str, Any], + ) -> None: """Set value.""" updated_value = {CONF_ID: config_key} # Iterate through some keys that we want to have ordered in the output diff --git a/homeassistant/components/config/script.py b/homeassistant/components/config/script.py index 73f89aaf509..aa8a2a52d83 100644 --- a/homeassistant/components/config/script.py +++ b/homeassistant/components/config/script.py @@ -1,4 +1,8 @@ """Provide configuration end points for scripts.""" +from __future__ import annotations + +from typing import Any + from homeassistant.components.script import DOMAIN from homeassistant.components.script.config import ( SCRIPT_ENTITY_SCHEMA, @@ -6,15 +10,16 @@ from homeassistant.components.script.config import ( ) from homeassistant.config import SCRIPT_CONFIG_PATH from homeassistant.const import SERVICE_RELOAD +from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_registry as er from . import ACTION_DELETE, EditKeyBasedConfigView -async def async_setup(hass): +async def async_setup(hass: HomeAssistant) -> bool: """Set up the script config API.""" - async def hook(action, config_key): + async def hook(action: str, config_key: str) -> None: """post_write_hook for Config View that reloads scripts.""" if action != ACTION_DELETE: await hass.services.async_call(DOMAIN, SERVICE_RELOAD) @@ -46,6 +51,12 @@ async def async_setup(hass): class EditScriptConfigView(EditKeyBasedConfigView): """Edit script config.""" - def _write_value(self, hass, data, config_key, new_value): + def _write_value( + self, + hass: HomeAssistant, + data: dict[str, dict[str, Any]], + config_key: str, + new_value: dict[str, Any], + ) -> None: """Set value.""" data[config_key] = new_value diff --git a/homeassistant/util/yaml/dumper.py b/homeassistant/util/yaml/dumper.py index 65747d1fd3e..ec4700ef17e 100644 --- a/homeassistant/util/yaml/dumper.py +++ b/homeassistant/util/yaml/dumper.py @@ -17,7 +17,7 @@ except ImportError: ) -def dump(_dict: dict) -> str: +def dump(_dict: dict | list) -> str: """Dump YAML to a string and remove null.""" return yaml.dump( _dict, diff --git a/mypy.ini b/mypy.ini index 84e0a494f65..d1918acbf66 100644 --- a/mypy.ini +++ b/mypy.ini @@ -980,6 +980,16 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.config.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.configurator.*] check_untyped_defs = true disallow_incomplete_defs = true