From 90bf20c6f84b4d9b427b610d27c1c1386e793e7f Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Mon, 25 Sep 2023 23:01:53 +0200 Subject: [PATCH] Add type hints for intent_script integration (#99393) * Add type hints for intent_script integration * Correct 2nd typo * omit total=False as all options are set --- .../components/intent_script/__init__.py | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/intent_script/__init__.py b/homeassistant/components/intent_script/__init__.py index 55c4947fe4a..f0cf36b5607 100644 --- a/homeassistant/components/intent_script/__init__.py +++ b/homeassistant/components/intent_script/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations import logging +from typing import TypedDict import voluptuous as vol @@ -62,7 +63,7 @@ CONFIG_SCHEMA = vol.Schema( ) -async def async_reload(hass: HomeAssistant, servie_call: ServiceCall) -> None: +async def async_reload(hass: HomeAssistant, service_call: ServiceCall) -> None: """Handle start Intent Script service call.""" new_config = await async_integration_yaml_config(hass, DOMAIN) existing_intents = hass.data[DOMAIN] @@ -79,7 +80,7 @@ async def async_reload(hass: HomeAssistant, servie_call: ServiceCall) -> None: async_load_intents(hass, new_intents) -def async_load_intents(hass: HomeAssistant, intents: dict): +def async_load_intents(hass: HomeAssistant, intents: dict[str, ConfigType]) -> None: """Load YAML intents into the intent system.""" template.attach(hass, intents) hass.data[DOMAIN] = intents @@ -98,8 +99,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async_load_intents(hass, intents) - async def _handle_reload(servie_call: ServiceCall) -> None: - return await async_reload(hass, servie_call) + async def _handle_reload(service_call: ServiceCall) -> None: + return await async_reload(hass, service_call) service.async_register_admin_service( hass, @@ -111,22 +112,41 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: return True +class _IntentSpeechRepromptData(TypedDict): + """Intent config data type for speech or reprompt info.""" + + content: template.Template + title: template.Template + text: template.Template + type: str + + +class _IntentCardData(TypedDict): + """Intent config data type for card info.""" + + type: str + title: template.Template + content: template.Template + + class ScriptIntentHandler(intent.IntentHandler): """Respond to an intent with a script.""" - def __init__(self, intent_type, config): + def __init__(self, intent_type: str, config: ConfigType) -> None: """Initialize the script intent handler.""" self.intent_type = intent_type self.config = config - async def async_handle(self, intent_obj: intent.Intent): + async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" - speech = self.config.get(CONF_SPEECH) - reprompt = self.config.get(CONF_REPROMPT) - card = self.config.get(CONF_CARD) - action = self.config.get(CONF_ACTION) - is_async_action = self.config.get(CONF_ASYNC_ACTION) - slots = {key: value["value"] for key, value in intent_obj.slots.items()} + speech: _IntentSpeechRepromptData | None = self.config.get(CONF_SPEECH) + reprompt: _IntentSpeechRepromptData | None = self.config.get(CONF_REPROMPT) + card: _IntentCardData | None = self.config.get(CONF_CARD) + action: script.Script | None = self.config.get(CONF_ACTION) + is_async_action: bool = self.config[CONF_ASYNC_ACTION] + slots: dict[str, str] = { + key: value["value"] for key, value in intent_obj.slots.items() + } _LOGGER.debug( "Intent named %s received with slots: %s", @@ -150,23 +170,23 @@ class ScriptIntentHandler(intent.IntentHandler): if speech is not None: response.async_set_speech( - speech[CONF_TEXT].async_render(slots, parse_result=False), - speech[CONF_TYPE], + speech["text"].async_render(slots, parse_result=False), + speech["type"], ) if reprompt is not None: - text_reprompt = reprompt[CONF_TEXT].async_render(slots, parse_result=False) + text_reprompt = reprompt["text"].async_render(slots, parse_result=False) if text_reprompt: response.async_set_reprompt( text_reprompt, - reprompt[CONF_TYPE], + reprompt["type"], ) if card is not None: response.async_set_card( - card[CONF_TITLE].async_render(slots, parse_result=False), - card[CONF_CONTENT].async_render(slots, parse_result=False), - card[CONF_TYPE], + card["title"].async_render(slots, parse_result=False), + card["content"].async_render(slots, parse_result=False), + card["type"], ) return response