From dd150bb79795bcf7323276e268358b0243f887c3 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 4 Feb 2021 11:08:10 +0100 Subject: [PATCH] Allow manual configuration of ignored singleton config entries (#45161) Co-authored-by: Paulus Schoutsen --- homeassistant/config_entries.py | 18 ++++++++++----- tests/test_config_entries.py | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index abc6b2f46af..122b6f15e41 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -905,7 +905,7 @@ class ConfigFlow(data_entry_flow.FlowHandler): if self.unique_id is None: return - for entry in self._async_current_entries(): + for entry in self._async_current_entries(include_ignore=True): if entry.unique_id == self.unique_id: if updates is not None: changed = self.hass.config_entries.async_update_entry( @@ -949,17 +949,25 @@ class ConfigFlow(data_entry_flow.FlowHandler): if progress["context"].get("unique_id") == DEFAULT_DISCOVERY_UNIQUE_ID: self.hass.config_entries.flow.async_abort(progress["flow_id"]) - for entry in self._async_current_entries(): + for entry in self._async_current_entries(include_ignore=True): if entry.unique_id == unique_id: return entry return None @callback - def _async_current_entries(self) -> List[ConfigEntry]: - """Return current entries.""" + def _async_current_entries(self, include_ignore: bool = False) -> List[ConfigEntry]: + """Return current entries. + + If the flow is user initiated, filter out ignored entries unless include_ignore is True. + """ assert self.hass is not None - return self.hass.config_entries.async_entries(self.handler) + config_entries = self.hass.config_entries.async_entries(self.handler) + + if include_ignore or self.source != SOURCE_USER: + return config_entries + + return [entry for entry in config_entries if entry.source != SOURCE_IGNORE] @callback def _async_current_ids(self, include_ignore: bool = True) -> Set[Optional[str]]: diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index 24444f6a6c0..435f2a11cc2 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -1585,6 +1585,45 @@ async def test_manual_add_overrides_ignored_entry(hass, manager): assert len(async_reload.mock_calls) == 0 +async def test_manual_add_overrides_ignored_entry_singleton(hass, manager): + """Test that we can ignore manually add entry, overriding ignored entry.""" + hass.config.components.add("comp") + entry = MockConfigEntry( + domain="comp", + state=config_entries.ENTRY_STATE_LOADED, + source=config_entries.SOURCE_IGNORE, + ) + entry.add_to_hass(hass) + + mock_setup_entry = AsyncMock(return_value=True) + + mock_integration(hass, MockModule("comp", async_setup_entry=mock_setup_entry)) + mock_entity_platform(hass, "config_flow.comp", None) + + class TestFlow(config_entries.ConfigFlow): + """Test flow.""" + + VERSION = 1 + + async def async_step_user(self, user_input=None): + """Test user step.""" + if self._async_current_entries(): + return self.async_abort(reason="single_instance_allowed") + return self.async_create_entry(title="title", data={"token": "supersecret"}) + + with patch.dict(config_entries.HANDLERS, {"comp": TestFlow, "beer": 5}): + await manager.flow.async_init( + "comp", context={"source": config_entries.SOURCE_USER} + ) + await hass.async_block_till_done() + + assert len(mock_setup_entry.mock_calls) == 1 + p_hass, p_entry = mock_setup_entry.mock_calls[0][1] + + assert p_hass is hass + assert p_entry.data == {"token": "supersecret"} + + async def test_unignore_step_form(hass, manager): """Test that we can ignore flows that are in progress and have a unique ID, then rediscover them.""" async_setup_entry = AsyncMock(return_value=True)