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 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."""

View file

@ -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:

View file

@ -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"]}