diff --git a/homeassistant/components/accuweather/__init__.py b/homeassistant/components/accuweather/__init__.py index b2ec7e0224b..90b939ab3b9 100644 --- a/homeassistant/components/accuweather/__init__.py +++ b/homeassistant/components/accuweather/__init__.py @@ -8,7 +8,6 @@ from aiohttp.client_exceptions import ClientConnectorError from async_timeout import timeout from homeassistant.const import CONF_API_KEY -from homeassistant.core import Config, HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -26,12 +25,6 @@ _LOGGER = logging.getLogger(__name__) PLATFORMS = ["sensor", "weather"] -async def async_setup(hass: HomeAssistant, config: Config) -> bool: - """Set up configured AccuWeather.""" - hass.data.setdefault(DOMAIN, {}) - return True - - async def async_setup_entry(hass, config_entry) -> bool: """Set up AccuWeather as config entry.""" api_key = config_entry.data[CONF_API_KEY] @@ -52,7 +45,7 @@ async def async_setup_entry(hass, config_entry) -> bool: undo_listener = config_entry.add_update_listener(update_listener) - hass.data[DOMAIN][config_entry.entry_id] = { + hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = { COORDINATOR: coordinator, UNDO_UPDATE_LISTENER: undo_listener, } diff --git a/homeassistant/components/adguard/__init__.py b/homeassistant/components/adguard/__init__.py index 04d266e7d9b..0f10d20ec59 100644 --- a/homeassistant/components/adguard/__init__.py +++ b/homeassistant/components/adguard/__init__.py @@ -34,7 +34,6 @@ from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.entity import Entity -from homeassistant.helpers.typing import ConfigType _LOGGER = logging.getLogger(__name__) @@ -49,11 +48,6 @@ SERVICE_REFRESH_SCHEMA = vol.Schema( PLATFORMS = ["sensor", "switch"] -async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Set up the AdGuard Home components.""" - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up AdGuard Home from a config entry.""" session = async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL]) diff --git a/homeassistant/components/airnow/__init__.py b/homeassistant/components/airnow/__init__.py index 1732445c566..04e1567e067 100644 --- a/homeassistant/components/airnow/__init__.py +++ b/homeassistant/components/airnow/__init__.py @@ -38,11 +38,6 @@ _LOGGER = logging.getLogger(__name__) PLATFORMS = ["sensor"] -async def async_setup(hass: HomeAssistant, config: dict): - """Set up the AirNow component.""" - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up AirNow from a config entry.""" api_key = entry.data[CONF_API_KEY] diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 1b8c47d36a2..8b609fe3126 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -20,11 +20,6 @@ CONFIG_SCHEMA = vol.Schema( ) -async def async_setup(hass, config): - """Old way of setting up deCONZ integrations.""" - return True - - async def async_setup_entry(hass, config_entry): """Set up a deCONZ bridge for a config entry. diff --git a/homeassistant/components/elgato/__init__.py b/homeassistant/components/elgato/__init__.py index 4f7731c122d..22d60406780 100644 --- a/homeassistant/components/elgato/__init__.py +++ b/homeassistant/components/elgato/__init__.py @@ -9,16 +9,10 @@ from homeassistant.const import CONF_HOST, CONF_PORT from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.typing import ConfigType from .const import DATA_ELGATO_CLIENT, DOMAIN -async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Set up the Elgato Key Light components.""" - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Elgato Key Light from a config entry.""" session = async_get_clientsession(hass) diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 0cb6cd94e08..02d6309fe7f 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -42,7 +42,7 @@ from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers.service import async_set_service_schema from homeassistant.helpers.storage import Store from homeassistant.helpers.template import Template -from homeassistant.helpers.typing import ConfigType, HomeAssistantType +from homeassistant.helpers.typing import HomeAssistantType # Import config flow so that it's added to the registry from .entry_data import RuntimeEntryData @@ -56,11 +56,6 @@ STORAGE_VERSION = 1 CONFIG_SCHEMA = vol.Schema({}, extra=vol.ALLOW_EXTRA) -async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: - """Stub to allow setting up this component.""" - return True - - async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: """Set up the esphome component.""" hass.data.setdefault(DOMAIN, {}) diff --git a/homeassistant/components/tasmota/__init__.py b/homeassistant/components/tasmota/__init__.py index 0b42725cdcf..83baae9c19c 100644 --- a/homeassistant/components/tasmota/__init__.py +++ b/homeassistant/components/tasmota/__init__.py @@ -24,7 +24,6 @@ from homeassistant.helpers.device_registry import ( EVENT_DEVICE_REGISTRY_UPDATED, async_entries_for_config_entry, ) -from homeassistant.helpers.typing import HomeAssistantType from . import device_automation, discovery from .const import ( @@ -38,11 +37,6 @@ from .const import ( _LOGGER = logging.getLogger(__name__) -async def async_setup(hass: HomeAssistantType, config: dict): - """Set up the Tasmota component.""" - return True - - async def async_setup_entry(hass, entry): """Set up Tasmota from a config entry.""" websocket_api.async_register_command(hass, websocket_remove_device) diff --git a/homeassistant/components/wled/__init__.py b/homeassistant/components/wled/__init__.py index 2ec02931415..069c12a2d06 100644 --- a/homeassistant/components/wled/__init__.py +++ b/homeassistant/components/wled/__init__.py @@ -16,7 +16,6 @@ from homeassistant.const import ATTR_NAME, CONF_HOST from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, @@ -37,11 +36,6 @@ PLATFORMS = (LIGHT_DOMAIN, SENSOR_DOMAIN, SWITCH_DOMAIN) _LOGGER = logging.getLogger(__name__) -async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Set up the WLED components.""" - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up WLED from a config entry.""" diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 288f9d0847b..6b306995dfc 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -169,7 +169,7 @@ async def _async_setup_component( return False if integration.disabled: - log_error(f"dependency is disabled - {integration.disabled}") + log_error(f"Dependency is disabled - {integration.disabled}") return False # Validate all dependencies exist and there are no circular dependencies @@ -219,6 +219,8 @@ async def _async_setup_component( SLOW_SETUP_WARNING, ) + task = None + result = True try: if hasattr(component, "async_setup"): task = component.async_setup(hass, processed_config) # type: ignore @@ -228,13 +230,14 @@ async def _async_setup_component( task = hass.loop.run_in_executor( None, component.setup, hass, processed_config # type: ignore ) - else: - log_error("No setup function defined.") + elif not hasattr(component, "async_setup_entry"): + log_error("No setup or config entry setup function defined.") hass.data[DATA_SETUP_STARTED].pop(domain) return False - async with hass.timeout.async_timeout(SLOW_SETUP_MAX_WAIT, domain): - result = await task + if task: + async with hass.timeout.async_timeout(SLOW_SETUP_MAX_WAIT, domain): + result = await task except asyncio.TimeoutError: _LOGGER.error( "Setup of %s is taking longer than %s seconds." diff --git a/script/scaffold/templates/config_flow/integration/__init__.py b/script/scaffold/templates/config_flow/integration/__init__.py index 24a0c1d7350..6c187d1dafe 100644 --- a/script/scaffold/templates/config_flow/integration/__init__.py +++ b/script/scaffold/templates/config_flow/integration/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations import asyncio -from typing import Any from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -14,11 +13,6 @@ from .const import DOMAIN PLATFORMS = ["light"] -async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool: - """Set up the NEW_NAME component.""" - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up NEW_NAME from a config entry.""" # TODO Store an API object for your platforms to access diff --git a/script/scaffold/templates/config_flow/tests/test_config_flow.py b/script/scaffold/templates/config_flow/tests/test_config_flow.py index 8205fdbeda4..674cb921cdd 100644 --- a/script/scaffold/templates/config_flow/tests/test_config_flow.py +++ b/script/scaffold/templates/config_flow/tests/test_config_flow.py @@ -20,8 +20,6 @@ async def test_form(hass: HomeAssistant) -> None: "homeassistant.components.NEW_DOMAIN.config_flow.PlaceholderHub.authenticate", return_value=True, ), patch( - "homeassistant.components.NEW_DOMAIN.async_setup", return_value=True - ) as mock_setup, patch( "homeassistant.components.NEW_DOMAIN.async_setup_entry", return_value=True, ) as mock_setup_entry: @@ -42,7 +40,6 @@ async def test_form(hass: HomeAssistant) -> None: "username": "test-username", "password": "test-password", } - assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/script/scaffold/templates/config_flow_discovery/integration/__init__.py b/script/scaffold/templates/config_flow_discovery/integration/__init__.py index 24a0c1d7350..6c187d1dafe 100644 --- a/script/scaffold/templates/config_flow_discovery/integration/__init__.py +++ b/script/scaffold/templates/config_flow_discovery/integration/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations import asyncio -from typing import Any from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -14,11 +13,6 @@ from .const import DOMAIN PLATFORMS = ["light"] -async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool: - """Set up the NEW_NAME component.""" - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up NEW_NAME from a config entry.""" # TODO Store an API object for your platforms to access diff --git a/tests/common.py b/tests/common.py index 984b35716f0..32d2742f4d8 100644 --- a/tests/common.py +++ b/tests/common.py @@ -566,7 +566,7 @@ class MockModule: if platform_schema_base is not None: self.PLATFORM_SCHEMA_BASE = platform_schema_base - if setup is not None: + if setup: # We run this in executor, wrap it in function self.setup = lambda *args: setup(*args) diff --git a/tests/components/airnow/test_config_flow.py b/tests/components/airnow/test_config_flow.py index f7533b7f5ac..9937e899643 100644 --- a/tests/components/airnow/test_config_flow.py +++ b/tests/components/airnow/test_config_flow.py @@ -75,9 +75,7 @@ async def test_form(hass): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {} - with patch("pyairnow.WebServiceAPI._get", return_value=MOCK_RESPONSE,), patch( - "homeassistant.components.airnow.async_setup", return_value=True - ) as mock_setup, patch( + with patch("pyairnow.WebServiceAPI._get", return_value=MOCK_RESPONSE), patch( "homeassistant.components.airnow.async_setup_entry", return_value=True, ) as mock_setup_entry: @@ -90,7 +88,6 @@ async def test_form(hass): assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["data"] == CONFIG - assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index 8f9a597e00c..4380b8c6021 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -539,8 +539,6 @@ async def test_flow_hassio_discovery(hass): assert result["description_placeholders"] == {"addon": "Mock Addon"} with patch( - "homeassistant.components.deconz.async_setup", return_value=True - ) as mock_setup, patch( "homeassistant.components.deconz.async_setup_entry", return_value=True, ) as mock_setup_entry: @@ -555,7 +553,6 @@ async def test_flow_hassio_discovery(hass): CONF_PORT: 80, CONF_API_KEY: API_KEY, } - assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/test_setup.py b/tests/test_setup.py index c2cbc3d6ea8..9b68dbf4eab 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -3,7 +3,7 @@ import asyncio import os import threading -from unittest.mock import Mock, patch +from unittest.mock import AsyncMock, Mock, patch import pytest import voluptuous as vol @@ -618,3 +618,29 @@ async def test_async_get_loaded_integrations(hass): "myintegration", "device_tracker", } + + +async def test_integration_no_setup(hass, caplog): + """Test we fail integration setup without setup functions.""" + mock_integration( + hass, + MockModule("test_integration_without_setup", setup=False), + ) + result = await setup.async_setup_component( + hass, "test_integration_without_setup", {} + ) + assert not result + assert "No setup or config entry setup function defined" in caplog.text + + +async def test_integration_only_setup_entry(hass): + """Test we have an integration with only a setup entry method.""" + mock_integration( + hass, + MockModule( + "test_integration_only_entry", + setup=False, + async_setup_entry=AsyncMock(return_value=True), + ), + ) + assert await setup.async_setup_component(hass, "test_integration_only_entry", {})