From 3e72c346b7e777ae82b2c85d2f40c8b11d88a835 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Tue, 16 Jan 2024 13:29:26 +0100 Subject: [PATCH] Remove MELCloud YAML import support (#108113) --- homeassistant/components/melcloud/__init__.py | 40 +---- .../components/melcloud/config_flow.py | 61 +------- tests/components/melcloud/test_config_flow.py | 143 +----------------- 3 files changed, 6 insertions(+), 238 deletions(-) diff --git a/homeassistant/components/melcloud/__init__.py b/homeassistant/components/melcloud/__init__.py index d1ed5cafcbf..2187cb5b8b8 100644 --- a/homeassistant/components/melcloud/__init__.py +++ b/homeassistant/components/melcloud/__init__.py @@ -9,16 +9,13 @@ from typing import Any from aiohttp import ClientConnectionError, ClientResponseError from pymelcloud import Device, get_devices from pymelcloud.atw_device import Zone -import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry -from homeassistant.const import CONF_TOKEN, CONF_USERNAME, Platform +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_TOKEN, Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo -from homeassistant.helpers.typing import ConfigType from homeassistant.util import Throttle from .const import DOMAIN @@ -29,39 +26,6 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) PLATFORMS = [Platform.CLIMATE, Platform.SENSOR, Platform.WATER_HEATER] -CONF_LANGUAGE = "language" -CONFIG_SCHEMA = vol.Schema( - vol.All( - cv.deprecated(DOMAIN), - { - DOMAIN: vol.Schema( - { - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_TOKEN): cv.string, - } - ) - }, - ), - extra=vol.ALLOW_EXTRA, -) - - -async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Establish connection with MELCloud.""" - if DOMAIN not in config: - return True - - username = config[DOMAIN][CONF_USERNAME] - token = config[DOMAIN][CONF_TOKEN] - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={CONF_USERNAME: username, CONF_TOKEN: token}, - ) - ) - return True - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Establish connection with MELClooud.""" diff --git a/homeassistant/components/melcloud/config_flow.py b/homeassistant/components/melcloud/config_flow.py index 9293c9bb3d5..9db44d5276c 100644 --- a/homeassistant/components/melcloud/config_flow.py +++ b/homeassistant/components/melcloud/config_flow.py @@ -13,49 +13,14 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME -from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant -from homeassistant.data_entry_flow import AbortFlow, FlowResult, FlowResultType +from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -async def async_create_import_issue( - hass: HomeAssistant, source: str, issue: str, success: bool = False -) -> None: - """Create issue from import.""" - if source != config_entries.SOURCE_IMPORT: - return - if not success: - async_create_issue( - hass, - DOMAIN, - f"deprecated_yaml_import_issue_{issue}", - breaks_in_ha_version="2024.2.0", - is_fixable=False, - severity=IssueSeverity.ERROR, - translation_key=f"deprecated_yaml_import_issue_{issue}", - ) - return - async_create_issue( - hass, - HOMEASSISTANT_DOMAIN, - f"deprecated_yaml_{DOMAIN}", - breaks_in_ha_version="2024.2.0", - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key="deprecated_yaml", - translation_placeholders={ - "domain": DOMAIN, - "integration_title": "MELCloud", - }, - ) - - class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow.""" @@ -66,11 +31,7 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): async def _create_entry(self, username: str, token: str) -> FlowResult: """Register new entry.""" await self.async_set_unique_id(username) - try: - self._abort_if_unique_id_configured({CONF_TOKEN: token}) - except AbortFlow: - await async_create_import_issue(self.hass, self.context["source"], "", True) - raise + self._abort_if_unique_id_configured({CONF_TOKEN: token}) return self.async_create_entry( title=username, data={CONF_USERNAME: username, CONF_TOKEN: token} ) @@ -97,18 +58,9 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): ) except ClientResponseError as err: if err.status in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN): - await async_create_import_issue( - self.hass, self.context["source"], "invalid_auth" - ) return self.async_abort(reason="invalid_auth") - await async_create_import_issue( - self.hass, self.context["source"], "cannot_connect" - ) return self.async_abort(reason="cannot_connect") except (asyncio.TimeoutError, ClientError): - await async_create_import_issue( - self.hass, self.context["source"], "cannot_connect" - ) return self.async_abort(reason="cannot_connect") return await self._create_entry(username, acquired_token) @@ -127,15 +79,6 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): username = user_input[CONF_USERNAME] return await self._create_client(username, password=user_input[CONF_PASSWORD]) - async def async_step_import(self, user_input: dict[str, Any]) -> FlowResult: - """Import a config entry.""" - result = await self._create_client( - user_input[CONF_USERNAME], token=user_input[CONF_TOKEN] - ) - if result["type"] == FlowResultType.CREATE_ENTRY: - await async_create_import_issue(self.hass, self.context["source"], "", True) - return result - async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult: """Handle initiation of re-authentication with MELCloud.""" self.entry = self.hass.config_entries.async_get_entry(self.context["entry_id"]) diff --git a/tests/components/melcloud/test_config_flow.py b/tests/components/melcloud/test_config_flow.py index f3d49f3c0bc..5e8614a555c 100644 --- a/tests/components/melcloud/test_config_flow.py +++ b/tests/components/melcloud/test_config_flow.py @@ -7,12 +7,11 @@ from aiohttp import ClientError, ClientResponseError import pymelcloud import pytest -from homeassistant import config_entries, data_entry_flow +from homeassistant import config_entries from homeassistant.components.melcloud.const import DOMAIN from homeassistant.config_entries import SOURCE_REAUTH -from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant +from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType -import homeassistant.helpers.issue_registry as ir from tests.common import MockConfigEntry @@ -57,8 +56,6 @@ async def test_form(hass: HomeAssistant, mock_login, mock_get_devices) -> None: assert result["errors"] is None with patch( - "homeassistant.components.melcloud.async_setup", return_value=True - ) as mock_setup, patch( "homeassistant.components.melcloud.async_setup_entry", return_value=True ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( @@ -73,7 +70,6 @@ async def test_form(hass: HomeAssistant, mock_login, mock_get_devices) -> None: "username": "test-email@test-domain.com", "token": "test-token", } - assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 @@ -122,138 +118,6 @@ async def test_form_response_errors( assert result["reason"] == message -@pytest.mark.parametrize( - ("error", "message", "issue"), - [ - ( - HTTPStatus.UNAUTHORIZED, - "invalid_auth", - "deprecated_yaml_import_issue_invalid_auth", - ), - ( - HTTPStatus.FORBIDDEN, - "invalid_auth", - "deprecated_yaml_import_issue_invalid_auth", - ), - ( - HTTPStatus.INTERNAL_SERVER_ERROR, - "cannot_connect", - "deprecated_yaml_import_issue_cannot_connect", - ), - ], -) -async def test_step_import_fails( - hass: HomeAssistant, - mock_login, - mock_get_devices, - mock_request_info, - error: Exception, - message: str, - issue: str, -) -> None: - """Test raising issues on import.""" - mock_get_devices.side_effect = ClientResponseError( - mock_request_info(), (), status=error - ) - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": config_entries.SOURCE_IMPORT}, - data={"username": "test-email@test-domain.com", "token": "test-token"}, - ) - - assert result["type"] == data_entry_flow.FlowResultType.ABORT - assert result["reason"] == message - - issue_registry = ir.async_get(hass) - assert issue_registry.async_get_issue(DOMAIN, issue) - - -async def test_step_import_fails_ClientError( - hass: HomeAssistant, - mock_login, - mock_get_devices, - mock_request_info, -) -> None: - """Test raising issues on import for ClientError.""" - mock_get_devices.side_effect = ClientError() - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": config_entries.SOURCE_IMPORT}, - data={"username": "test-email@test-domain.com", "token": "test-token"}, - ) - - assert result["type"] == data_entry_flow.FlowResultType.ABORT - assert result["reason"] == "cannot_connect" - - issue_registry = ir.async_get(hass) - assert issue_registry.async_get_issue( - DOMAIN, "deprecated_yaml_import_issue_cannot_connect" - ) - - -async def test_step_import_already_exist( - hass: HomeAssistant, - mock_login, - mock_get_devices, - mock_request_info, -) -> None: - """Test that errors are shown when duplicates are added.""" - conf = {"username": "test-email@test-domain.com", "token": "test-token"} - config_entry = MockConfigEntry( - domain=DOMAIN, - data=conf, - title=conf["username"], - unique_id=conf["username"], - ) - config_entry.add_to_hass(hass) - - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=conf - ) - assert result["type"] == data_entry_flow.FlowResultType.ABORT - assert result["reason"] == "already_configured" - - issue_registry = ir.async_get(hass) - issue = issue_registry.async_get_issue( - HOMEASSISTANT_DOMAIN, "deprecated_yaml_melcloud" - ) - assert issue.translation_key == "deprecated_yaml" - - -async def test_import_with_token( - hass: HomeAssistant, mock_login, mock_get_devices -) -> None: - """Test successful import.""" - with patch( - "homeassistant.components.melcloud.async_setup", return_value=True - ) as mock_setup, patch( - "homeassistant.components.melcloud.async_setup_entry", return_value=True - ) as mock_setup_entry: - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": config_entries.SOURCE_IMPORT}, - data={"username": "test-email@test-domain.com", "token": "test-token"}, - ) - await hass.async_block_till_done() - - assert result["type"] == "create_entry" - assert result["title"] == "test-email@test-domain.com" - assert result["data"] == { - "username": "test-email@test-domain.com", - "token": "test-token", - } - assert len(mock_setup.mock_calls) == 1 - assert len(mock_setup_entry.mock_calls) == 1 - - issue_registry = ir.async_get(hass) - issue = issue_registry.async_get_issue( - HOMEASSISTANT_DOMAIN, "deprecated_yaml_melcloud" - ) - assert issue.translation_key == "deprecated_yaml" - - async def test_token_refresh(hass: HomeAssistant, mock_login, mock_get_devices) -> None: """Re-configuration with existing username should refresh token.""" mock_entry = MockConfigEntry( @@ -264,8 +128,6 @@ async def test_token_refresh(hass: HomeAssistant, mock_login, mock_get_devices) mock_entry.add_to_hass(hass) with patch( - "homeassistant.components.melcloud.async_setup", return_value=True - ) as mock_setup, patch( "homeassistant.components.melcloud.async_setup_entry", return_value=True ) as mock_setup_entry: result = await hass.config_entries.flow.async_init( @@ -280,7 +142,6 @@ async def test_token_refresh(hass: HomeAssistant, mock_login, mock_get_devices) assert result["type"] == "abort" assert result["reason"] == "already_configured" await hass.async_block_till_done() - assert len(mock_setup.mock_calls) == 0 assert len(mock_setup_entry.mock_calls) == 0 entries = hass.config_entries.async_entries(DOMAIN)