1
mirror of https://github.com/home-assistant/core synced 2024-09-28 03:04:04 +02:00

Add FlowResultType enum to data entry flow (#72955)

This commit is contained in:
epenet 2022-06-08 07:02:44 +02:00 committed by GitHub
parent 329595bf73
commit f91aa33c5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 79 additions and 53 deletions

View File

@ -103,7 +103,7 @@ class AuthManagerFlowManager(data_entry_flow.FlowManager):
"""Return a user as result of login flow."""
flow = cast(LoginFlow, flow)
if result["type"] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY:
return result
# we got final result

View File

@ -64,7 +64,7 @@ class AlmondFlowHandler(
"""Handle authorize step."""
result = await super().async_step_auth(user_input)
if result["type"] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP:
if result["type"] == data_entry_flow.FlowResultType.EXTERNAL_STEP:
self.host = str(URL(result["url"]).with_path("me"))
return result

View File

@ -52,7 +52,7 @@ flow for details.
Progress the flow. Most flows will be 1 page, but could optionally add extra
login challenges, like TFA. Once the flow has finished, the returned step will
have type RESULT_TYPE_CREATE_ENTRY and "result" key will contain an authorization code.
have type FlowResultType.CREATE_ENTRY and "result" key will contain an authorization code.
The authorization code associated with an authorized user by default, it will
associate with an credential if "type" set to "link_user" in
"/auth/login_flow"
@ -123,13 +123,13 @@ class AuthProvidersView(HomeAssistantView):
def _prepare_result_json(result):
"""Convert result to JSON."""
if result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY:
data = result.copy()
data.pop("result")
data.pop("data")
return data
if result["type"] != data_entry_flow.RESULT_TYPE_FORM:
if result["type"] != data_entry_flow.FlowResultType.FORM:
return result
data = result.copy()
@ -154,11 +154,11 @@ class LoginFlowBaseView(HomeAssistantView):
async def _async_flow_result_to_response(self, request, client_id, result):
"""Convert the flow result to a response."""
if result["type"] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY:
# @log_invalid_auth does not work here since it returns HTTP 200.
# We need to manually log failed login attempts.
if (
result["type"] == data_entry_flow.RESULT_TYPE_FORM
result["type"] == data_entry_flow.FlowResultType.FORM
and (errors := result.get("errors"))
and errors.get("base")
in (

View File

@ -129,11 +129,11 @@ def websocket_depose_mfa(
def _prepare_result_json(result):
"""Convert result to JSON."""
if result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY:
data = result.copy()
return data
if result["type"] != data_entry_flow.RESULT_TYPE_FORM:
if result["type"] != data_entry_flow.FlowResultType.FORM:
return result
data = result.copy()

View File

@ -143,7 +143,7 @@ class ConfigManagerEntryResourceReloadView(HomeAssistantView):
def _prepare_config_flow_result_json(result, prepare_result_json):
"""Convert result to JSON."""
if result["type"] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY:
return prepare_result_json(result)
data = result.copy()

View File

@ -11,7 +11,7 @@ import time
from homeassistant.const import CONF_DEVICE, CONF_PLATFORM
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT
from homeassistant.data_entry_flow import FlowResultType
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
@ -305,7 +305,7 @@ async def async_start( # noqa: C901
)
if (
result
and result["type"] == RESULT_TYPE_ABORT
and result["type"] == FlowResultType.ABORT
and result["reason"]
in ("already_configured", "single_instance_allowed")
):

View File

@ -682,7 +682,7 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager):
if not self._async_has_other_discovery_flows(flow.flow_id):
persistent_notification.async_dismiss(self.hass, DISCOVERY_NOTIFICATION_ID)
if result["type"] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY:
return result
# Check if config entry exists with unique ID. Unload it.
@ -1534,7 +1534,7 @@ class OptionsFlowManager(data_entry_flow.FlowManager):
"""
flow = cast(OptionsFlow, flow)
if result["type"] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY:
return result
entry = self.hass.config_entries.async_get_entry(flow.handler)

View File

@ -10,10 +10,27 @@ from typing import Any, TypedDict
import voluptuous as vol
from .backports.enum import StrEnum
from .core import HomeAssistant, callback
from .exceptions import HomeAssistantError
from .helpers.frame import report
from .util import uuid as uuid_util
class FlowResultType(StrEnum):
"""Result type for a data entry flow."""
FORM = "form"
CREATE_ENTRY = "create_entry"
ABORT = "abort"
EXTERNAL_STEP = "external"
EXTERNAL_STEP_DONE = "external_done"
SHOW_PROGRESS = "progress"
SHOW_PROGRESS_DONE = "progress_done"
MENU = "menu"
# RESULT_TYPE_* is deprecated, to be removed in 2022.9
RESULT_TYPE_FORM = "form"
RESULT_TYPE_CREATE_ENTRY = "create_entry"
RESULT_TYPE_ABORT = "abort"
@ -64,7 +81,7 @@ class FlowResult(TypedDict, total=False):
"""Typed result dict."""
version: int
type: str
type: FlowResultType
flow_id: str
handler: str
title: str
@ -207,7 +224,7 @@ class FlowManager(abc.ABC):
self._initialize_tasks[handler].remove(task)
self._initializing[handler].remove(init_done)
if result["type"] != RESULT_TYPE_ABORT:
if result["type"] != FlowResultType.ABORT:
await self.async_post_init(flow, result)
return result
@ -252,7 +269,7 @@ class FlowManager(abc.ABC):
user_input = cur_step["data_schema"](user_input)
# Handle a menu navigation choice
if cur_step["type"] == RESULT_TYPE_MENU and user_input:
if cur_step["type"] == FlowResultType.MENU and user_input:
result = await self._async_handle_step(
flow, user_input["next_step_id"], None
)
@ -261,18 +278,25 @@ class FlowManager(abc.ABC):
flow, cur_step["step_id"], user_input
)
if cur_step["type"] in (RESULT_TYPE_EXTERNAL_STEP, RESULT_TYPE_SHOW_PROGRESS):
if cur_step["type"] == RESULT_TYPE_EXTERNAL_STEP and result["type"] not in (
RESULT_TYPE_EXTERNAL_STEP,
RESULT_TYPE_EXTERNAL_STEP_DONE,
if cur_step["type"] in (
FlowResultType.EXTERNAL_STEP,
FlowResultType.SHOW_PROGRESS,
):
if cur_step["type"] == FlowResultType.EXTERNAL_STEP and result[
"type"
] not in (
FlowResultType.EXTERNAL_STEP,
FlowResultType.EXTERNAL_STEP_DONE,
):
raise ValueError(
"External step can only transition to "
"external step or external step done."
)
if cur_step["type"] == RESULT_TYPE_SHOW_PROGRESS and result["type"] not in (
RESULT_TYPE_SHOW_PROGRESS,
RESULT_TYPE_SHOW_PROGRESS_DONE,
if cur_step["type"] == FlowResultType.SHOW_PROGRESS and result[
"type"
] not in (
FlowResultType.SHOW_PROGRESS,
FlowResultType.SHOW_PROGRESS_DONE,
):
raise ValueError(
"Show progress can only transition to show progress or show progress done."
@ -282,7 +306,7 @@ class FlowManager(abc.ABC):
# the frontend.
if (
cur_step["step_id"] != result.get("step_id")
or result["type"] == RESULT_TYPE_SHOW_PROGRESS
or result["type"] == FlowResultType.SHOW_PROGRESS
):
# Tell frontend to reload the flow state.
self.hass.bus.async_fire(
@ -345,25 +369,21 @@ class FlowManager(abc.ABC):
if step_done:
step_done.set_result(None)
if result["type"] not in (
RESULT_TYPE_FORM,
RESULT_TYPE_EXTERNAL_STEP,
RESULT_TYPE_CREATE_ENTRY,
RESULT_TYPE_ABORT,
RESULT_TYPE_EXTERNAL_STEP_DONE,
RESULT_TYPE_SHOW_PROGRESS,
RESULT_TYPE_SHOW_PROGRESS_DONE,
RESULT_TYPE_MENU,
):
raise ValueError(f"Handler returned incorrect type: {result['type']}")
if not isinstance(result["type"], FlowResultType):
result["type"] = FlowResultType(result["type"]) # type: ignore[unreachable]
report(
"does not use FlowResultType enum for data entry flow result type. "
"This is deprecated and will stop working in Home Assistant 2022.9",
error_if_core=False,
)
if result["type"] in (
RESULT_TYPE_FORM,
RESULT_TYPE_EXTERNAL_STEP,
RESULT_TYPE_EXTERNAL_STEP_DONE,
RESULT_TYPE_SHOW_PROGRESS,
RESULT_TYPE_SHOW_PROGRESS_DONE,
RESULT_TYPE_MENU,
FlowResultType.FORM,
FlowResultType.EXTERNAL_STEP,
FlowResultType.EXTERNAL_STEP_DONE,
FlowResultType.SHOW_PROGRESS,
FlowResultType.SHOW_PROGRESS_DONE,
FlowResultType.MENU,
):
flow.cur_step = result
return result
@ -372,7 +392,7 @@ class FlowManager(abc.ABC):
result = await self.async_finish_flow(flow, result.copy())
# _async_finish_flow may change result type, check it again
if result["type"] == RESULT_TYPE_FORM:
if result["type"] == FlowResultType.FORM:
flow.cur_step = result
return result
@ -427,7 +447,7 @@ class FlowHandler:
) -> FlowResult:
"""Return the definition of a form to gather user input."""
return {
"type": RESULT_TYPE_FORM,
"type": FlowResultType.FORM,
"flow_id": self.flow_id,
"handler": self.handler,
"step_id": step_id,
@ -449,7 +469,7 @@ class FlowHandler:
"""Finish config flow and create a config entry."""
return {
"version": self.VERSION,
"type": RESULT_TYPE_CREATE_ENTRY,
"type": FlowResultType.CREATE_ENTRY,
"flow_id": self.flow_id,
"handler": self.handler,
"title": title,
@ -480,7 +500,7 @@ class FlowHandler:
) -> FlowResult:
"""Return the definition of an external step for the user to take."""
return {
"type": RESULT_TYPE_EXTERNAL_STEP,
"type": FlowResultType.EXTERNAL_STEP,
"flow_id": self.flow_id,
"handler": self.handler,
"step_id": step_id,
@ -492,7 +512,7 @@ class FlowHandler:
def async_external_step_done(self, *, next_step_id: str) -> FlowResult:
"""Return the definition of an external step for the user to take."""
return {
"type": RESULT_TYPE_EXTERNAL_STEP_DONE,
"type": FlowResultType.EXTERNAL_STEP_DONE,
"flow_id": self.flow_id,
"handler": self.handler,
"step_id": next_step_id,
@ -508,7 +528,7 @@ class FlowHandler:
) -> FlowResult:
"""Show a progress message to the user, without user input allowed."""
return {
"type": RESULT_TYPE_SHOW_PROGRESS,
"type": FlowResultType.SHOW_PROGRESS,
"flow_id": self.flow_id,
"handler": self.handler,
"step_id": step_id,
@ -520,7 +540,7 @@ class FlowHandler:
def async_show_progress_done(self, *, next_step_id: str) -> FlowResult:
"""Mark the progress done."""
return {
"type": RESULT_TYPE_SHOW_PROGRESS_DONE,
"type": FlowResultType.SHOW_PROGRESS_DONE,
"flow_id": self.flow_id,
"handler": self.handler,
"step_id": next_step_id,
@ -539,7 +559,7 @@ class FlowHandler:
Options dict maps step_id => i18n label
"""
return {
"type": RESULT_TYPE_MENU,
"type": FlowResultType.MENU,
"flow_id": self.flow_id,
"handler": self.handler,
"step_id": step_id,
@ -558,7 +578,7 @@ def _create_abort_data(
) -> FlowResult:
"""Return the definition of an external step for the user to take."""
return {
"type": RESULT_TYPE_ABORT,
"type": FlowResultType.ABORT,
"flow_id": flow_id,
"handler": handler,
"reason": reason,

View File

@ -26,7 +26,7 @@ class _BaseFlowManagerView(HomeAssistantView):
self, result: data_entry_flow.FlowResult
) -> data_entry_flow.FlowResult:
"""Convert result to JSON."""
if result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY:
data = result.copy()
data.pop("result")
data.pop("data")

View File

@ -42,7 +42,7 @@ class SchemaFlowFormStep:
# The next_step function is called if the schema validates successfully or if no
# schema is defined. The next_step function is passed the union of config entry
# options and user input from previous steps.
# If next_step returns None, the flow is ended with RESULT_TYPE_CREATE_ENTRY.
# If next_step returns None, the flow is ended with FlowResultType.CREATE_ENTRY.
next_step: Callable[[dict[str, Any]], str | None] = lambda _: None
# Optional function to allow amending a form schema.

View File

@ -220,6 +220,12 @@ _OBSOLETE_IMPORT: dict[str, list[ObsoleteImportMatch]] = {
constant=re.compile(r"^SOURCE_(\w*)$"),
),
],
"homeassistant.data_entry_flow": [
ObsoleteImportMatch(
reason="replaced by FlowResultType enum",
constant=re.compile(r"^RESULT_TYPE_(\w*)$"),
),
],
"homeassistant.helpers.device_registry": [
ObsoleteImportMatch(
reason="replaced by DeviceEntryDisabler enum",