diff --git a/homeassistant/helpers/intent.py b/homeassistant/helpers/intent.py index c46a506a2eb..01763fade9d 100644 --- a/homeassistant/helpers/intent.py +++ b/homeassistant/helpers/intent.py @@ -718,9 +718,13 @@ class IntentHandler: """Intent handler registration.""" intent_type: str - slot_schema: vol.Schema | None = None platforms: Iterable[str] | None = [] + @property + def slot_schema(self) -> dict | None: + """Return a slot schema.""" + return None + @callback def async_can_handle(self, intent_obj: Intent) -> bool: """Test if an intent can be handled.""" @@ -761,14 +765,6 @@ class DynamicServiceIntentHandler(IntentHandler): Service specific intent handler that calls a service by name/entity_id. """ - slot_schema = { - vol.Any("name", "area", "floor"): cv.string, - vol.Optional("domain"): vol.All(cv.ensure_list, [cv.string]), - vol.Optional("device_class"): vol.All(cv.ensure_list, [cv.string]), - vol.Optional("preferred_area_id"): cv.string, - vol.Optional("preferred_floor_id"): cv.string, - } - # We use a small timeout in service calls to (hopefully) pass validation # checks, but not try to wait for the call to fully complete. service_timeout: float = 0.2 @@ -809,33 +805,33 @@ class DynamicServiceIntentHandler(IntentHandler): self.optional_slots[key] = value_schema @cached_property - def _slot_schema(self) -> vol.Schema: - """Create validation schema for slots (with extra required slots).""" - if self.slot_schema is None: - raise ValueError("Slot schema is not defined") + def slot_schema(self) -> dict: + """Return a slot schema.""" + slot_schema = { + vol.Any("name", "area", "floor"): cv.string, + vol.Optional("domain"): vol.All(cv.ensure_list, [cv.string]), + vol.Optional("device_class"): vol.All(cv.ensure_list, [cv.string]), + vol.Optional("preferred_area_id"): cv.string, + vol.Optional("preferred_floor_id"): cv.string, + } - if self.required_slots or self.optional_slots: - slot_schema = { - **self.slot_schema, - **{ - vol.Required(key[0]): schema - for key, schema in self.required_slots.items() - }, - **{ - vol.Optional(key[0]): schema - for key, schema in self.optional_slots.items() - }, - } - else: - slot_schema = self.slot_schema + if self.required_slots: + slot_schema.update( + { + vol.Required(key[0]): validator + for key, validator in self.required_slots.items() + } + ) - return vol.Schema( - { - key: SLOT_SCHEMA.extend({"value": validator}) - for key, validator in slot_schema.items() - }, - extra=vol.ALLOW_EXTRA, - ) + if self.optional_slots: + slot_schema.update( + { + vol.Optional(key[0]): validator + for key, validator in self.optional_slots.items() + } + ) + + return slot_schema @abstractmethod def get_domain_and_service( diff --git a/tests/helpers/test_intent.py b/tests/helpers/test_intent.py index 5e54277b423..1ac189d8242 100644 --- a/tests/helpers/test_intent.py +++ b/tests/helpers/test_intent.py @@ -32,7 +32,12 @@ class MockIntentHandler(intent.IntentHandler): def __init__(self, slot_schema) -> None: """Initialize the mock handler.""" - self.slot_schema = slot_schema + self._mock_slot_schema = slot_schema + + @property + def slot_schema(self): + """Return the slot schema.""" + return self._mock_slot_schema async def test_async_match_states(