diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index bbd23983e2..4a00b36290 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -104,7 +104,10 @@ class AuthManagerFlowManager(data_entry_flow.FlowManager): """Return a user as result of login flow.""" flow = cast(LoginFlow, flow) - if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): return result # we got final result diff --git a/homeassistant/components/auth/login_flow.py b/homeassistant/components/auth/login_flow.py index b907598fe5..add0a03878 100644 --- a/homeassistant/components/auth/login_flow.py +++ b/homeassistant/components/auth/login_flow.py @@ -52,7 +52,8 @@ 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 FlowResultType.CREATE_ENTRY and "result" key will contain an authorization code. +have type FlowResultType.CREATE_ENTRY or FlowResultType.FINISH_FLOW 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" @@ -156,7 +157,10 @@ def _prepare_result_json( result: data_entry_flow.FlowResult, ) -> data_entry_flow.FlowResult: """Convert result to JSON.""" - if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): data = result.copy() data.pop("result") data.pop("data") @@ -196,7 +200,10 @@ class LoginFlowBaseView(HomeAssistantView): result: data_entry_flow.FlowResult, ) -> web.Response: """Convert the flow result to a response.""" - if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): # @log_invalid_auth does not work here since it returns HTTP 200. # We need to manually log failed login attempts. if ( diff --git a/homeassistant/components/auth/mfa_setup_flow.py b/homeassistant/components/auth/mfa_setup_flow.py index d6a9282e08..f0f520a196 100644 --- a/homeassistant/components/auth/mfa_setup_flow.py +++ b/homeassistant/components/auth/mfa_setup_flow.py @@ -145,7 +145,10 @@ def _prepare_result_json( result: data_entry_flow.FlowResult, ) -> data_entry_flow.FlowResult: """Convert result to JSON.""" - if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): data = result.copy() return data diff --git a/homeassistant/components/config/config_entries.py b/homeassistant/components/config/config_entries.py index 39c5bce25c..6d41dcb107 100644 --- a/homeassistant/components/config/config_entries.py +++ b/homeassistant/components/config/config_entries.py @@ -117,7 +117,10 @@ class ConfigManagerEntryResourceReloadView(HomeAssistantView): def _prepare_config_flow_result_json(result, prepare_result_json): """Convert result to JSON.""" - if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): return prepare_result_json(result) data = result.copy() diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 3442d613bc..d25bf99d03 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -761,7 +761,10 @@ 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.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): return result # Check if config entry exists with unique ID. Unload it. @@ -1674,7 +1677,10 @@ class OptionsFlowManager(data_entry_flow.FlowManager): """ flow = cast(OptionsFlow, flow) - if result["type"] != data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): return result entry = self.hass.config_entries.async_get_entry(flow.handler) diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index d4c8a0db4e..a371f81a82 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -24,14 +24,16 @@ _LOGGER = logging.getLogger(__name__) class FlowResultType(StrEnum): """Result type for a data entry flow.""" - FORM = "form" - CREATE_ENTRY = "create_entry" ABORT = "abort" + # CREATE_ENTRY is deprecated and replaced by FINISH_FLOW, to be removed in 2024.1 + CREATE_ENTRY = "create_entry" EXTERNAL_STEP = "external" EXTERNAL_STEP_DONE = "external_done" + FINISH_FLOW = "finish_flow" + FORM = "form" + MENU = "menu" SHOW_PROGRESS = "progress" SHOW_PROGRESS_DONE = "progress_done" - MENU = "menu" # RESULT_TYPE_* is deprecated, to be removed in 2022.9 @@ -162,7 +164,7 @@ class FlowManager(abc.ABC): async def async_finish_flow( self, flow: FlowHandler, result: FlowResult ) -> FlowResult: - """Finish a config flow and add an entry.""" + """Finish a flow.""" async def async_post_init(self, flow: FlowHandler, result: FlowResult) -> None: """Entry has finished executing its first step asynchronously.""" @@ -503,7 +505,10 @@ class FlowHandler: description: str | None = None, description_placeholders: Mapping[str, str] | None = None, ) -> FlowResult: - """Finish config flow and create a config entry.""" + """Finish a flow. + + Deprecated and replaced by async_finish_flow, to be removed in 2024.1 + """ flow_result = FlowResult( version=self.VERSION, type=FlowResultType.CREATE_ENTRY, @@ -518,6 +523,28 @@ class FlowHandler: flow_result["title"] = title return flow_result + @callback + def async_finish_flow( + self, + *, + title: str, + data: Mapping[str, Any], + description: str | None = None, + description_placeholders: Mapping[str, str] | None = None, + ) -> FlowResult: + """Finish a flow.""" + return FlowResult( + version=self.VERSION, + type=FlowResultType.FINISH_FLOW, + flow_id=self.flow_id, + handler=self.handler, + title=title, + data=data, + description=description, + description_placeholders=description_placeholders, + context=self.context, + ) + @callback def async_abort( self, diff --git a/homeassistant/helpers/data_entry_flow.py b/homeassistant/helpers/data_entry_flow.py index e3e4b4f0de..ad2e45c941 100644 --- a/homeassistant/helpers/data_entry_flow.py +++ b/homeassistant/helpers/data_entry_flow.py @@ -26,7 +26,10 @@ class _BaseFlowManagerView(HomeAssistantView): self, result: data_entry_flow.FlowResult ) -> data_entry_flow.FlowResult: """Convert result to JSON.""" - if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY: + if result["type"] not in ( + data_entry_flow.FlowResultType.CREATE_ENTRY, + data_entry_flow.FlowResultType.FINISH_FLOW, + ): data = result.copy() data.pop("result") data.pop("data") diff --git a/homeassistant/helpers/schema_config_entry_flow.py b/homeassistant/helpers/schema_config_entry_flow.py index 4e319b20cb..a41115ea87 100644 --- a/homeassistant/helpers/schema_config_entry_flow.py +++ b/homeassistant/helpers/schema_config_entry_flow.py @@ -398,7 +398,7 @@ class SchemaOptionsFlowHandler(config_entries.OptionsFlowWithConfigEntry): data: Mapping[str, Any], **kwargs: Any, ) -> FlowResult: - """Finish config flow and create a config entry.""" + """Finish options flow.""" if self._async_options_flow_finished: self._async_options_flow_finished(self.hass, data) return super().async_create_entry(data=data, **kwargs)