diff --git a/homeassistant/components/shell_command/__init__.py b/homeassistant/components/shell_command/__init__.py index 95bbb01bcfb..c2c384e39aa 100644 --- a/homeassistant/components/shell_command/__init__.py +++ b/homeassistant/components/shell_command/__init__.py @@ -15,7 +15,7 @@ from homeassistant.core import ( ServiceResponse, SupportsResponse, ) -from homeassistant.exceptions import TemplateError +from homeassistant.exceptions import HomeAssistantError, TemplateError from homeassistant.helpers import config_validation as cv, template from homeassistant.helpers.typing import ConfigType from homeassistant.util.json import JsonObjectType @@ -91,7 +91,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: try: async with asyncio.timeout(COMMAND_TIMEOUT): stdout_data, stderr_data = await process.communicate() - except TimeoutError: + except TimeoutError as err: _LOGGER.error( "Timed out running command: `%s`, after: %ss", cmd, COMMAND_TIMEOUT ) @@ -103,7 +103,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: process._transport.close() # type: ignore[attr-defined] del process - raise + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="timeout", + translation_placeholders={ + "command": cmd, + "timeout": str(COMMAND_TIMEOUT), + }, + ) from err if stdout_data: _LOGGER.debug( @@ -135,11 +142,15 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: service_response["stdout"] = stdout_data.decode("utf-8").strip() if stderr_data: service_response["stderr"] = stderr_data.decode("utf-8").strip() - except UnicodeDecodeError: + except UnicodeDecodeError as err: _LOGGER.exception( "Unable to handle non-utf8 output of command: `%s`", cmd ) - raise + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="non_utf8_output", + translation_placeholders={"command": cmd}, + ) from err return service_response return None diff --git a/homeassistant/components/shell_command/strings.json b/homeassistant/components/shell_command/strings.json new file mode 100644 index 00000000000..c87dac15b2d --- /dev/null +++ b/homeassistant/components/shell_command/strings.json @@ -0,0 +1,10 @@ +{ + "exceptions": { + "timeout": { + "message": "Timed out running command: `{command}`, after: {timeout} seconds" + }, + "non_utf8_output": { + "message": "Unable to handle non-utf8 output of command: `{command}`" + } + } +} diff --git a/tests/components/shell_command/test_init.py b/tests/components/shell_command/test_init.py index 93b06ddf9d8..526ac1643ec 100644 --- a/tests/components/shell_command/test_init.py +++ b/tests/components/shell_command/test_init.py @@ -11,7 +11,7 @@ import pytest from homeassistant.components import shell_command from homeassistant.core import HomeAssistant -from homeassistant.exceptions import TemplateError +from homeassistant.exceptions import HomeAssistantError, TemplateError from homeassistant.setup import async_setup_component @@ -199,7 +199,10 @@ async def test_non_text_stdout_capture( assert not response # Non-text output throws with 'return_response' - with pytest.raises(UnicodeDecodeError): + with pytest.raises( + HomeAssistantError, + match="Unable to handle non-utf8 output of command: `curl -o - https://raw.githubusercontent.com/home-assistant/assets/master/misc/loading-screen.gif`", + ): response = await hass.services.async_call( "shell_command", "output_image", blocking=True, return_response=True ) @@ -258,7 +261,10 @@ async def test_do_not_run_forever( side_effect=mock_create_subprocess_shell, ), ): - with pytest.raises(TimeoutError): + with pytest.raises( + HomeAssistantError, + match="Timed out running command: `mock_sleep 10000`, after: 0.001 seconds", + ): await hass.services.async_call( shell_command.DOMAIN, "test_service",