From 0bf95df4d6e40364b8130b9248abeb3f579fa70f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 17 Feb 2024 03:34:03 -0600 Subject: [PATCH] Avoid creating tasks to setup ignored and disabled config entries (#110756) * Avoid creating tasks to setup ignored and disabled config entries * lint --- .../components/config/config_entries.py | 6 +- homeassistant/config_entries.py | 22 +++++- homeassistant/setup.py | 17 +++-- tests/test_config_entries.py | 75 +++++++++++++++++++ 4 files changed, 107 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/config/config_entries.py b/homeassistant/components/config/config_entries.py index 36a26311bce..4004078be5f 100644 --- a/homeassistant/components/config/config_entries.py +++ b/homeassistant/components/config/config_entries.py @@ -515,10 +515,10 @@ async def async_matching_config_entries( hass: HomeAssistant, type_filter: list[str] | None, domain: str | None ) -> list[dict[str, Any]]: """Return matching config entries by type and/or domain.""" - kwargs = {} if domain: - kwargs["domain"] = domain - entries = hass.config_entries.async_entries(**kwargs) + entries = hass.config_entries.async_entries(domain) + else: + entries = hass.config_entries.async_entries() if not type_filter: return [entry_json(entry) for entry in entries] diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index cc5a5a1c273..a6a9a35032f 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -1314,11 +1314,27 @@ class ConfigEntries: return self._entries.data.get(entry_id) @callback - def async_entries(self, domain: str | None = None) -> list[ConfigEntry]: + def async_entries( + self, + domain: str | None = None, + include_ignore: bool = True, + include_disabled: bool = True, + ) -> list[ConfigEntry]: """Return all entries or entries for a specific domain.""" if domain is None: - return list(self._entries.values()) - return list(self._entries.get_entries_for_domain(domain)) + entries: Iterable[ConfigEntry] = self._entries.values() + else: + entries = self._entries.get_entries_for_domain(domain) + + if include_ignore and include_disabled: + return list(entries) + + return [ + entry + for entry in entries + if (include_ignore or entry.source != SOURCE_IGNORE) + and (include_disabled or not entry.disabled_by) + ] @callback def async_entry_for_domain_unique_id( diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 99e0a3e2c4b..0cd4d3ea103 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -370,15 +370,18 @@ async def _async_setup_component( # call to avoid a deadlock when forwarding platforms hass.config.components.add(domain) - await asyncio.gather( - *( - asyncio.create_task( - entry.async_setup(hass, integration=integration), - name=f"config entry setup {entry.title} {entry.domain} {entry.entry_id}", + if entries := hass.config_entries.async_entries( + domain, include_ignore=False, include_disabled=False + ): + await asyncio.gather( + *( + asyncio.create_task( + entry.async_setup(hass, integration=integration), + name=f"config entry setup {entry.title} {entry.domain} {entry.entry_id}", + ) + for entry in entries ) - for entry in hass.config_entries.async_entries(domain) ) - ) # Cleanup if domain in hass.data[DATA_SETUP]: diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index a3da4ac8928..c5eb8d18efe 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -662,6 +662,81 @@ async def test_domains_gets_domains_excludes_ignore_and_disabled( ] +async def test_entries_excludes_ignore_and_disabled( + manager: config_entries.ConfigEntries, +) -> None: + """Test ignored and disabled entries are returned by default.""" + entry = MockConfigEntry(domain="test") + entry.add_to_manager(manager) + entry2a = MockConfigEntry(domain="test2") + entry2a.add_to_manager(manager) + entry2b = MockConfigEntry(domain="test2") + entry2b.add_to_manager(manager) + entry_ignored = MockConfigEntry( + domain="ignored", source=config_entries.SOURCE_IGNORE + ) + entry_ignored.add_to_manager(manager) + entry3 = MockConfigEntry(domain="test3") + entry3.add_to_manager(manager) + disabled_entry = MockConfigEntry( + domain="disabled", disabled_by=config_entries.ConfigEntryDisabler.USER + ) + disabled_entry.add_to_manager(manager) + assert manager.async_entries() == [ + entry, + entry2a, + entry2b, + entry_ignored, + entry3, + disabled_entry, + ] + assert manager.async_entries(include_ignore=False) == [ + entry, + entry2a, + entry2b, + entry3, + disabled_entry, + ] + assert manager.async_entries(include_disabled=False) == [ + entry, + entry2a, + entry2b, + entry_ignored, + entry3, + ] + assert manager.async_entries(include_ignore=False, include_disabled=False) == [ + entry, + entry2a, + entry2b, + entry3, + ] + + assert manager.async_entries(include_ignore=True) == [ + entry, + entry2a, + entry2b, + entry_ignored, + entry3, + disabled_entry, + ] + assert manager.async_entries(include_disabled=True) == [ + entry, + entry2a, + entry2b, + entry_ignored, + entry3, + disabled_entry, + ] + assert manager.async_entries(include_ignore=True, include_disabled=True) == [ + entry, + entry2a, + entry2b, + entry_ignored, + entry3, + disabled_entry, + ] + + async def test_saving_and_loading(hass: HomeAssistant) -> None: """Test that we're saving and loading correctly.""" mock_integration(