1
mirror of https://github.com/home-assistant/core synced 2024-10-01 05:30:36 +02:00

Define data flow result type (#49260)

* Define data flow result type

* Revert explicit definitions

* Fix tests

* Specific mypy ignore
This commit is contained in:
Ruslan Sayfutdinov 2021-04-15 18:17:07 +01:00 committed by GitHub
parent dafc7a072c
commit 80f66f301b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 169 additions and 114 deletions

View File

@ -4,13 +4,14 @@ from __future__ import annotations
import asyncio import asyncio
from collections import OrderedDict from collections import OrderedDict
from datetime import timedelta from datetime import timedelta
from typing import Any, Dict, Optional, Tuple, cast from typing import Any, Dict, Mapping, Optional, Tuple, cast
import jwt import jwt
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
from homeassistant.auth.const import ACCESS_TOKEN_EXPIRATION from homeassistant.auth.const import ACCESS_TOKEN_EXPIRATION
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import auth_store, models from . import auth_store, models
@ -97,8 +98,8 @@ class AuthManagerFlowManager(data_entry_flow.FlowManager):
return await auth_provider.async_login_flow(context) return await auth_provider.async_login_flow(context)
async def async_finish_flow( async def async_finish_flow(
self, flow: data_entry_flow.FlowHandler, result: dict[str, Any] self, flow: data_entry_flow.FlowHandler, result: FlowResultDict
) -> dict[str, Any]: ) -> FlowResultDict:
"""Return a user as result of login flow.""" """Return a user as result of login flow."""
flow = cast(LoginFlow, flow) flow = cast(LoginFlow, flow)
@ -115,7 +116,7 @@ class AuthManagerFlowManager(data_entry_flow.FlowManager):
raise KeyError(f"Unknown auth provider {result['handler']}") raise KeyError(f"Unknown auth provider {result['handler']}")
credentials = await auth_provider.async_get_or_create_credentials( credentials = await auth_provider.async_get_or_create_credentials(
result["data"] cast(Mapping[str, str], result["data"]),
) )
if flow.context.get("credential_only"): if flow.context.get("credential_only"):

View File

@ -12,6 +12,7 @@ from voluptuous.humanize import humanize_error
from homeassistant import data_entry_flow, requirements from homeassistant import data_entry_flow, requirements
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.decorator import Registry from homeassistant.util.decorator import Registry
@ -105,7 +106,7 @@ class SetupFlow(data_entry_flow.FlowHandler):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the first step of setup flow. """Handle the first step of setup flow.
Return self.async_show_form(step_id='init') if user_input is None. Return self.async_show_form(step_id='init') if user_input is None.

View File

@ -14,6 +14,7 @@ import voluptuous as vol
from homeassistant.const import CONF_EXCLUDE, CONF_INCLUDE from homeassistant.const import CONF_EXCLUDE, CONF_INCLUDE
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import ServiceNotFound from homeassistant.exceptions import ServiceNotFound
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
@ -292,7 +293,7 @@ class NotifySetupFlow(SetupFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Let user select available notify services.""" """Let user select available notify services."""
errors: dict[str, str] = {} errors: dict[str, str] = {}
@ -318,7 +319,7 @@ class NotifySetupFlow(SetupFlow):
async def async_step_setup( async def async_step_setup(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Verify user can receive one-time password.""" """Verify user can receive one-time password."""
errors: dict[str, str] = {} errors: dict[str, str] = {}

View File

@ -9,6 +9,7 @@ import voluptuous as vol
from homeassistant.auth.models import User from homeassistant.auth.models import User
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultDict
from . import ( from . import (
MULTI_FACTOR_AUTH_MODULE_SCHEMA, MULTI_FACTOR_AUTH_MODULE_SCHEMA,
@ -189,7 +190,7 @@ class TotpSetupFlow(SetupFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the first step of setup flow. """Handle the first step of setup flow.
Return self.async_show_form(step_id='init') if user_input is None. Return self.async_show_form(step_id='init') if user_input is None.

View File

@ -1,6 +1,7 @@
"""Auth providers for Home Assistant.""" """Auth providers for Home Assistant."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Mapping
import importlib import importlib
import logging import logging
import types import types
@ -12,6 +13,7 @@ from voluptuous.humanize import humanize_error
from homeassistant import data_entry_flow, requirements from homeassistant import data_entry_flow, requirements
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from homeassistant.util.decorator import Registry from homeassistant.util.decorator import Registry
@ -102,7 +104,7 @@ class AuthProvider:
raise NotImplementedError raise NotImplementedError
async def async_get_or_create_credentials( async def async_get_or_create_credentials(
self, flow_result: dict[str, str] self, flow_result: Mapping[str, str]
) -> Credentials: ) -> Credentials:
"""Get credentials based on the flow result.""" """Get credentials based on the flow result."""
raise NotImplementedError raise NotImplementedError
@ -198,7 +200,7 @@ class LoginFlow(data_entry_flow.FlowHandler):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the first step of login flow. """Handle the first step of login flow.
Return self.async_show_form(step_id='init') if user_input is None. Return self.async_show_form(step_id='init') if user_input is None.
@ -208,7 +210,7 @@ class LoginFlow(data_entry_flow.FlowHandler):
async def async_step_select_mfa_module( async def async_step_select_mfa_module(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of select mfa module.""" """Handle the step of select mfa module."""
errors = {} errors = {}
@ -233,7 +235,7 @@ class LoginFlow(data_entry_flow.FlowHandler):
async def async_step_mfa( async def async_step_mfa(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of mfa validation.""" """Handle the step of mfa validation."""
assert self.credential assert self.credential
assert self.user assert self.user
@ -285,6 +287,6 @@ class LoginFlow(data_entry_flow.FlowHandler):
errors=errors, errors=errors,
) )
async def async_finish(self, flow_result: Any) -> dict: async def async_finish(self, flow_result: Any) -> FlowResultDict:
"""Handle the pass of login flow.""" """Handle the pass of login flow."""
return self.async_create_entry(title=self._auth_provider.name, data=flow_result) return self.async_create_entry(title=self._auth_provider.name, data=flow_result)

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio.subprocess import asyncio.subprocess
import collections import collections
from collections.abc import Mapping
import logging import logging
import os import os
from typing import Any, cast from typing import Any, cast
@ -10,6 +11,7 @@ from typing import Any, cast
import voluptuous as vol import voluptuous as vol
from homeassistant.const import CONF_COMMAND from homeassistant.const import CONF_COMMAND
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
@ -100,7 +102,7 @@ class CommandLineAuthProvider(AuthProvider):
self._user_meta[username] = meta self._user_meta[username] = meta
async def async_get_or_create_credentials( async def async_get_or_create_credentials(
self, flow_result: dict[str, str] self, flow_result: Mapping[str, str]
) -> Credentials: ) -> Credentials:
"""Get credentials based on the flow result.""" """Get credentials based on the flow result."""
username = flow_result["username"] username = flow_result["username"]
@ -127,7 +129,7 @@ class CommandLineLoginFlow(LoginFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of the form.""" """Handle the step of the form."""
errors = {} errors = {}

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio import asyncio
import base64 import base64
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Mapping
import logging import logging
from typing import Any, cast from typing import Any, cast
@ -12,6 +13,7 @@ import voluptuous as vol
from homeassistant.const import CONF_ID from homeassistant.const import CONF_ID
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
@ -277,7 +279,7 @@ class HassAuthProvider(AuthProvider):
await self.data.async_save() await self.data.async_save()
async def async_get_or_create_credentials( async def async_get_or_create_credentials(
self, flow_result: dict[str, str] self, flow_result: Mapping[str, str]
) -> Credentials: ) -> Credentials:
"""Get credentials based on the flow result.""" """Get credentials based on the flow result."""
if self.data is None: if self.data is None:
@ -319,7 +321,7 @@ class HassLoginFlow(LoginFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of the form.""" """Handle the step of the form."""
errors = {} errors = {}

View File

@ -2,12 +2,14 @@
from __future__ import annotations from __future__ import annotations
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Mapping
import hmac import hmac
from typing import Any, cast from typing import cast
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
@ -62,7 +64,7 @@ class ExampleAuthProvider(AuthProvider):
raise InvalidAuthError raise InvalidAuthError
async def async_get_or_create_credentials( async def async_get_or_create_credentials(
self, flow_result: dict[str, str] self, flow_result: Mapping[str, str]
) -> Credentials: ) -> Credentials:
"""Get credentials based on the flow result.""" """Get credentials based on the flow result."""
username = flow_result["username"] username = flow_result["username"]
@ -97,7 +99,7 @@ class ExampleLoginFlow(LoginFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of the form.""" """Handle the step of the form."""
errors = {} errors = {}

View File

@ -5,12 +5,14 @@ It will be removed when auth system production ready
""" """
from __future__ import annotations from __future__ import annotations
from collections.abc import Mapping
import hmac import hmac
from typing import Any, cast from typing import cast
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -57,7 +59,7 @@ class LegacyApiPasswordAuthProvider(AuthProvider):
raise InvalidAuthError raise InvalidAuthError
async def async_get_or_create_credentials( async def async_get_or_create_credentials(
self, flow_result: dict[str, str] self, flow_result: Mapping[str, str]
) -> Credentials: ) -> Credentials:
"""Return credentials for this login.""" """Return credentials for this login."""
credentials = await self.async_credentials() credentials = await self.async_credentials()
@ -82,7 +84,7 @@ class LegacyLoginFlow(LoginFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of the form.""" """Handle the step of the form."""
errors = {} errors = {}

View File

@ -5,6 +5,7 @@ Abort login flow if not access from trusted network.
""" """
from __future__ import annotations from __future__ import annotations
from collections.abc import Mapping
from ipaddress import ( from ipaddress import (
IPv4Address, IPv4Address,
IPv4Network, IPv4Network,
@ -18,6 +19,7 @@ from typing import Any, Dict, List, Union, cast
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -127,7 +129,7 @@ class TrustedNetworksAuthProvider(AuthProvider):
) )
async def async_get_or_create_credentials( async def async_get_or_create_credentials(
self, flow_result: dict[str, str] self, flow_result: Mapping[str, str]
) -> Credentials: ) -> Credentials:
"""Get credentials based on the flow result.""" """Get credentials based on the flow result."""
user_id = flow_result["user"] user_id = flow_result["user"]
@ -199,7 +201,7 @@ class TrustedNetworksLoginFlow(LoginFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the step of the form.""" """Handle the step of the form."""
try: try:
cast( cast(

View File

@ -16,6 +16,7 @@ from homeassistant.const import (
HTTP_UNAUTHORIZED, HTTP_UNAUTHORIZED,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import DiscoveryInfoType from homeassistant.helpers.typing import DiscoveryInfoType
@ -91,7 +92,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
_, hub_name = await _validate_input(self.hass, self._discovered) _, hub_name = await _validate_input(self.hass, self._discovered)
self._discovered[CONF_NAME] = hub_name self._discovered[CONF_NAME] = hub_name
async def async_step_zeroconf(self, discovery_info: DiscoveryInfoType) -> dict[str, Any]: # type: ignore async def async_step_zeroconf( # type: ignore[override]
self, discovery_info: DiscoveryInfoType
) -> FlowResultDict:
"""Handle a flow initialized by zeroconf discovery.""" """Handle a flow initialized by zeroconf discovery."""
name: str = discovery_info[CONF_NAME] name: str = discovery_info[CONF_NAME]
host: str = discovery_info[CONF_HOST] host: str = discovery_info[CONF_HOST]
@ -115,7 +118,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_confirm( async def async_step_confirm(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle confirmation flow for discovered bond hub.""" """Handle confirmation flow for discovered bond hub."""
errors = {} errors = {}
if user_input is not None: if user_input is not None:
@ -156,7 +159,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a flow initialized by the user.""" """Handle a flow initialized by the user."""
errors = {} errors = {}
if user_input is not None: if user_input is not None:

View File

@ -323,7 +323,7 @@ def get_core_info(hass):
@callback @callback
@bind_hass @bind_hass
def is_hassio(hass): def is_hassio(hass: HomeAssistant) -> bool:
"""Return true if Hass.io is loaded. """Return true if Hass.io is loaded.
Async friendly. Async friendly.

View File

@ -29,6 +29,8 @@ from homeassistant.const import (
CONF_USERNAME, CONF_USERNAME,
) )
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.helpers.typing import DiscoveryInfoType
from .const import ( from .const import (
CONNECTION_TIMEOUT, CONNECTION_TIMEOUT,
@ -58,7 +60,7 @@ class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self, self,
user_input: dict[str, Any] | None = None, user_input: dict[str, Any] | None = None,
errors: dict[str, str] | None = None, errors: dict[str, str] | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
if user_input is None: if user_input is None:
user_input = {} user_input = {}
return self.async_show_form( return self.async_show_form(
@ -85,7 +87,7 @@ class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_import( async def async_step_import(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle import initiated config flow.""" """Handle import initiated config flow."""
return await self.async_step_user(user_input) return await self.async_step_user(user_input)
@ -99,7 +101,7 @@ class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle user initiated config flow.""" """Handle user initiated config flow."""
if user_input is None: if user_input is None:
return await self._async_show_user_form() return await self._async_show_user_form()
@ -211,9 +213,9 @@ class ConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_create_entry(title=title, data=user_input) return self.async_create_entry(title=title, data=user_input)
async def async_step_ssdp( # type: ignore # mypy says signature incompatible with supertype, but it's the same? async def async_step_ssdp( # type: ignore[override]
self, discovery_info: dict[str, Any] self, discovery_info: DiscoveryInfoType
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle SSDP initiated config flow.""" """Handle SSDP initiated config flow."""
await self.async_set_unique_id(discovery_info[ssdp.ATTR_UPNP_UDN]) await self.async_set_unique_id(discovery_info[ssdp.ATTR_UPNP_UDN])
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
@ -254,7 +256,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle options flow.""" """Handle options flow."""
# Recipients are persisted as a list, but handled as comma separated string in UI # Recipients are persisted as a list, but handled as comma separated string in UI

View File

@ -27,6 +27,7 @@ from homeassistant.const import (
CONF_TOKEN, CONF_TOKEN,
) )
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResultDict
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
@ -130,7 +131,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def _advance_to_auth_step_if_necessary( async def _advance_to_auth_step_if_necessary(
self, hyperion_client: client.HyperionClient self, hyperion_client: client.HyperionClient
) -> dict[str, Any]: ) -> FlowResultDict:
"""Determine if auth is required.""" """Determine if auth is required."""
auth_resp = await hyperion_client.async_is_auth_required() auth_resp = await hyperion_client.async_is_auth_required()
@ -145,7 +146,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_reauth( async def async_step_reauth(
self, self,
config_data: ConfigType, config_data: ConfigType,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a reauthentication flow.""" """Handle a reauthentication flow."""
self._data = dict(config_data) self._data = dict(config_data)
async with self._create_client(raw_connection=True) as hyperion_client: async with self._create_client(raw_connection=True) as hyperion_client:
@ -153,9 +154,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
return self.async_abort(reason="cannot_connect") return self.async_abort(reason="cannot_connect")
return await self._advance_to_auth_step_if_necessary(hyperion_client) return await self._advance_to_auth_step_if_necessary(hyperion_client)
async def async_step_ssdp( # type: ignore[override] async def async_step_ssdp(self, discovery_info: dict[str, Any]) -> FlowResultDict: # type: ignore[override]
self, discovery_info: dict[str, Any]
) -> dict[str, Any]:
"""Handle a flow initiated by SSDP.""" """Handle a flow initiated by SSDP."""
# Sample data provided by SSDP: { # Sample data provided by SSDP: {
# 'ssdp_location': 'http://192.168.0.1:8090/description.xml', # 'ssdp_location': 'http://192.168.0.1:8090/description.xml',
@ -226,7 +225,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_user( async def async_step_user(
self, self,
user_input: ConfigType | None = None, user_input: ConfigType | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a flow initiated by the user.""" """Handle a flow initiated by the user."""
errors = {} errors = {}
if user_input: if user_input:
@ -297,7 +296,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_auth( async def async_step_auth(
self, self,
user_input: ConfigType | None = None, user_input: ConfigType | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the auth step of a flow.""" """Handle the auth step of a flow."""
errors = {} errors = {}
if user_input: if user_input:
@ -326,7 +325,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_create_token( async def async_step_create_token(
self, user_input: ConfigType | None = None self, user_input: ConfigType | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Send a request for a new token.""" """Send a request for a new token."""
if user_input is None: if user_input is None:
self._auth_id = client.generate_random_auth_id() self._auth_id = client.generate_random_auth_id()
@ -352,7 +351,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_create_token_external( async def async_step_create_token_external(
self, auth_resp: ConfigType | None = None self, auth_resp: ConfigType | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle completion of the request for a new token.""" """Handle completion of the request for a new token."""
if auth_resp is not None and client.ResponseOK(auth_resp): if auth_resp is not None and client.ResponseOK(auth_resp):
token = auth_resp.get(const.KEY_INFO, {}).get(const.KEY_TOKEN) token = auth_resp.get(const.KEY_INFO, {}).get(const.KEY_TOKEN)
@ -365,7 +364,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_create_token_success( async def async_step_create_token_success(
self, _: ConfigType | None = None self, _: ConfigType | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Create an entry after successful token creation.""" """Create an entry after successful token creation."""
# Clean-up the request task. # Clean-up the request task.
await self._cancel_request_token_task() await self._cancel_request_token_task()
@ -381,7 +380,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_create_token_fail( async def async_step_create_token_fail(
self, _: ConfigType | None = None self, _: ConfigType | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Show an error on the auth form.""" """Show an error on the auth form."""
# Clean-up the request task. # Clean-up the request task.
await self._cancel_request_token_task() await self._cancel_request_token_task()
@ -389,7 +388,7 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_confirm( async def async_step_confirm(
self, user_input: ConfigType | None = None self, user_input: ConfigType | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Get final confirmation before entry creation.""" """Get final confirmation before entry creation."""
if user_input is None and self._require_confirm: if user_input is None and self._require_confirm:
return self.async_show_form( return self.async_show_form(
@ -449,7 +448,7 @@ class HyperionOptionsFlow(OptionsFlow):
async def async_step_init( async def async_step_init(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Manage the options.""" """Manage the options."""
effects = {source: source for source in const.KEY_COMPONENTID_EXTERNAL_SOURCES} effects = {source: source for source in const.KEY_COMPONENTID_EXTERNAL_SOURCES}

View File

@ -14,7 +14,7 @@ from homeassistant import config_entries, exceptions
from homeassistant.components.hassio import is_hassio from homeassistant.components.hassio import is_hassio
from homeassistant.const import CONF_URL from homeassistant.const import CONF_URL
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import AbortFlow from homeassistant.data_entry_flow import AbortFlow, FlowResultDict
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .addon import AddonError, AddonManager, get_addon_manager from .addon import AddonError, AddonManager, get_addon_manager
@ -89,16 +89,16 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle the initial step.""" """Handle the initial step."""
if is_hassio(self.hass): # type: ignore # no-untyped-call if is_hassio(self.hass):
return await self.async_step_on_supervisor() return await self.async_step_on_supervisor()
return await self.async_step_manual() return await self.async_step_manual()
async def async_step_manual( async def async_step_manual(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a manual configuration.""" """Handle a manual configuration."""
if user_input is None: if user_input is None:
return self.async_show_form( return self.async_show_form(
@ -134,9 +134,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
step_id="manual", data_schema=STEP_USER_DATA_SCHEMA, errors=errors step_id="manual", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
) )
async def async_step_hassio( # type: ignore # override async def async_step_hassio(self, discovery_info: dict[str, Any]) -> FlowResultDict: # type: ignore[override]
self, discovery_info: dict[str, Any]
) -> dict[str, Any]:
"""Receive configuration from add-on discovery info. """Receive configuration from add-on discovery info.
This flow is triggered by the Z-Wave JS add-on. This flow is triggered by the Z-Wave JS add-on.
@ -154,7 +152,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_hassio_confirm( async def async_step_hassio_confirm(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Confirm the add-on discovery.""" """Confirm the add-on discovery."""
if user_input is not None: if user_input is not None:
return await self.async_step_on_supervisor( return await self.async_step_on_supervisor(
@ -164,7 +162,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_show_form(step_id="hassio_confirm") return self.async_show_form(step_id="hassio_confirm")
@callback @callback
def _async_create_entry_from_vars(self) -> dict[str, Any]: def _async_create_entry_from_vars(self) -> FlowResultDict:
"""Return a config entry for the flow.""" """Return a config entry for the flow."""
return self.async_create_entry( return self.async_create_entry(
title=TITLE, title=TITLE,
@ -179,7 +177,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_on_supervisor( async def async_step_on_supervisor(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle logic when on Supervisor host.""" """Handle logic when on Supervisor host."""
if user_input is None: if user_input is None:
return self.async_show_form( return self.async_show_form(
@ -203,7 +201,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_install_addon( async def async_step_install_addon(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Install Z-Wave JS add-on.""" """Install Z-Wave JS add-on."""
if not self.install_task: if not self.install_task:
self.install_task = self.hass.async_create_task(self._async_install_addon()) self.install_task = self.hass.async_create_task(self._async_install_addon())
@ -223,13 +221,13 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_install_failed( async def async_step_install_failed(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Add-on installation failed.""" """Add-on installation failed."""
return self.async_abort(reason="addon_install_failed") return self.async_abort(reason="addon_install_failed")
async def async_step_configure_addon( async def async_step_configure_addon(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Ask for config for Z-Wave JS add-on.""" """Ask for config for Z-Wave JS add-on."""
addon_config = await self._async_get_addon_config() addon_config = await self._async_get_addon_config()
@ -265,7 +263,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_start_addon( async def async_step_start_addon(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Start Z-Wave JS add-on.""" """Start Z-Wave JS add-on."""
if not self.start_task: if not self.start_task:
self.start_task = self.hass.async_create_task(self._async_start_addon()) self.start_task = self.hass.async_create_task(self._async_start_addon())
@ -283,7 +281,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_start_failed( async def async_step_start_failed(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Add-on start failed.""" """Add-on start failed."""
return self.async_abort(reason="addon_start_failed") return self.async_abort(reason="addon_start_failed")
@ -320,7 +318,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_finish_addon_setup( async def async_step_finish_addon_setup(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Prepare info needed to complete the config entry. """Prepare info needed to complete the config entry.
Get add-on discovery info and server version info. Get add-on discovery info and server version info.

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections.abc import Mapping
from contextvars import ContextVar from contextvars import ContextVar
import functools import functools
import logging import logging
@ -21,7 +22,7 @@ from homeassistant.exceptions import (
) )
from homeassistant.helpers import device_registry, entity_registry from homeassistant.helpers import device_registry, entity_registry
from homeassistant.helpers.event import Event from homeassistant.helpers.event import Event
from homeassistant.helpers.typing import UNDEFINED, UndefinedType from homeassistant.helpers.typing import UNDEFINED, DiscoveryInfoType, UndefinedType
from homeassistant.setup import async_process_deps_reqs, async_setup_component from homeassistant.setup import async_process_deps_reqs, async_setup_component
from homeassistant.util.decorator import Registry from homeassistant.util.decorator import Registry
import homeassistant.util.uuid as uuid_util import homeassistant.util.uuid as uuid_util
@ -146,7 +147,7 @@ class ConfigEntry:
version: int, version: int,
domain: str, domain: str,
title: str, title: str,
data: dict, data: Mapping[str, Any],
source: str, source: str,
connection_class: str, connection_class: str,
system_options: dict, system_options: dict,
@ -559,8 +560,8 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager):
self._hass_config = hass_config self._hass_config = hass_config
async def async_finish_flow( async def async_finish_flow(
self, flow: data_entry_flow.FlowHandler, result: dict[str, Any] self, flow: data_entry_flow.FlowHandler, result: data_entry_flow.FlowResultDict
) -> dict[str, Any]: ) -> data_entry_flow.FlowResultDict:
"""Finish a config flow and add an entry.""" """Finish a config flow and add an entry."""
flow = cast(ConfigFlow, flow) flow = cast(ConfigFlow, flow)
@ -668,7 +669,7 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager):
return flow return flow
async def async_post_init( async def async_post_init(
self, flow: data_entry_flow.FlowHandler, result: dict self, flow: data_entry_flow.FlowHandler, result: data_entry_flow.FlowResultDict
) -> None: ) -> None:
"""After a flow is initialised trigger new flow notifications.""" """After a flow is initialised trigger new flow notifications."""
source = flow.context["source"] source = flow.context["source"]
@ -931,7 +932,7 @@ class ConfigEntries:
unique_id: str | dict | None | UndefinedType = UNDEFINED, unique_id: str | dict | None | UndefinedType = UNDEFINED,
title: str | dict | UndefinedType = UNDEFINED, title: str | dict | UndefinedType = UNDEFINED,
data: dict | UndefinedType = UNDEFINED, data: dict | UndefinedType = UNDEFINED,
options: dict | UndefinedType = UNDEFINED, options: Mapping[str, Any] | UndefinedType = UNDEFINED,
system_options: dict | UndefinedType = UNDEFINED, system_options: dict | UndefinedType = UNDEFINED,
) -> bool: ) -> bool:
"""Update a config entry. """Update a config entry.
@ -956,7 +957,7 @@ class ConfigEntries:
changed = True changed = True
entry.data = MappingProxyType(data) entry.data = MappingProxyType(data)
if options is not UNDEFINED and entry.options != options: # type: ignore if options is not UNDEFINED and entry.options != options:
changed = True changed = True
entry.options = MappingProxyType(options) entry.options = MappingProxyType(options)
@ -1147,7 +1148,9 @@ class ConfigFlow(data_entry_flow.FlowHandler):
} }
@callback @callback
def _async_in_progress(self, include_uninitialized: bool = False) -> list[dict]: def _async_in_progress(
self, include_uninitialized: bool = False
) -> list[data_entry_flow.FlowResultDict]:
"""Return other in progress flows for current domain.""" """Return other in progress flows for current domain."""
return [ return [
flw flw
@ -1157,18 +1160,22 @@ class ConfigFlow(data_entry_flow.FlowHandler):
if flw["handler"] == self.handler and flw["flow_id"] != self.flow_id if flw["handler"] == self.handler and flw["flow_id"] != self.flow_id
] ]
async def async_step_ignore(self, user_input: dict[str, Any]) -> dict[str, Any]: async def async_step_ignore(
self, user_input: dict[str, Any]
) -> data_entry_flow.FlowResultDict:
"""Ignore this config flow.""" """Ignore this config flow."""
await self.async_set_unique_id(user_input["unique_id"], raise_on_progress=False) await self.async_set_unique_id(user_input["unique_id"], raise_on_progress=False)
return self.async_create_entry(title=user_input["title"], data={}) return self.async_create_entry(title=user_input["title"], data={})
async def async_step_unignore(self, user_input: dict[str, Any]) -> dict[str, Any]: async def async_step_unignore(
self, user_input: dict[str, Any]
) -> data_entry_flow.FlowResultDict:
"""Rediscover a config entry by it's unique_id.""" """Rediscover a config entry by it's unique_id."""
return self.async_abort(reason="not_implemented") return self.async_abort(reason="not_implemented")
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> data_entry_flow.FlowResultDict:
"""Handle a flow initiated by the user.""" """Handle a flow initiated by the user."""
return self.async_abort(reason="not_implemented") return self.async_abort(reason="not_implemented")
@ -1197,8 +1204,8 @@ class ConfigFlow(data_entry_flow.FlowHandler):
raise data_entry_flow.AbortFlow("already_in_progress") raise data_entry_flow.AbortFlow("already_in_progress")
async def async_step_discovery( async def async_step_discovery(
self, discovery_info: dict[str, Any] self, discovery_info: DiscoveryInfoType
) -> dict[str, Any]: ) -> data_entry_flow.FlowResultDict:
"""Handle a flow initialized by discovery.""" """Handle a flow initialized by discovery."""
await self._async_handle_discovery_without_unique_id() await self._async_handle_discovery_without_unique_id()
return await self.async_step_user() return await self.async_step_user()
@ -1206,7 +1213,7 @@ class ConfigFlow(data_entry_flow.FlowHandler):
@callback @callback
def async_abort( def async_abort(
self, *, reason: str, description_placeholders: dict | None = None self, *, reason: str, description_placeholders: dict | None = None
) -> dict[str, Any]: ) -> data_entry_flow.FlowResultDict:
"""Abort the config flow.""" """Abort the config flow."""
# Remove reauth notification if no reauth flows are in progress # Remove reauth notification if no reauth flows are in progress
if self.source == SOURCE_REAUTH and not any( if self.source == SOURCE_REAUTH and not any(
@ -1254,8 +1261,8 @@ class OptionsFlowManager(data_entry_flow.FlowManager):
return cast(OptionsFlow, HANDLERS[entry.domain].async_get_options_flow(entry)) return cast(OptionsFlow, HANDLERS[entry.domain].async_get_options_flow(entry))
async def async_finish_flow( async def async_finish_flow(
self, flow: data_entry_flow.FlowHandler, result: dict[str, Any] self, flow: data_entry_flow.FlowHandler, result: data_entry_flow.FlowResultDict
) -> dict[str, Any]: ) -> data_entry_flow.FlowResultDict:
"""Finish an options flow and update options for configuration entry. """Finish an options flow and update options for configuration entry.
Flow.handler and entry_id is the same thing to map flow with entry. Flow.handler and entry_id is the same thing to map flow with entry.

View File

@ -5,7 +5,7 @@ import abc
import asyncio import asyncio
from collections.abc import Mapping from collections.abc import Mapping
from types import MappingProxyType from types import MappingProxyType
from typing import Any from typing import Any, TypedDict
import uuid import uuid
import voluptuous as vol import voluptuous as vol
@ -51,6 +51,29 @@ class AbortFlow(FlowError):
self.description_placeholders = description_placeholders self.description_placeholders = description_placeholders
class FlowResultDict(TypedDict, total=False):
"""Typed result dict."""
version: int
type: str
flow_id: str
handler: str
title: str
data: Mapping[str, Any]
step_id: str
data_schema: vol.Schema
extra: str
required: bool
errors: dict[str, str] | None
description: str | None
description_placeholders: dict[str, Any] | None
progress_action: str
url: str
reason: str
context: dict[str, Any]
result: Any
class FlowManager(abc.ABC): class FlowManager(abc.ABC):
"""Manage all the flows that are in progress.""" """Manage all the flows that are in progress."""
@ -88,15 +111,17 @@ class FlowManager(abc.ABC):
@abc.abstractmethod @abc.abstractmethod
async def async_finish_flow( async def async_finish_flow(
self, flow: FlowHandler, result: dict[str, Any] self, flow: FlowHandler, result: FlowResultDict
) -> dict[str, Any]: ) -> FlowResultDict:
"""Finish a config flow and add an entry.""" """Finish a config flow and add an entry."""
async def async_post_init(self, flow: FlowHandler, result: dict[str, Any]) -> None: async def async_post_init(self, flow: FlowHandler, result: FlowResultDict) -> None:
"""Entry has finished executing its first step asynchronously.""" """Entry has finished executing its first step asynchronously."""
@callback @callback
def async_progress(self, include_uninitialized: bool = False) -> list[dict]: def async_progress(
self, include_uninitialized: bool = False
) -> list[FlowResultDict]:
"""Return the flows in progress.""" """Return the flows in progress."""
return [ return [
{ {
@ -110,8 +135,8 @@ class FlowManager(abc.ABC):
] ]
async def async_init( async def async_init(
self, handler: str, *, context: dict | None = None, data: Any = None self, handler: str, *, context: dict[str, Any] | None = None, data: Any = None
) -> Any: ) -> FlowResultDict:
"""Start a configuration flow.""" """Start a configuration flow."""
if context is None: if context is None:
context = {} context = {}
@ -160,7 +185,7 @@ class FlowManager(abc.ABC):
async def async_configure( async def async_configure(
self, flow_id: str, user_input: dict | None = None self, flow_id: str, user_input: dict | None = None
) -> Any: ) -> FlowResultDict:
"""Continue a configuration flow.""" """Continue a configuration flow."""
flow = self._progress.get(flow_id) flow = self._progress.get(flow_id)
@ -217,7 +242,7 @@ class FlowManager(abc.ABC):
step_id: str, step_id: str,
user_input: dict | None, user_input: dict | None,
step_done: asyncio.Future | None = None, step_done: asyncio.Future | None = None,
) -> dict: ) -> FlowResultDict:
"""Handle a step of a flow.""" """Handle a step of a flow."""
method = f"async_step_{step_id}" method = f"async_step_{step_id}"
@ -230,7 +255,7 @@ class FlowManager(abc.ABC):
) )
try: try:
result: dict = await getattr(flow, method)(user_input) result: FlowResultDict = await getattr(flow, method)(user_input)
except AbortFlow as err: except AbortFlow as err:
result = _create_abort_data( result = _create_abort_data(
flow.flow_id, flow.handler, err.reason, err.description_placeholders flow.flow_id, flow.handler, err.reason, err.description_placeholders
@ -265,7 +290,7 @@ class FlowManager(abc.ABC):
return result return result
# We pass a copy of the result because we're mutating our version # We pass a copy of the result because we're mutating our version
result = await self.async_finish_flow(flow, dict(result)) result = await self.async_finish_flow(flow, result.copy())
# _async_finish_flow may change result type, check it again # _async_finish_flow may change result type, check it again
if result["type"] == RESULT_TYPE_FORM: if result["type"] == RESULT_TYPE_FORM:
@ -288,7 +313,7 @@ class FlowHandler:
hass: HomeAssistant = None # type: ignore hass: HomeAssistant = None # type: ignore
handler: str = None # type: ignore handler: str = None # type: ignore
# Ensure the attribute has a subscriptable, but immutable, default value. # Ensure the attribute has a subscriptable, but immutable, default value.
context: dict = MappingProxyType({}) # type: ignore context: dict[str, Any] = MappingProxyType({}) # type: ignore
# Set by _async_create_flow callback # Set by _async_create_flow callback
init_step = "init" init_step = "init"
@ -318,9 +343,9 @@ class FlowHandler:
*, *,
step_id: str, step_id: str,
data_schema: vol.Schema = None, data_schema: vol.Schema = None,
errors: dict | None = None, errors: dict[str, str] | None = None,
description_placeholders: dict | None = None, description_placeholders: dict[str, Any] | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Return the definition of a form to gather user input.""" """Return the definition of a form to gather user input."""
return { return {
"type": RESULT_TYPE_FORM, "type": RESULT_TYPE_FORM,
@ -340,7 +365,7 @@ class FlowHandler:
data: Mapping[str, Any], data: Mapping[str, Any],
description: str | None = None, description: str | None = None,
description_placeholders: dict | None = None, description_placeholders: dict | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Finish config flow and create a config entry.""" """Finish config flow and create a config entry."""
return { return {
"version": self.VERSION, "version": self.VERSION,
@ -356,7 +381,7 @@ class FlowHandler:
@callback @callback
def async_abort( def async_abort(
self, *, reason: str, description_placeholders: dict | None = None self, *, reason: str, description_placeholders: dict | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Abort the config flow.""" """Abort the config flow."""
return _create_abort_data( return _create_abort_data(
self.flow_id, self.handler, reason, description_placeholders self.flow_id, self.handler, reason, description_placeholders
@ -365,7 +390,7 @@ class FlowHandler:
@callback @callback
def async_external_step( def async_external_step(
self, *, step_id: str, url: str, description_placeholders: dict | None = None self, *, step_id: str, url: str, description_placeholders: dict | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Return the definition of an external step for the user to take.""" """Return the definition of an external step for the user to take."""
return { return {
"type": RESULT_TYPE_EXTERNAL_STEP, "type": RESULT_TYPE_EXTERNAL_STEP,
@ -377,7 +402,7 @@ class FlowHandler:
} }
@callback @callback
def async_external_step_done(self, *, next_step_id: str) -> dict[str, Any]: def async_external_step_done(self, *, next_step_id: str) -> FlowResultDict:
"""Return the definition of an external step for the user to take.""" """Return the definition of an external step for the user to take."""
return { return {
"type": RESULT_TYPE_EXTERNAL_STEP_DONE, "type": RESULT_TYPE_EXTERNAL_STEP_DONE,
@ -393,7 +418,7 @@ class FlowHandler:
step_id: str, step_id: str,
progress_action: str, progress_action: str,
description_placeholders: dict | None = None, description_placeholders: dict | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Show a progress message to the user, without user input allowed.""" """Show a progress message to the user, without user input allowed."""
return { return {
"type": RESULT_TYPE_SHOW_PROGRESS, "type": RESULT_TYPE_SHOW_PROGRESS,
@ -405,7 +430,7 @@ class FlowHandler:
} }
@callback @callback
def async_show_progress_done(self, *, next_step_id: str) -> dict[str, Any]: def async_show_progress_done(self, *, next_step_id: str) -> FlowResultDict:
"""Mark the progress done.""" """Mark the progress done."""
return { return {
"type": RESULT_TYPE_SHOW_PROGRESS_DONE, "type": RESULT_TYPE_SHOW_PROGRESS_DONE,
@ -421,7 +446,7 @@ def _create_abort_data(
handler: str, handler: str,
reason: str, reason: str,
description_placeholders: dict | None = None, description_placeholders: dict | None = None,
) -> dict[str, Any]: ) -> FlowResultDict:
"""Return the definition of an external step for the user to take.""" """Return the definition of an external step for the user to take."""
return { return {
"type": RESULT_TYPE_ABORT, "type": RESULT_TYPE_ABORT,

View File

@ -5,6 +5,8 @@ from typing import Any, Awaitable, Callable, Union
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.helpers.typing import DiscoveryInfoType
DiscoveryFunctionType = Callable[[], Union[Awaitable[bool], bool]] DiscoveryFunctionType = Callable[[], Union[Awaitable[bool], bool]]
@ -29,7 +31,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a flow initialized by the user.""" """Handle a flow initialized by the user."""
if self._async_current_entries(): if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")
@ -40,7 +42,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
async def async_step_confirm( async def async_step_confirm(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Confirm setup.""" """Confirm setup."""
if user_input is None: if user_input is None:
self._set_confirm_only() self._set_confirm_only()
@ -69,8 +71,8 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
return self.async_create_entry(title=self._title, data={}) return self.async_create_entry(title=self._title, data={})
async def async_step_discovery( async def async_step_discovery(
self, discovery_info: dict[str, Any] self, discovery_info: DiscoveryInfoType
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a flow initialized by discovery.""" """Handle a flow initialized by discovery."""
if self._async_in_progress() or self._async_current_entries(): if self._async_in_progress() or self._async_current_entries():
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")
@ -85,7 +87,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
async_step_homekit = async_step_discovery async_step_homekit = async_step_discovery
async_step_dhcp = async_step_discovery async_step_dhcp = async_step_discovery
async def async_step_import(self, _: dict[str, Any] | None) -> dict[str, Any]: async def async_step_import(self, _: dict[str, Any] | None) -> FlowResultDict:
"""Handle a flow initialized by import.""" """Handle a flow initialized by import."""
if self._async_current_entries(): if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")
@ -135,7 +137,7 @@ class WebhookFlowHandler(config_entries.ConfigFlow):
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Handle a user initiated set up flow to create a webhook.""" """Handle a user initiated set up flow to create a webhook."""
if not self._allow_multiple and self._async_current_entries(): if not self._allow_multiple and self._async_current_entries():
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")

View File

@ -23,6 +23,7 @@ from yarl import URL
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import http from homeassistant.components import http
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResultDict
from homeassistant.helpers.network import NoURLAvailableError from homeassistant.helpers.network import NoURLAvailableError
from .aiohttp_client import async_get_clientsession from .aiohttp_client import async_get_clientsession
@ -234,7 +235,7 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
async def async_step_pick_implementation( async def async_step_pick_implementation(
self, user_input: dict | None = None self, user_input: dict | None = None
) -> dict: ) -> FlowResultDict:
"""Handle a flow start.""" """Handle a flow start."""
implementations = await async_get_implementations(self.hass, self.DOMAIN) implementations = await async_get_implementations(self.hass, self.DOMAIN)
@ -265,7 +266,7 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
async def async_step_auth( async def async_step_auth(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Create an entry for auth.""" """Create an entry for auth."""
# Flow has been triggered by external data # Flow has been triggered by external data
if user_input: if user_input:
@ -291,7 +292,7 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
async def async_step_creation( async def async_step_creation(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]: ) -> FlowResultDict:
"""Create config entry from external data.""" """Create config entry from external data."""
token = await self.flow_impl.async_resolve_external_data(self.external_data) token = await self.flow_impl.async_resolve_external_data(self.external_data)
# Force int for non-compliant oauth2 providers # Force int for non-compliant oauth2 providers
@ -308,7 +309,7 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
{"auth_implementation": self.flow_impl.domain, "token": token} {"auth_implementation": self.flow_impl.domain, "token": token}
) )
async def async_oauth_create_entry(self, data: dict) -> dict: async def async_oauth_create_entry(self, data: dict) -> FlowResultDict:
"""Create an entry for the flow. """Create an entry for the flow.
Ok to override if you want to fetch extra info or even add another step. Ok to override if you want to fetch extra info or even add another step.

View File

@ -21,7 +21,9 @@ class _BaseFlowManagerView(HomeAssistantView):
self._flow_mgr = flow_mgr self._flow_mgr = flow_mgr
# pylint: disable=no-self-use # pylint: disable=no-self-use
def _prepare_result_json(self, result: dict[str, Any]) -> dict[str, Any]: def _prepare_result_json(
self, result: data_entry_flow.FlowResultDict
) -> data_entry_flow.FlowResultDict:
"""Convert result to JSON.""" """Convert result to JSON."""
if result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY: if result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
data = result.copy() data = result.copy()