From f85fa4cbbbee886dfe968ce647b48b4b7d753477 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Fri, 17 Nov 2023 15:36:19 +0100 Subject: [PATCH] Add ServiceValidationError and translation support (#1961) * Add ServiceValidationError and translation support * Improvements, add blog post * Add error handling response * Follow up comment * Update blog/2023-10-29-service-exceptions-and-translations.md Co-authored-by: Martin Hjelmare * Update blog/2023-10-29-service-exceptions-and-translations.md Co-authored-by: Martin Hjelmare * Follow up raising vs handling errors * Fix links * Update docs/core/platform/raising_exceptions.md Co-authored-by: Martin Hjelmare * Update blog/2023-10-29-service-exceptions-and-translations.md Co-authored-by: Martin Hjelmare * Update docs/api/websocket.md Co-authored-by: Martin Hjelmare * Update docs/internationalization/core.md Co-authored-by: Martin Hjelmare * Update docs/internationalization/core.md Co-authored-by: Martin Hjelmare * Update docs/core/platform/raising_exceptions.md Co-authored-by: Martin Hjelmare * Update docs/integration_quality_scale_index.md Co-authored-by: Martin Hjelmare * Update docs/internationalization/core.md Co-authored-by: Martin Hjelmare * Update blog/2023-10-29-service-exceptions-and-translations.md Co-authored-by: Martin Hjelmare * Rename file to adjust date --------- Co-authored-by: Martin Hjelmare --- ...-16-service-exceptions-and-translations.md | 21 +++++++++++ docs/api/websocket.md | 25 +++++++++++++ docs/core/platform/raising_exceptions.md | 11 ++++++ docs/integration_quality_scale_index.md | 2 +- docs/internationalization/core.md | 37 +++++++++++++++++++ sidebars.js | 1 + 6 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 blog/2023-11-16-service-exceptions-and-translations.md create mode 100644 docs/core/platform/raising_exceptions.md diff --git a/blog/2023-11-16-service-exceptions-and-translations.md b/blog/2023-11-16-service-exceptions-and-translations.md new file mode 100644 index 00000000000..6f689ea1f02 --- /dev/null +++ b/blog/2023-11-16-service-exceptions-and-translations.md @@ -0,0 +1,21 @@ +--- +author: Jan Bouwhuis +authorURL: https://github.com/jbouwh +authorImageURL: https://avatars.githubusercontent.com/u/7188918?s=96&v=4 +title: Exception handling during and translation support +--- + +## Exception handling during service calls + +Currently service calls that raise exceptions will log full stack traces. Service calls that fail due to invalid user input don't need a stack trace but would benefit from a helpful error message in the users own language. + +To be able to suppress the stack trace in these cases, we introduce `ServiceValidationError` as a new exception type. The `ServiceValidationError` exception can be raised instead of `HomeAssistantError` during the execution of a service call. The error message will show in the UI, and in the logs. The stack trace is printed at debug level, to support development. For other exceptions that are raised from a service call (including `HomeAssistantError`) nothing changes and a full stack trace is printed. [Read more](/docs/core/platform/raising_exceptions). + +## Translation support for Exceptions + +The `HomeAssistantError` exception and its subclasses, including `ServiceValidationError`, now accept a translation key to allow localization. [Read more](/docs/internationalization/core/#exceptions). The translation key will be used in cases where the frontend receives information about the exception. + +### Background + +- Background [discussion](https://github.com/home-assistant/architecture/discussions/992). +- Implementation [Core PR #102592](https://github.com/home-assistant/core/pull/102592). diff --git a/docs/api/websocket.md b/docs/api/websocket.md index 38ccc34bfee..b060130db7d 100644 --- a/docs/api/websocket.md +++ b/docs/api/websocket.md @@ -528,3 +528,28 @@ If an error occurs, the `success` key in the `result` message will be set to `fa } } ``` + +### Error handling during service calls and translations + +The JSON below shows an example of an error response. If `HomeAssistantError` error (or a subclass of `HomeAssistantError`) is handled, translation information, if set, will be added to the response. + +When handling `ServiceValidationError` (`service_validation_error`) a stack trace is printed to the logs at debug level only. + +```json +{ + "id": 24, + "type":"result", + "success": false, + "error": { + "code": "service_validation_error", + "message": "Option 'custom' is not a supported mode.", + "translation_key": "unsupported_mode", + "translation_domain": "kitchen_sink", + "translation_placeholders": { + "mode": "custom" + } + } +} +``` + +[Read more](/docs/core/platform/raising_exceptions) about raising exceptions or and the [localization of exceptions](/docs/internationalization/core/#exceptions). diff --git a/docs/core/platform/raising_exceptions.md b/docs/core/platform/raising_exceptions.md new file mode 100644 index 00000000000..5705831d91f --- /dev/null +++ b/docs/core/platform/raising_exceptions.md @@ -0,0 +1,11 @@ +--- +title: "Raising Exceptions" +--- + +Operations like service calls and entity methods (e.g. *Set HVAC Mode*) should raise exceptions properly. Raise `ServiceValidationError` on an invalid user input and raise `HomeAssistantError` for other failures such as a problem communicating with a device. Note that the exception stack trace will be logged. + +Raise `ServiceValidationError` for validation errors that occur during service calls where printing a full stack trace to the logs is not warranted. This exception class will only log exception stack traces at debug level. + +## Localizing Exceptions + +Home Assistant [supports localization](/docs/internationalization/core/#exceptions) for `HomeAssistantError` and its subclasses like `ServiceValidationError`. diff --git a/docs/integration_quality_scale_index.md b/docs/integration_quality_scale_index.md index 059c7202577..1c89c96aa3a 100644 --- a/docs/integration_quality_scale_index.md +++ b/docs/integration_quality_scale_index.md @@ -26,7 +26,7 @@ This integration is able to cope when things go wrong. It will not print any exc - Handles expiration of auth credentials. Refresh if possible or print correct error and fail setup. If based on a config entry, should trigger a new config entry flow to re-authorize. ([docs](config_entries_config_flow_handler.md#reauthentication)) - Handles internet unavailable. Log a warning once when unavailable, log once when reconnected. - Handles device/service unavailable. Log a warning once when unavailable, log once when reconnected. -- Operations like service calls and entity methods (e.g. *Set HVAC Mode*) have proper exception handling. Raise `ValueError` on invalid user input and raise `HomeAssistantError` for other failures such as a problem communicating with a device. +- Operations like service calls and entity methods (e.g. *Set HVAC Mode*) have proper exception handling. Raise `ServiceValidationError` on invalid user input and raise `HomeAssistantError` for other failures such as a problem communicating with a device. [Read more](/docs/core/platform/raising_exceptions) about raising exceptions. - Set `available` property to `False` if appropriate ([docs](core/entity.md#generic-properties)) - Entities have unique ID (if available) ([docs](entity_registry_index.md#unique-id-requirements)) diff --git a/docs/internationalization/core.md b/docs/internationalization/core.md index f8af14eef05..ec73c561ed6 100644 --- a/docs/internationalization/core.md +++ b/docs/internationalization/core.md @@ -13,6 +13,7 @@ The `strings.json` contains translations for different things that the integrati | `title` | Title of the integration. | | `config` | Translations for the config flow. | | `device_automation` | Translations for device automations. | +| `exceptions` | Translations for error messages. | | `issues` | Translations for repairs issues. | | `options` | Translations for the options flow. | | `selectors` | Selectors of the integration. | @@ -159,6 +160,42 @@ The translation strings for device automations are defined under the `device_aut ``` +### Exceptions + +Localization is supported for `HomeAssistantError` and its subclasses. +The translation strings for exceptions are defined under the `exception` key in a `strings.json` file. The example below describes the different supported keys. + +```json +{ + "exceptions": { + // Translations for known exceptions + "invalid_index": { + "message": "Invalid index selected, expected [0,1,2]. Got {index}" + } + } +} + +``` + +Example of raising an exception with localization during a service call: + +```python +async def async_select_index(hass: HomeAssistant, index: int) -> None: + """Setup the config entry for my device.""" + try: + check_index(index) + except ValueError as ex: + raise ServiceValidationError( + message, + translation_domain=DOMAIN, + translation_key="invalid_index", + translation_placeholders={ + "index": index, + }, + ) from ex +``` + + ### Issues The translation strings for repairs issues are defined under the `issues` key. An example strings file below describes the different supported keys. diff --git a/sidebars.js b/sidebars.js index aaf36a5493a..557fea3de86 100644 --- a/sidebars.js +++ b/sidebars.js @@ -218,6 +218,7 @@ module.exports = { "creating_integration_brand", "core/platform/application_credentials", "core/platform/backup", + "core/platform/raising_exceptions", "core/platform/repairs", "core/platform/reproduce_state", "core/platform/significant_change",