From 1e0165c5f708bff5d9072d65ce51994f8c523ad1 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 27 Jan 2025 10:16:13 +0100 Subject: [PATCH] Add lovelace compatiblity code (#136617) * Add lovelace compatiblity code * Docstring * Add tests --- homeassistant/components/lovelace/__init__.py | 27 ++++++++++++ tests/components/lovelace/test_init.py | 41 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/homeassistant/components/lovelace/__init__.py b/homeassistant/components/lovelace/__init__.py index 9b1c86edb36..51d2ed3eab7 100644 --- a/homeassistant/components/lovelace/__init__.py +++ b/homeassistant/components/lovelace/__init__.py @@ -15,6 +15,7 @@ from homeassistant.const import CONF_FILENAME, CONF_MODE, CONF_RESOURCES from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import collection, config_validation as cv +from homeassistant.helpers.frame import report_usage from homeassistant.helpers.service import async_register_admin_service from homeassistant.helpers.typing import ConfigType from homeassistant.loader import async_get_integration @@ -99,6 +100,32 @@ class LovelaceData: resources: resources.ResourceYAMLCollection | resources.ResourceStorageCollection yaml_dashboards: dict[str | None, ConfigType] + def __getitem__(self, name: str) -> Any: + """Enable method for compatibility reason. + + Following migration from an untyped dict to a dataclass in + https://github.com/home-assistant/core/pull/136313 + """ + report_usage( + f"accessed lovelace_data['{name}'] instead of lovelace_data.{name}", + breaks_in_ha_version="2026.2", + ) + return getattr(self, name) + + def get(self, name: str, default: Any = None) -> Any: + """Enable method for compatibility reason. + + Following migration from an untyped dict to a dataclass in + https://github.com/home-assistant/core/pull/136313 + """ + report_usage( + f"accessed lovelace_data.get('{name}') instead of lovelace_data.{name}", + breaks_in_ha_version="2026.2", + ) + if hasattr(self, name): + return getattr(self, name) + return default + async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Lovelace commands.""" diff --git a/tests/components/lovelace/test_init.py b/tests/components/lovelace/test_init.py index f56ff4371e6..6f11c22466e 100644 --- a/tests/components/lovelace/test_init.py +++ b/tests/components/lovelace/test_init.py @@ -38,3 +38,44 @@ async def test_create_dashboards_when_onboarded( response = await client.receive_json() assert response["success"] assert response["result"] == [] + + +async def test_hass_data_compatibility( + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test compatibility for external access. + + See: + https://github.com/hacs/integration/blob/4a820e8b1b066bc54a1c9c61102038af6c030603 + /custom_components/hacs/repositories/plugin.py#L173 + """ + expected = ( + "Detected that integration 'lovelace' accessed lovelace_data.get('resources')" + " instead of lovelace_data.resources at" + ) + + assert await async_setup_component(hass, "lovelace", {}) + + assert (lovelace_data := hass.data.get("lovelace")) is not None + assert expected not in caplog.text + + # Direct access to resources is fine + assert lovelace_data.resources is not None + assert ( + "Detected that integration 'lovelace' accessed lovelace_data" not in caplog.text + ) + + # Dict compatibility logs warning + assert lovelace_data["resources"] is not None + assert ( + "Detected that integration 'lovelace' accessed lovelace_data['resources']" + in caplog.text + ) + + # Dict get compatibility logs warning + assert lovelace_data.get("resources") is not None + assert ( + "Detected that integration 'lovelace' accessed lovelace_data.get('resources')" + in caplog.text + )