Improve To-do service error handling (#106886)

This commit is contained in:
Allen Porter 2024-01-02 10:50:28 -08:00 committed by GitHub
parent afed45d5d0
commit 943fb2791e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 13 deletions

View file

@ -19,7 +19,7 @@ from homeassistant.core import (
SupportsResponse, SupportsResponse,
callback, callback,
) )
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
@ -106,8 +106,11 @@ def _validate_supported_features(
if desc.service_field not in call_data: if desc.service_field not in call_data:
continue continue
if not supported_features or not supported_features & desc.required_feature: if not supported_features or not supported_features & desc.required_feature:
raise ValueError( raise ServiceValidationError(
f"Entity does not support setting field '{desc.service_field}'" f"Entity does not support setting field '{desc.service_field}'",
translation_domain=DOMAIN,
translation_key="update_field_not_supported",
translation_placeholders={"service_field": desc.service_field},
) )
@ -481,7 +484,12 @@ async def _async_update_todo_item(entity: TodoListEntity, call: ServiceCall) ->
item = call.data["item"] item = call.data["item"]
found = _find_by_uid_or_summary(item, entity.todo_items) found = _find_by_uid_or_summary(item, entity.todo_items)
if not found: if not found:
raise ValueError(f"Unable to find To-do item '{item}'") raise ServiceValidationError(
f"Unable to find To-do item '{item}'",
translation_domain=DOMAIN,
translation_key="item_not_found",
translation_placeholders={"item": item},
)
_validate_supported_features(entity.supported_features, call.data) _validate_supported_features(entity.supported_features, call.data)
@ -509,7 +517,12 @@ async def _async_remove_todo_items(entity: TodoListEntity, call: ServiceCall) ->
for item in call.data.get("item", []): for item in call.data.get("item", []):
found = _find_by_uid_or_summary(item, entity.todo_items) found = _find_by_uid_or_summary(item, entity.todo_items)
if not found or not found.uid: if not found or not found.uid:
raise ValueError(f"Unable to find To-do item '{item}") raise ServiceValidationError(
f"Unable to find To-do item '{item}'",
translation_domain=DOMAIN,
translation_key="item_not_found",
translation_placeholders={"item": item},
)
uids.append(found.uid) uids.append(found.uid)
await entity.async_delete_todo_items(uids=uids) await entity.async_delete_todo_items(uids=uids)

View file

@ -90,5 +90,13 @@
"completed": "Completed" "completed": "Completed"
} }
} }
},
"exceptions": {
"item_not_found": {
"message": "Unable to find To-do item: {item}"
},
"update_field_not_supported": {
"message": "Entity does not support setting field: {service_field}"
}
} }
} }

View file

@ -7,6 +7,7 @@ import pytest
from homeassistant.components.todo import DOMAIN as TODO_DOMAIN from homeassistant.components.todo import DOMAIN as TODO_DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from tests.typing import WebSocketGenerator from tests.typing import WebSocketGenerator
@ -338,7 +339,7 @@ async def test_update_invalid_item(
) -> None: ) -> None:
"""Test updating a todo item that does not exist.""" """Test updating a todo item that does not exist."""
with pytest.raises(ValueError, match="Unable to find"): with pytest.raises(ServiceValidationError, match="Unable to find"):
await hass.services.async_call( await hass.services.async_call(
TODO_DOMAIN, TODO_DOMAIN,
"update_item", "update_item",

View file

@ -20,7 +20,7 @@ from homeassistant.components.todo import (
from homeassistant.config_entries import ConfigEntry, ConfigEntryState, ConfigFlow from homeassistant.config_entries import ConfigEntry, ConfigEntryState, ConfigFlow
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import intent from homeassistant.helpers import intent
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -347,12 +347,12 @@ async def test_add_item_service_raises(
({"item": ""}, vol.Invalid, "length of value must be at least 1"), ({"item": ""}, vol.Invalid, "length of value must be at least 1"),
( (
{"item": "Submit forms", "description": "Submit tax forms"}, {"item": "Submit forms", "description": "Submit tax forms"},
ValueError, ServiceValidationError,
"does not support setting field 'description'", "does not support setting field 'description'",
), ),
( (
{"item": "Submit forms", "due_date": "2023-11-17"}, {"item": "Submit forms", "due_date": "2023-11-17"},
ValueError, ServiceValidationError,
"does not support setting field 'due_date'", "does not support setting field 'due_date'",
), ),
( (
@ -360,7 +360,7 @@ async def test_add_item_service_raises(
"item": "Submit forms", "item": "Submit forms",
"due_datetime": f"2023-11-17T17:00:00{TEST_OFFSET}", "due_datetime": f"2023-11-17T17:00:00{TEST_OFFSET}",
}, },
ValueError, ServiceValidationError,
"does not support setting field 'due_datetime'", "does not support setting field 'due_datetime'",
), ),
], ],
@ -622,7 +622,7 @@ async def test_update_todo_item_service_by_summary_not_found(
await create_mock_platform(hass, [test_entity]) await create_mock_platform(hass, [test_entity])
with pytest.raises(ValueError, match="Unable to find"): with pytest.raises(ServiceValidationError, match="Unable to find"):
await hass.services.async_call( await hass.services.async_call(
DOMAIN, DOMAIN,
"update_item", "update_item",
@ -681,7 +681,7 @@ async def test_update_todo_item_field_unsupported(
await create_mock_platform(hass, [test_entity]) await create_mock_platform(hass, [test_entity])
with pytest.raises(ValueError, match="does not support"): with pytest.raises(ServiceValidationError, match="does not support"):
await hass.services.async_call( await hass.services.async_call(
DOMAIN, DOMAIN,
"update_item", "update_item",
@ -931,7 +931,7 @@ async def test_remove_todo_item_service_by_summary_not_found(
await create_mock_platform(hass, [test_entity]) await create_mock_platform(hass, [test_entity])
with pytest.raises(ValueError, match="Unable to find"): with pytest.raises(ServiceValidationError, match="Unable to find"):
await hass.services.async_call( await hass.services.async_call(
DOMAIN, DOMAIN,
"remove_item", "remove_item",