Add config_flow helper to get reauth/reconfigure config entry (#127115)
* Add config_flow helper to get config entry from context * Simplify * Apply to aussie_broadband * Another example * Rename and adjust docstring * Simplify * Add test * Refactor to hide context * Raise * Improve coverage * Use AttributeError * Use ValueError * Raise UnknownEntrypull/127279/head
parent
201b8d9ebf
commit
21266e1c68
|
@ -99,10 +99,7 @@ class AussieBroadbandConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
}
|
}
|
||||||
|
|
||||||
if not (errors := await self.async_auth(data)):
|
if not (errors := await self.async_auth(data)):
|
||||||
entry = self.hass.config_entries.async_get_entry(
|
entry = self._get_reauth_entry()
|
||||||
self.context["entry_id"]
|
|
||||||
)
|
|
||||||
assert entry
|
|
||||||
return self.async_update_reload_and_abort(entry, data=data)
|
return self.async_update_reload_and_abort(entry, data=data)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
|
|
|
@ -75,10 +75,7 @@ class BryantConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
system_zone = await _enumerate_sz(user_input[CONF_FILENAME])
|
system_zone = await _enumerate_sz(user_input[CONF_FILENAME])
|
||||||
if len(system_zone) != 0:
|
if len(system_zone) != 0:
|
||||||
our_entry = self.hass.config_entries.async_get_entry(
|
our_entry = self._get_reconfigure_entry()
|
||||||
self.context["entry_id"]
|
|
||||||
)
|
|
||||||
assert our_entry is not None, "Could not find own entry"
|
|
||||||
return self.async_update_reload_and_abort(
|
return self.async_update_reload_and_abort(
|
||||||
entry=our_entry,
|
entry=our_entry,
|
||||||
data={
|
data={
|
||||||
|
|
|
@ -2726,6 +2726,36 @@ class ConfigFlow(ConfigEntryBaseFlow):
|
||||||
"""Return True if other_flow is matching this flow."""
|
"""Return True if other_flow is matching this flow."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _reauth_entry_id(self) -> str:
|
||||||
|
"""Return reauth entry id."""
|
||||||
|
if self.source != SOURCE_REAUTH:
|
||||||
|
raise ValueError(f"Source is {self.source}, expected {SOURCE_REAUTH}")
|
||||||
|
return self.context["entry_id"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _get_reauth_entry(self) -> ConfigEntry:
|
||||||
|
"""Return the reauth config entry linked to the current context."""
|
||||||
|
if entry := self.hass.config_entries.async_get_entry(self._reauth_entry_id):
|
||||||
|
return entry
|
||||||
|
raise UnknownEntry
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _reconfigure_entry_id(self) -> str:
|
||||||
|
"""Return reconfigure entry id."""
|
||||||
|
if self.source != SOURCE_RECONFIGURE:
|
||||||
|
raise ValueError(f"Source is {self.source}, expected {SOURCE_RECONFIGURE}")
|
||||||
|
return self.context["entry_id"] # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _get_reconfigure_entry(self) -> ConfigEntry:
|
||||||
|
"""Return the reconfigure config entry linked to the current context."""
|
||||||
|
if entry := self.hass.config_entries.async_get_entry(
|
||||||
|
self._reconfigure_entry_id
|
||||||
|
):
|
||||||
|
return entry
|
||||||
|
raise UnknownEntry
|
||||||
|
|
||||||
|
|
||||||
class OptionsFlowManager(data_entry_flow.FlowManager[ConfigFlowResult]):
|
class OptionsFlowManager(data_entry_flow.FlowManager[ConfigFlowResult]):
|
||||||
"""Flow to set options for a configuration entry."""
|
"""Flow to set options for a configuration entry."""
|
||||||
|
|
|
@ -6383,6 +6383,152 @@ async def test_async_has_matching_flow_not_implemented(
|
||||||
manager.flow.async_has_matching_flow(flow)
|
manager.flow.async_has_matching_flow(flow)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_reauth_entry(
|
||||||
|
hass: HomeAssistant, manager: config_entries.ConfigEntries
|
||||||
|
) -> None:
|
||||||
|
"""Test _get_context_entry behavior."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
title="test_title",
|
||||||
|
domain="test",
|
||||||
|
entry_id="01J915Q6T9F6G5V0QJX6HBC94T",
|
||||||
|
data={"host": "any", "port": 123},
|
||||||
|
unique_id=None,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
mock_integration(hass, MockModule("test"))
|
||||||
|
mock_platform(hass, "test.config_flow", None)
|
||||||
|
|
||||||
|
class TestFlow(config_entries.ConfigFlow):
|
||||||
|
VERSION = 1
|
||||||
|
|
||||||
|
async def async_step_user(self, user_input=None):
|
||||||
|
"""Test user step."""
|
||||||
|
return await self._async_step_confirm()
|
||||||
|
|
||||||
|
async def async_step_reauth(self, entry_data):
|
||||||
|
"""Test reauth step."""
|
||||||
|
return await self._async_step_confirm()
|
||||||
|
|
||||||
|
async def async_step_reconfigure(self, entry_data):
|
||||||
|
"""Test reauth step."""
|
||||||
|
return await self._async_step_confirm()
|
||||||
|
|
||||||
|
async def _async_step_confirm(self):
|
||||||
|
"""Confirm input."""
|
||||||
|
try:
|
||||||
|
entry = self._get_reauth_entry()
|
||||||
|
except ValueError as err:
|
||||||
|
reason = str(err)
|
||||||
|
except config_entries.UnknownEntry:
|
||||||
|
reason = "Entry not found"
|
||||||
|
else:
|
||||||
|
reason = f"Found entry {entry.title}"
|
||||||
|
try:
|
||||||
|
entry_id = self._reauth_entry_id
|
||||||
|
except ValueError:
|
||||||
|
reason = f"{reason}: -"
|
||||||
|
else:
|
||||||
|
reason = f"{reason}: {entry_id}"
|
||||||
|
return self.async_abort(reason=reason)
|
||||||
|
|
||||||
|
# A reauth flow finds the config entry from context
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await entry.start_reauth_flow(hass)
|
||||||
|
assert result["reason"] == "Found entry test_title: 01J915Q6T9F6G5V0QJX6HBC94T"
|
||||||
|
|
||||||
|
# The config entry is removed before the reauth flow is aborted
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await entry.start_reauth_flow(hass, context={"entry_id": "01JRemoved"})
|
||||||
|
assert result["reason"] == "Entry not found: 01JRemoved"
|
||||||
|
|
||||||
|
# A reconfigure flow does not have access to the config entry
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await entry.start_reconfigure_flow(hass)
|
||||||
|
assert result["reason"] == "Source is reconfigure, expected reauth: -"
|
||||||
|
|
||||||
|
# A user flow does not have access to the config entry
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await manager.flow.async_init(
|
||||||
|
"test", context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["reason"] == "Source is user, expected reauth: -"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_reconfigure_entry(
|
||||||
|
hass: HomeAssistant, manager: config_entries.ConfigEntries
|
||||||
|
) -> None:
|
||||||
|
"""Test _get_context_entry behavior."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
title="test_title",
|
||||||
|
domain="test",
|
||||||
|
entry_id="01J915Q6T9F6G5V0QJX6HBC94T",
|
||||||
|
data={"host": "any", "port": 123},
|
||||||
|
unique_id=None,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
mock_integration(hass, MockModule("test"))
|
||||||
|
mock_platform(hass, "test.config_flow", None)
|
||||||
|
|
||||||
|
class TestFlow(config_entries.ConfigFlow):
|
||||||
|
VERSION = 1
|
||||||
|
|
||||||
|
async def async_step_user(self, user_input=None):
|
||||||
|
"""Test user step."""
|
||||||
|
return await self._async_step_confirm()
|
||||||
|
|
||||||
|
async def async_step_reauth(self, entry_data):
|
||||||
|
"""Test reauth step."""
|
||||||
|
return await self._async_step_confirm()
|
||||||
|
|
||||||
|
async def async_step_reconfigure(self, entry_data):
|
||||||
|
"""Test reauth step."""
|
||||||
|
return await self._async_step_confirm()
|
||||||
|
|
||||||
|
async def _async_step_confirm(self):
|
||||||
|
"""Confirm input."""
|
||||||
|
try:
|
||||||
|
entry = self._get_reconfigure_entry()
|
||||||
|
except ValueError as err:
|
||||||
|
reason = str(err)
|
||||||
|
except config_entries.UnknownEntry:
|
||||||
|
reason = "Entry not found"
|
||||||
|
else:
|
||||||
|
reason = f"Found entry {entry.title}"
|
||||||
|
try:
|
||||||
|
entry_id = self._reconfigure_entry_id
|
||||||
|
except ValueError:
|
||||||
|
reason = f"{reason}: -"
|
||||||
|
else:
|
||||||
|
reason = f"{reason}: {entry_id}"
|
||||||
|
return self.async_abort(reason=reason)
|
||||||
|
|
||||||
|
# A reauth flow does not have access to the config entry from context
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await entry.start_reauth_flow(hass)
|
||||||
|
assert result["reason"] == "Source is reauth, expected reconfigure: -"
|
||||||
|
|
||||||
|
# A reconfigure flow finds the config entry
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await entry.start_reconfigure_flow(hass)
|
||||||
|
assert result["reason"] == "Found entry test_title: 01J915Q6T9F6G5V0QJX6HBC94T"
|
||||||
|
|
||||||
|
# A reconfigure flow finds the config entry
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await entry.start_reconfigure_flow(
|
||||||
|
hass, context={"entry_id": "01JRemoved"}
|
||||||
|
)
|
||||||
|
assert result["reason"] == "Entry not found: 01JRemoved"
|
||||||
|
|
||||||
|
# A user flow does not have access to the config entry
|
||||||
|
with mock_config_flow("test", TestFlow):
|
||||||
|
result = await manager.flow.async_init(
|
||||||
|
"test", context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["reason"] == "Source is user, expected reconfigure: -"
|
||||||
|
|
||||||
|
|
||||||
async def test_reauth_helper_alignment(
|
async def test_reauth_helper_alignment(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
manager: config_entries.ConfigEntries,
|
manager: config_entries.ConfigEntries,
|
||||||
|
|
Loading…
Reference in New Issue