From 0723b1c539767a8e0ac125b95095585e4b91ffc7 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Thu, 2 Dec 2021 20:17:54 +0100 Subject: [PATCH] Introduce HassioServiceInfo (#60844) Co-authored-by: epenet --- homeassistant/components/hassio/discovery.py | 33 ++++++++++++++++++++ tests/components/almond/test_config_flow.py | 5 ++- tests/components/hassio/test_discovery.py | 27 ++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/hassio/discovery.py b/homeassistant/components/hassio/discovery.py index 9f15ff6e8b8..67090d78a96 100644 --- a/homeassistant/components/hassio/discovery.py +++ b/homeassistant/components/hassio/discovery.py @@ -1,6 +1,11 @@ """Implement the services discovery feature from Hass.io for Add-ons.""" +from __future__ import annotations + import asyncio +from collections.abc import Mapping +from dataclasses import dataclass import logging +from typing import Any from aiohttp import web from aiohttp.web_exceptions import HTTPServiceUnavailable @@ -9,6 +14,8 @@ from homeassistant import config_entries from homeassistant.components.http import HomeAssistantView from homeassistant.const import ATTR_NAME, ATTR_SERVICE, EVENT_HOMEASSISTANT_START from homeassistant.core import HomeAssistant, callback +from homeassistant.data_entry_flow import BaseServiceInfo +from homeassistant.helpers.frame import report from .const import ATTR_ADDON, ATTR_CONFIG, ATTR_DISCOVERY, ATTR_UUID from .handler import HassioAPIError @@ -16,6 +23,32 @@ from .handler import HassioAPIError _LOGGER = logging.getLogger(__name__) +@dataclass +class HassioServiceInfo(BaseServiceInfo): + """Prepared info from hassio entries.""" + + config: Mapping[str, Any] + + # Used to prevent log flooding. To be removed in 2022.6 + _warning_logged: bool = False + + def __getitem__(self, name: str) -> Any: + """ + Allow property access by name for compatibility reason. + + Deprecated, and will be removed in version 2022.6. + """ + if not self._warning_logged: + report( + f"accessed discovery_info['{name}'] instead of discovery_info.config['{name}']; this will fail in version 2022.6", + exclude_integrations={"hassio"}, + error_if_core=False, + level=logging.DEBUG, + ) + self._warning_logged = True + return self.config[name] + + @callback def async_setup_discovery_view(hass: HomeAssistant, hassio): """Discovery setup.""" diff --git a/tests/components/almond/test_config_flow.py b/tests/components/almond/test_config_flow.py index e0e88d0f43b..5e4283fb611 100644 --- a/tests/components/almond/test_config_flow.py +++ b/tests/components/almond/test_config_flow.py @@ -6,6 +6,7 @@ from unittest.mock import patch from homeassistant import config_entries, data_entry_flow, setup from homeassistant.components.almond import config_flow from homeassistant.components.almond.const import DOMAIN +from homeassistant.components.hassio.discovery import HassioServiceInfo from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET from homeassistant.helpers import config_entry_oauth2_flow @@ -51,7 +52,9 @@ async def test_hassio(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_HASSIO}, - data={"addon": "Almond add-on", "host": "almond-addon", "port": "1234"}, + data=HassioServiceInfo( + config={"addon": "Almond add-on", "host": "almond-addon", "port": "1234"} + ), ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM diff --git a/tests/components/hassio/test_discovery.py b/tests/components/hassio/test_discovery.py index fc99b06619f..de424c4d339 100644 --- a/tests/components/hassio/test_discovery.py +++ b/tests/components/hassio/test_discovery.py @@ -2,6 +2,7 @@ from http import HTTPStatus from unittest.mock import Mock, patch +from homeassistant.components.hassio.discovery import HassioServiceInfo from homeassistant.components.hassio.handler import HassioAPIError from homeassistant.const import EVENT_HOMEASSISTANT_START from homeassistant.setup import async_setup_component @@ -168,3 +169,29 @@ async def test_hassio_discovery_webhook(hass, aioclient_mock, hassio_client): "addon": "Mosquitto Test", } ) + + +async def test_service_info_compatibility(hass, caplog): + """Test compatibility with old-style dict. + + To be removed in 2022.6 + """ + discovery_info = HassioServiceInfo( + config={ + "broker": "mock-broker", + "port": 1883, + "username": "mock-user", + "password": "mock-pass", + "protocol": "3.1.1", + "addon": "Mosquitto Test", + } + ) + + # Ensure first call get logged + assert discovery_info["broker"] == "mock-broker" + assert "Detected code that accessed discovery_info['broker']" in caplog.text + + # Ensure second call doesn't get logged + caplog.clear() + assert discovery_info["broker"] == "mock-broker" + assert "Detected code that accessed discovery_info['broker']" not in caplog.text