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:
epenet 2022-11-24 12:18:09 +01:00 committed by GitHub
parent 7f90fb1cd1
commit 4c38a5d773
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 6 deletions

View file

@ -5,6 +5,7 @@ import asyncio
from collections import ChainMap
from collections.abc import Callable, Coroutine, Generator, Iterable, Mapping
from contextvars import ContextVar
from copy import deepcopy
from enum import Enum
import functools
import logging
@ -1672,11 +1673,20 @@ class OptionsFlowManager(data_entry_flow.FlowManager):
class OptionsFlow(data_entry_flow.FlowHandler):
"""Base class for config option flows."""
"""Base class for config options flows."""
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:
"""Handler to handle when entities related to config entries updating disabled_by."""

View file

@ -75,12 +75,12 @@ class SchemaCommonFlowHandler:
self,
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
flow: dict[str, SchemaFlowFormStep | SchemaFlowMenuStep],
config_entry: config_entries.ConfigEntry | None,
options: dict[str, Any] | None,
) -> None:
"""Initialize a common handler."""
self._flow = flow
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(
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."""
def __init__(
@ -310,8 +310,10 @@ class SchemaOptionsFlowHandler(config_entries.OptionsFlow):
async_options_flow_finished: Callable[[HomeAssistant, Mapping[str, Any]], None],
) -> None:
"""Initialize options flow."""
self._common_handler = SchemaCommonFlowHandler(self, options_flow, config_entry)
self.config_entry = config_entry
super().__init__(config_entry)
self._common_handler = SchemaCommonFlowHandler(
self, options_flow, self._options
)
self._async_options_flow_finished = async_options_flow_finished
for step in options_flow:

View file

@ -3426,3 +3426,23 @@ async def test_async_wait_component_startup(hass: HomeAssistant):
# The component has been loaded
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"]}