mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Enable strict-typing in lovelace (#136327)
This commit is contained in:
parent
33ce795695
commit
83e826219a
@ -307,6 +307,7 @@ homeassistant.components.logbook.*
|
|||||||
homeassistant.components.logger.*
|
homeassistant.components.logger.*
|
||||||
homeassistant.components.london_underground.*
|
homeassistant.components.london_underground.*
|
||||||
homeassistant.components.lookin.*
|
homeassistant.components.lookin.*
|
||||||
|
homeassistant.components.lovelace.*
|
||||||
homeassistant.components.luftdaten.*
|
homeassistant.components.luftdaten.*
|
||||||
homeassistant.components.madvr.*
|
homeassistant.components.madvr.*
|
||||||
homeassistant.components.manual.*
|
homeassistant.components.manual.*
|
||||||
|
@ -81,7 +81,7 @@ class LovelaceData:
|
|||||||
|
|
||||||
mode: str
|
mode: str
|
||||||
dashboards: dict[str | None, dashboard.LovelaceConfig]
|
dashboards: dict[str | None, dashboard.LovelaceConfig]
|
||||||
resources: resources.ResourceStorageCollection
|
resources: resources.ResourceYAMLCollection | resources.ResourceStorageCollection
|
||||||
yaml_dashboards: dict[str | None, ConfigType]
|
yaml_dashboards: dict[str | None, ConfigType]
|
||||||
|
|
||||||
|
|
||||||
@ -115,6 +115,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
hass.data[LOVELACE_DATA].resources = resource_collection
|
hass.data[LOVELACE_DATA].resources = resource_collection
|
||||||
|
|
||||||
default_config: dashboard.LovelaceConfig
|
default_config: dashboard.LovelaceConfig
|
||||||
|
resource_collection: (
|
||||||
|
resources.ResourceYAMLCollection | resources.ResourceStorageCollection
|
||||||
|
)
|
||||||
if mode == MODE_YAML:
|
if mode == MODE_YAML:
|
||||||
default_config = dashboard.LovelaceYAML(hass, None, None)
|
default_config = dashboard.LovelaceYAML(hass, None, None)
|
||||||
resource_collection = await create_yaml_resource_col(hass, yaml_resources)
|
resource_collection = await create_yaml_resource_col(hass, yaml_resources)
|
||||||
@ -174,7 +177,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
if hass.config.recovery_mode:
|
if hass.config.recovery_mode:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def storage_dashboard_changed(change_type, item_id, item):
|
async def storage_dashboard_changed(
|
||||||
|
change_type: str, item_id: str, item: dict
|
||||||
|
) -> None:
|
||||||
"""Handle a storage dashboard change."""
|
"""Handle a storage dashboard change."""
|
||||||
url_path = item[CONF_URL_PATH]
|
url_path = item[CONF_URL_PATH]
|
||||||
|
|
||||||
@ -236,7 +241,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def create_yaml_resource_col(hass, yaml_resources):
|
async def create_yaml_resource_col(
|
||||||
|
hass: HomeAssistant, yaml_resources: list[ConfigType] | None
|
||||||
|
) -> resources.ResourceYAMLCollection:
|
||||||
"""Create yaml resources collection."""
|
"""Create yaml resources collection."""
|
||||||
if yaml_resources is None:
|
if yaml_resources is None:
|
||||||
default_config = dashboard.LovelaceYAML(hass, None, None)
|
default_config = dashboard.LovelaceYAML(hass, None, None)
|
||||||
@ -256,7 +263,9 @@ async def create_yaml_resource_col(hass, yaml_resources):
|
|||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _register_panel(hass, url_path, mode, config, update):
|
def _register_panel(
|
||||||
|
hass: HomeAssistant, url_path: str | None, mode: str, config: dict, update: bool
|
||||||
|
) -> None:
|
||||||
"""Register a panel."""
|
"""Register a panel."""
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"frontend_url_path": url_path,
|
"frontend_url_path": url_path,
|
||||||
|
@ -7,7 +7,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -67,21 +67,25 @@ class LovelaceConfig(ABC):
|
|||||||
"""Return mode of the lovelace config."""
|
"""Return mode of the lovelace config."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def async_get_info(self):
|
async def async_get_info(self) -> dict[str, Any]:
|
||||||
"""Return the config info."""
|
"""Return the config info."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def async_load(self, force: bool) -> dict[str, Any]:
|
async def async_load(self, force: bool) -> dict[str, Any]:
|
||||||
"""Load config."""
|
"""Load config."""
|
||||||
|
|
||||||
async def async_save(self, config):
|
async def async_save(self, config: dict[str, Any]) -> None:
|
||||||
"""Save config."""
|
"""Save config."""
|
||||||
raise HomeAssistantError("Not supported")
|
raise HomeAssistantError("Not supported")
|
||||||
|
|
||||||
async def async_delete(self):
|
async def async_delete(self) -> None:
|
||||||
"""Delete config."""
|
"""Delete config."""
|
||||||
raise HomeAssistantError("Not supported")
|
raise HomeAssistantError("Not supported")
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def async_json(self, force: bool) -> json_fragment:
|
||||||
|
"""Return JSON representation of the config."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _config_updated(self) -> None:
|
def _config_updated(self) -> None:
|
||||||
"""Fire config updated event."""
|
"""Fire config updated event."""
|
||||||
@ -113,7 +117,7 @@ class LovelaceStorage(LovelaceConfig):
|
|||||||
"""Return mode of the lovelace config."""
|
"""Return mode of the lovelace config."""
|
||||||
return MODE_STORAGE
|
return MODE_STORAGE
|
||||||
|
|
||||||
async def async_get_info(self):
|
async def async_get_info(self) -> dict[str, Any]:
|
||||||
"""Return the Lovelace storage info."""
|
"""Return the Lovelace storage info."""
|
||||||
data = self._data or await self._load()
|
data = self._data or await self._load()
|
||||||
if data["config"] is None:
|
if data["config"] is None:
|
||||||
@ -129,7 +133,7 @@ class LovelaceStorage(LovelaceConfig):
|
|||||||
if (config := data["config"]) is None:
|
if (config := data["config"]) is None:
|
||||||
raise ConfigNotFound
|
raise ConfigNotFound
|
||||||
|
|
||||||
return config
|
return config # type: ignore[no-any-return]
|
||||||
|
|
||||||
async def async_json(self, force: bool) -> json_fragment:
|
async def async_json(self, force: bool) -> json_fragment:
|
||||||
"""Return JSON representation of the config."""
|
"""Return JSON representation of the config."""
|
||||||
@ -139,19 +143,21 @@ class LovelaceStorage(LovelaceConfig):
|
|||||||
await self._load()
|
await self._load()
|
||||||
return self._json_config or self._async_build_json()
|
return self._json_config or self._async_build_json()
|
||||||
|
|
||||||
async def async_save(self, config):
|
async def async_save(self, config: dict[str, Any]) -> None:
|
||||||
"""Save config."""
|
"""Save config."""
|
||||||
if self.hass.config.recovery_mode:
|
if self.hass.config.recovery_mode:
|
||||||
raise HomeAssistantError("Saving not supported in recovery mode")
|
raise HomeAssistantError("Saving not supported in recovery mode")
|
||||||
|
|
||||||
if self._data is None:
|
if self._data is None:
|
||||||
await self._load()
|
await self._load()
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert self._data is not None
|
||||||
self._data["config"] = config
|
self._data["config"] = config
|
||||||
self._json_config = None
|
self._json_config = None
|
||||||
self._config_updated()
|
self._config_updated()
|
||||||
await self._store.async_save(self._data)
|
await self._store.async_save(self._data)
|
||||||
|
|
||||||
async def async_delete(self):
|
async def async_delete(self) -> None:
|
||||||
"""Delete config."""
|
"""Delete config."""
|
||||||
if self.hass.config.recovery_mode:
|
if self.hass.config.recovery_mode:
|
||||||
raise HomeAssistantError("Deleting not supported in recovery mode")
|
raise HomeAssistantError("Deleting not supported in recovery mode")
|
||||||
@ -195,7 +201,7 @@ class LovelaceYAML(LovelaceConfig):
|
|||||||
"""Return mode of the lovelace config."""
|
"""Return mode of the lovelace config."""
|
||||||
return MODE_YAML
|
return MODE_YAML
|
||||||
|
|
||||||
async def async_get_info(self):
|
async def async_get_info(self) -> dict[str, Any]:
|
||||||
"""Return the YAML storage mode."""
|
"""Return the YAML storage mode."""
|
||||||
try:
|
try:
|
||||||
config = await self.async_load(False)
|
config = await self.async_load(False)
|
||||||
@ -251,7 +257,7 @@ class LovelaceYAML(LovelaceConfig):
|
|||||||
return is_updated, config, json
|
return is_updated, config, json
|
||||||
|
|
||||||
|
|
||||||
def _config_info(mode, config):
|
def _config_info(mode: str, config: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""Generate info about the config."""
|
"""Generate info about the config."""
|
||||||
return {
|
return {
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
@ -265,7 +271,7 @@ class DashboardsCollection(collection.DictStorageCollection):
|
|||||||
CREATE_SCHEMA = vol.Schema(STORAGE_DASHBOARD_CREATE_FIELDS)
|
CREATE_SCHEMA = vol.Schema(STORAGE_DASHBOARD_CREATE_FIELDS)
|
||||||
UPDATE_SCHEMA = vol.Schema(STORAGE_DASHBOARD_UPDATE_FIELDS)
|
UPDATE_SCHEMA = vol.Schema(STORAGE_DASHBOARD_UPDATE_FIELDS)
|
||||||
|
|
||||||
def __init__(self, hass):
|
def __init__(self, hass: HomeAssistant) -> None:
|
||||||
"""Initialize the dashboards collection."""
|
"""Initialize the dashboards collection."""
|
||||||
super().__init__(
|
super().__init__(
|
||||||
storage.Store(hass, DASHBOARDS_STORAGE_VERSION, DASHBOARDS_STORAGE_KEY),
|
storage.Store(hass, DASHBOARDS_STORAGE_VERSION, DASHBOARDS_STORAGE_KEY),
|
||||||
@ -283,12 +289,12 @@ class DashboardsCollection(collection.DictStorageCollection):
|
|||||||
if url_path in self.hass.data[DATA_PANELS]:
|
if url_path in self.hass.data[DATA_PANELS]:
|
||||||
raise vol.Invalid("Panel url path needs to be unique")
|
raise vol.Invalid("Panel url path needs to be unique")
|
||||||
|
|
||||||
return self.CREATE_SCHEMA(data)
|
return self.CREATE_SCHEMA(data) # type: ignore[no-any-return]
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _get_suggested_id(self, info: dict) -> str:
|
def _get_suggested_id(self, info: dict) -> str:
|
||||||
"""Suggest an ID based on the config."""
|
"""Suggest an ID based on the config."""
|
||||||
return info[CONF_URL_PATH]
|
return info[CONF_URL_PATH] # type: ignore[no-any-return]
|
||||||
|
|
||||||
async def _update_data(self, item: dict, update_data: dict) -> dict:
|
async def _update_data(self, item: dict, update_data: dict) -> dict:
|
||||||
"""Return a new updated data object."""
|
"""Return a new updated data object."""
|
||||||
|
@ -34,11 +34,11 @@ class ResourceYAMLCollection:
|
|||||||
|
|
||||||
loaded = True
|
loaded = True
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data: list[dict[str, Any]]) -> None:
|
||||||
"""Initialize a resource YAML collection."""
|
"""Initialize a resource YAML collection."""
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
async def async_get_info(self):
|
async def async_get_info(self) -> dict[str, int]:
|
||||||
"""Return the resources info for YAML mode."""
|
"""Return the resources info for YAML mode."""
|
||||||
return {"resources": len(self.async_items() or [])}
|
return {"resources": len(self.async_items() or [])}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ class ResourceStorageCollection(collection.DictStorageCollection):
|
|||||||
)
|
)
|
||||||
self.ll_config = ll_config
|
self.ll_config = ll_config
|
||||||
|
|
||||||
async def async_get_info(self):
|
async def async_get_info(self) -> dict[str, int]:
|
||||||
"""Return the resources info for YAML mode."""
|
"""Return the resources info for YAML mode."""
|
||||||
if not self.loaded:
|
if not self.loaded:
|
||||||
await self.async_load()
|
await self.async_load()
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -14,10 +15,20 @@ from homeassistant.helpers import config_validation as cv
|
|||||||
from homeassistant.helpers.json import json_fragment
|
from homeassistant.helpers.json import json_fragment
|
||||||
|
|
||||||
from .const import CONF_URL_PATH, LOVELACE_DATA, ConfigNotFound
|
from .const import CONF_URL_PATH, LOVELACE_DATA, ConfigNotFound
|
||||||
from .dashboard import LovelaceStorage
|
from .dashboard import LovelaceConfig
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .resources import ResourceStorageCollection
|
||||||
|
|
||||||
|
type AsyncLovelaceWebSocketCommandHandler[_R] = Callable[
|
||||||
|
[HomeAssistant, websocket_api.ActiveConnection, dict[str, Any], LovelaceConfig],
|
||||||
|
Awaitable[_R],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _handle_errors(func):
|
def _handle_errors[_R](
|
||||||
|
func: AsyncLovelaceWebSocketCommandHandler[_R],
|
||||||
|
) -> websocket_api.AsyncWebSocketCommandHandler:
|
||||||
"""Handle error with WebSocket calls."""
|
"""Handle error with WebSocket calls."""
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
@ -75,6 +86,8 @@ async def websocket_lovelace_resources_impl(
|
|||||||
This function is called by both Storage and YAML mode WS handlers.
|
This function is called by both Storage and YAML mode WS handlers.
|
||||||
"""
|
"""
|
||||||
resources = hass.data[LOVELACE_DATA].resources
|
resources = hass.data[LOVELACE_DATA].resources
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert isinstance(resources, ResourceStorageCollection)
|
||||||
|
|
||||||
if hass.config.safe_mode:
|
if hass.config.safe_mode:
|
||||||
connection.send_result(msg["id"], [])
|
connection.send_result(msg["id"], [])
|
||||||
@ -100,7 +113,7 @@ async def websocket_lovelace_config(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
connection: websocket_api.ActiveConnection,
|
connection: websocket_api.ActiveConnection,
|
||||||
msg: dict[str, Any],
|
msg: dict[str, Any],
|
||||||
config: LovelaceStorage,
|
config: LovelaceConfig,
|
||||||
) -> json_fragment:
|
) -> json_fragment:
|
||||||
"""Send Lovelace UI config over WebSocket connection."""
|
"""Send Lovelace UI config over WebSocket connection."""
|
||||||
return await config.async_json(msg["force"])
|
return await config.async_json(msg["force"])
|
||||||
@ -120,7 +133,7 @@ async def websocket_lovelace_save_config(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
connection: websocket_api.ActiveConnection,
|
connection: websocket_api.ActiveConnection,
|
||||||
msg: dict[str, Any],
|
msg: dict[str, Any],
|
||||||
config: LovelaceStorage,
|
config: LovelaceConfig,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Save Lovelace UI configuration."""
|
"""Save Lovelace UI configuration."""
|
||||||
await config.async_save(msg["config"])
|
await config.async_save(msg["config"])
|
||||||
@ -139,7 +152,7 @@ async def websocket_lovelace_delete_config(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
connection: websocket_api.ActiveConnection,
|
connection: websocket_api.ActiveConnection,
|
||||||
msg: dict[str, Any],
|
msg: dict[str, Any],
|
||||||
config: LovelaceStorage,
|
config: LovelaceConfig,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Delete Lovelace UI configuration."""
|
"""Delete Lovelace UI configuration."""
|
||||||
await config.async_delete()
|
await config.async_delete()
|
||||||
|
10
mypy.ini
generated
10
mypy.ini
generated
@ -2826,6 +2826,16 @@ disallow_untyped_defs = true
|
|||||||
warn_return_any = true
|
warn_return_any = true
|
||||||
warn_unreachable = true
|
warn_unreachable = true
|
||||||
|
|
||||||
|
[mypy-homeassistant.components.lovelace.*]
|
||||||
|
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.luftdaten.*]
|
[mypy-homeassistant.components.luftdaten.*]
|
||||||
check_untyped_defs = true
|
check_untyped_defs = true
|
||||||
disallow_incomplete_defs = true
|
disallow_incomplete_defs = true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user