Add OptionsFlow helper class (#82531)
* Add OptionsFlow helper classes * More integrations * Adjust SchemaOptionsFlowHandler * Use single class * Simplify access to options * Reduce PR * Make _options private * Add test
This commit is contained in:
parent
7f90fb1cd1
commit
4c38a5d773
3 changed files with 38 additions and 6 deletions
|
@ -5,6 +5,7 @@ import asyncio
|
||||||
from collections import ChainMap
|
from collections import ChainMap
|
||||||
from collections.abc import Callable, Coroutine, Generator, Iterable, Mapping
|
from collections.abc import Callable, Coroutine, Generator, Iterable, Mapping
|
||||||
from contextvars import ContextVar
|
from contextvars import ContextVar
|
||||||
|
from copy import deepcopy
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
|
@ -1672,11 +1673,20 @@ class OptionsFlowManager(data_entry_flow.FlowManager):
|
||||||
|
|
||||||
|
|
||||||
class OptionsFlow(data_entry_flow.FlowHandler):
|
class OptionsFlow(data_entry_flow.FlowHandler):
|
||||||
"""Base class for config option flows."""
|
"""Base class for config options flows."""
|
||||||
|
|
||||||
handler: str
|
handler: str
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsFlowWithConfigEntry(OptionsFlow):
|
||||||
|
"""Base class for options flows with config entry and options."""
|
||||||
|
|
||||||
|
def __init__(self, config_entry: ConfigEntry) -> None:
|
||||||
|
"""Initialize options flow."""
|
||||||
|
self.config_entry = config_entry
|
||||||
|
self._options = deepcopy(dict(config_entry.options))
|
||||||
|
|
||||||
|
|
||||||
class EntityRegistryDisabledHandler:
|
class EntityRegistryDisabledHandler:
|
||||||
"""Handler to handle when entities related to config entries updating disabled_by."""
|
"""Handler to handle when entities related to config entries updating disabled_by."""
|
||||||
|
|
||||||
|
|
|
@ -75,12 +75,12 @@ class SchemaCommonFlowHandler:
|
||||||
self,
|
self,
|
||||||
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
|
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
|
||||||
flow: dict[str, SchemaFlowFormStep | SchemaFlowMenuStep],
|
flow: dict[str, SchemaFlowFormStep | SchemaFlowMenuStep],
|
||||||
config_entry: config_entries.ConfigEntry | None,
|
options: dict[str, Any] | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a common handler."""
|
"""Initialize a common handler."""
|
||||||
self._flow = flow
|
self._flow = flow
|
||||||
self._handler = handler
|
self._handler = handler
|
||||||
self._options = dict(config_entry.options) if config_entry is not None else {}
|
self._options = options if options is not None else {}
|
||||||
|
|
||||||
async def async_step(
|
async def async_step(
|
||||||
self, step_id: str, user_input: dict[str, Any] | None = None
|
self, step_id: str, user_input: dict[str, Any] | None = None
|
||||||
|
@ -300,7 +300,7 @@ class SchemaConfigFlowHandler(config_entries.ConfigFlow):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SchemaOptionsFlowHandler(config_entries.OptionsFlow):
|
class SchemaOptionsFlowHandler(config_entries.OptionsFlowWithConfigEntry):
|
||||||
"""Handle a schema based options flow."""
|
"""Handle a schema based options flow."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -310,8 +310,10 @@ class SchemaOptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
async_options_flow_finished: Callable[[HomeAssistant, Mapping[str, Any]], None],
|
async_options_flow_finished: Callable[[HomeAssistant, Mapping[str, Any]], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize options flow."""
|
"""Initialize options flow."""
|
||||||
self._common_handler = SchemaCommonFlowHandler(self, options_flow, config_entry)
|
super().__init__(config_entry)
|
||||||
self.config_entry = config_entry
|
self._common_handler = SchemaCommonFlowHandler(
|
||||||
|
self, options_flow, self._options
|
||||||
|
)
|
||||||
self._async_options_flow_finished = async_options_flow_finished
|
self._async_options_flow_finished = async_options_flow_finished
|
||||||
|
|
||||||
for step in options_flow:
|
for step in options_flow:
|
||||||
|
|
|
@ -3426,3 +3426,23 @@ async def test_async_wait_component_startup(hass: HomeAssistant):
|
||||||
|
|
||||||
# The component has been loaded
|
# The component has been loaded
|
||||||
assert "test" in hass.config.components
|
assert "test" in hass.config.components
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options_flow_options_not_mutated() -> None:
|
||||||
|
"""Test that OptionsFlowWithConfigEntry doesn't mutate entry options."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain="test",
|
||||||
|
data={"first": True},
|
||||||
|
options={"sub_dict": {"1": "one"}, "sub_list": ["one"]},
|
||||||
|
)
|
||||||
|
|
||||||
|
options_flow = config_entries.OptionsFlowWithConfigEntry(entry)
|
||||||
|
|
||||||
|
options_flow._options["sub_dict"]["2"] = "two"
|
||||||
|
options_flow._options["sub_list"].append("two")
|
||||||
|
|
||||||
|
assert options_flow._options == {
|
||||||
|
"sub_dict": {"1": "one", "2": "two"},
|
||||||
|
"sub_list": ["one", "two"],
|
||||||
|
}
|
||||||
|
assert entry.options == {"sub_dict": {"1": "one"}, "sub_list": ["one"]}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue