From 3dc8df2403aec7129b4841a380b1b058da20506c Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Mon, 18 Mar 2024 14:42:21 +0100 Subject: [PATCH] Get ServiceValidationError message from translation cache only (#113704) * Get ServiceValidationError message from translation cache only * Remove message for NotValidPresetModeError --- homeassistant/components/bsblan/climate.py | 1 - homeassistant/components/easyenergy/services.py | 2 -- homeassistant/components/ecovacs/vacuum.py | 3 --- homeassistant/components/energyzero/services.py | 3 --- homeassistant/components/fan/__init__.py | 2 -- homeassistant/components/homeassistant/scene.py | 2 -- homeassistant/components/lock/__init__.py | 1 - homeassistant/components/mqtt/__init__.py | 3 --- homeassistant/components/select/__init__.py | 1 - homeassistant/components/smtp/notify.py | 4 ---- homeassistant/components/tessie/lock.py | 1 - homeassistant/components/todo/__init__.py | 3 --- homeassistant/components/water_heater/__init__.py | 5 ----- homeassistant/components/yolink/services.py | 1 - tests/components/energyzero/test_services.py | 9 ++++++--- tests/components/mqtt/test_init.py | 4 ++-- tests/components/todo/test_init.py | 10 ++++++---- tests/components/water_heater/test_init.py | 4 ++-- 18 files changed, 16 insertions(+), 43 deletions(-) diff --git a/homeassistant/components/bsblan/climate.py b/homeassistant/components/bsblan/climate.py index eaa412978c0..1b300e1e738 100644 --- a/homeassistant/components/bsblan/climate.py +++ b/homeassistant/components/bsblan/climate.py @@ -150,7 +150,6 @@ class BSBLANClimate( await self.async_set_data(preset_mode=preset_mode) else: raise ServiceValidationError( - "Can't set preset mode when hvac mode is not auto", translation_domain=DOMAIN, translation_key="set_preset_mode_error", translation_placeholders={"preset_mode": preset_mode}, diff --git a/homeassistant/components/easyenergy/services.py b/homeassistant/components/easyenergy/services.py index 402f3195dc7..5b80cfafd08 100644 --- a/homeassistant/components/easyenergy/services.py +++ b/homeassistant/components/easyenergy/services.py @@ -95,7 +95,6 @@ def __get_coordinator( if not entry: raise ServiceValidationError( - f"Invalid config entry: {entry_id}", translation_domain=DOMAIN, translation_key="invalid_config_entry", translation_placeholders={ @@ -104,7 +103,6 @@ def __get_coordinator( ) if entry.state != ConfigEntryState.LOADED: raise ServiceValidationError( - f"{entry.title} is not loaded", translation_domain=DOMAIN, translation_key="unloaded_config_entry", translation_placeholders={ diff --git a/homeassistant/components/ecovacs/vacuum.py b/homeassistant/components/ecovacs/vacuum.py index b70f6a6344e..d5016ab683d 100644 --- a/homeassistant/components/ecovacs/vacuum.py +++ b/homeassistant/components/ecovacs/vacuum.py @@ -337,7 +337,6 @@ class EcovacsVacuum( params = {} elif isinstance(params, list): raise ServiceValidationError( - "Params must be a dict!", translation_domain=DOMAIN, translation_key="vacuum_send_command_params_dict", ) @@ -345,7 +344,6 @@ class EcovacsVacuum( if command in ["spot_area", "custom_area"]: if params is None: raise ServiceValidationError( - f"Params are required for {command}!", translation_domain=DOMAIN, translation_key="vacuum_send_command_params_required", translation_placeholders={"command": command}, @@ -354,7 +352,6 @@ class EcovacsVacuum( info = self._device.device_info name = info.get("nick", info["name"]) raise ServiceValidationError( - f"Vacuum {name} does not support area capability!", translation_domain=DOMAIN, translation_key="vacuum_send_command_area_not_supported", translation_placeholders={"name": name}, diff --git a/homeassistant/components/energyzero/services.py b/homeassistant/components/energyzero/services.py index d04912ca99e..d98699c5c08 100644 --- a/homeassistant/components/energyzero/services.py +++ b/homeassistant/components/energyzero/services.py @@ -62,7 +62,6 @@ def __get_date(date_input: str | None) -> date | datetime: return value raise ServiceValidationError( - "Invalid datetime provided.", translation_domain=DOMAIN, translation_key="invalid_date", translation_placeholders={ @@ -93,7 +92,6 @@ def __get_coordinator( if not entry: raise ServiceValidationError( - f"Invalid config entry: {entry_id}", translation_domain=DOMAIN, translation_key="invalid_config_entry", translation_placeholders={ @@ -102,7 +100,6 @@ def __get_coordinator( ) if entry.state != ConfigEntryState.LOADED: raise ServiceValidationError( - f"{entry.title} is not loaded", translation_domain=DOMAIN, translation_key="unloaded_config_entry", translation_placeholders={ diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index 185b9631198..b62f207bde8 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -297,8 +297,6 @@ class FanEntity(ToggleEntity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): if not preset_modes or preset_mode not in preset_modes: preset_modes_str: str = ", ".join(preset_modes or []) raise NotValidPresetModeError( - f"The preset_mode {preset_mode} is not a valid preset_mode:" - f" {preset_modes}", translation_placeholders={ "preset_mode": preset_mode, "preset_modes": preset_modes_str, diff --git a/homeassistant/components/homeassistant/scene.py b/homeassistant/components/homeassistant/scene.py index 9d03b35e079..1c4fee23198 100644 --- a/homeassistant/components/homeassistant/scene.py +++ b/homeassistant/components/homeassistant/scene.py @@ -282,7 +282,6 @@ async def async_setup_platform( scene = platform.entities.get(entity_id) if scene is None: raise ServiceValidationError( - f"{entity_id} is not a valid scene entity_id", translation_domain=SCENE_DOMAIN, translation_key="entity_not_scene", translation_placeholders={ @@ -292,7 +291,6 @@ async def async_setup_platform( assert isinstance(scene, HomeAssistantScene) if not scene.from_service: raise ServiceValidationError( - f"The scene {entity_id} is not created with service `scene.create`", translation_domain=SCENE_DOMAIN, translation_key="entity_not_dynamically_created", translation_placeholders={ diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index e8b7a013523..b2cd28324cb 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -156,7 +156,6 @@ class LockEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): if TYPE_CHECKING: assert self.code_format raise ServiceValidationError( - f"The code for {self.entity_id} doesn't match pattern {self.code_format}", translation_domain=DOMAIN, translation_key="add_default_code", translation_placeholders={ diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 3b34ef79291..8e866776a41 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -331,8 +331,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: except vol.Invalid as err: err_str = str(err) raise ServiceValidationError( - f"Unable to publish: topic template '{msg_topic_template}' produced an " - f"invalid topic '{rendered_topic}' after rendering ({err_str})", translation_domain=DOMAIN, translation_key="invalid_publish_topic", translation_placeholders={ @@ -405,7 +403,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) except ConfigValidationError as ex: raise ServiceValidationError( - str(ex), translation_domain=ex.translation_domain, translation_key=ex.translation_key, translation_placeholders=ex.translation_placeholders, diff --git a/homeassistant/components/select/__init__.py b/homeassistant/components/select/__init__.py index 1594b9e2195..0c54dfc0aac 100644 --- a/homeassistant/components/select/__init__.py +++ b/homeassistant/components/select/__init__.py @@ -179,7 +179,6 @@ class SelectEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): if not options or option not in options: friendly_options: str = ", ".join(options or []) raise ServiceValidationError( - f"Option {option} is not valid for {self.entity_id}", translation_domain=DOMAIN, translation_key="not_valid_option", translation_placeholders={ diff --git a/homeassistant/components/smtp/notify.py b/homeassistant/components/smtp/notify.py index a82675a2f07..68be378f367 100644 --- a/homeassistant/components/smtp/notify.py +++ b/homeassistant/components/smtp/notify.py @@ -264,10 +264,6 @@ def _attach_file(hass, atch_name, content_id=""): file_name = os.path.basename(atch_name) url = "https://www.home-assistant.io/docs/configuration/basic/" raise ServiceValidationError( - f"Cannot send email with attachment '{file_name}' " - f"from directory '{file_path}' which is not secure to load data from. " - f"Only folders added to `{allow_list}` are accessible. " - f"See {url} for more information.", translation_domain=DOMAIN, translation_key="remote_path_not_allowed", translation_placeholders={ diff --git a/homeassistant/components/tessie/lock.py b/homeassistant/components/tessie/lock.py index ccd613af2e3..09402055ee8 100644 --- a/homeassistant/components/tessie/lock.py +++ b/homeassistant/components/tessie/lock.py @@ -112,7 +112,6 @@ class TessieCableLockEntity(TessieEntity, LockEntity): async def async_lock(self, **kwargs: Any) -> None: """Charge cable Lock cannot be manually locked.""" raise ServiceValidationError( - "Insert cable to lock", translation_domain=DOMAIN, translation_key="no_cable", ) diff --git a/homeassistant/components/todo/__init__.py b/homeassistant/components/todo/__init__.py index 0b8dd756289..74ee99b811f 100644 --- a/homeassistant/components/todo/__init__.py +++ b/homeassistant/components/todo/__init__.py @@ -107,7 +107,6 @@ def _validate_supported_features( continue if not supported_features or not supported_features & desc.required_feature: raise ServiceValidationError( - 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}, @@ -485,7 +484,6 @@ async def _async_update_todo_item(entity: TodoListEntity, call: ServiceCall) -> found = _find_by_uid_or_summary(item, entity.todo_items) if not found: raise ServiceValidationError( - f"Unable to find To-do item '{item}'", translation_domain=DOMAIN, translation_key="item_not_found", translation_placeholders={"item": item}, @@ -518,7 +516,6 @@ async def _async_remove_todo_items(entity: TodoListEntity, call: ServiceCall) -> found = _find_by_uid_or_summary(item, entity.todo_items) if not found or not found.uid: raise ServiceValidationError( - f"Unable to find To-do item '{item}'", translation_domain=DOMAIN, translation_key="item_not_found", translation_placeholders={"item": item}, diff --git a/homeassistant/components/water_heater/__init__.py b/homeassistant/components/water_heater/__init__.py index 370bb5c293c..167acb85914 100644 --- a/homeassistant/components/water_heater/__init__.py +++ b/homeassistant/components/water_heater/__init__.py @@ -368,8 +368,6 @@ class WaterHeaterEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): """Handle a set target operation mode service call.""" if self.operation_list is None: raise ServiceValidationError( - f"Operation mode {operation_mode} not valid for " - f"entity {self.entity_id}. The operation list is not defined", translation_domain=DOMAIN, translation_key="operation_list_not_defined", translation_placeholders={ @@ -380,9 +378,6 @@ class WaterHeaterEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): if operation_mode not in self.operation_list: operation_list = ", ".join(self.operation_list) raise ServiceValidationError( - f"Operation mode {operation_mode} not valid for " - f"entity {self.entity_id}. Valid " - f"operation modes are: {operation_list}", translation_domain=DOMAIN, translation_key="not_valid_operation_mode", translation_placeholders={ diff --git a/homeassistant/components/yolink/services.py b/homeassistant/components/yolink/services.py index e41e3dce260..a011d493dc9 100644 --- a/homeassistant/components/yolink/services.py +++ b/homeassistant/components/yolink/services.py @@ -36,7 +36,6 @@ def async_register_services(hass: HomeAssistant) -> None: break if entry is None or entry.state == ConfigEntryState.NOT_LOADED: raise ServiceValidationError( - "Config entry not found or not loaded!", translation_domain=DOMAIN, translation_key="invalid_config_entry", ) diff --git a/tests/components/energyzero/test_services.py b/tests/components/energyzero/test_services.py index c0b54729e03..38929d7007a 100644 --- a/tests/components/energyzero/test_services.py +++ b/tests/components/energyzero/test_services.py @@ -1,5 +1,7 @@ """Tests for the services provided by the EnergyZero integration.""" +import re + import pytest from syrupy.assertion import SnapshotAssertion import voluptuous as vol @@ -101,7 +103,7 @@ def config_entry_data( "start": "incorrect date", }, ServiceValidationError, - "Invalid datetime provided.", + "Invalid date provided. Got incorrect date", ), ( {"config_entry": True}, @@ -110,7 +112,7 @@ def config_entry_data( "end": "incorrect date", }, ServiceValidationError, - "Invalid datetime provided.", + "Invalid date provided. Got incorrect date", ), ], indirect=["config_entry_data"], @@ -125,7 +127,7 @@ async def test_service_validation( ) -> None: """Test the EnergyZero Service validation.""" - with pytest.raises(error, match=error_message): + with pytest.raises(error) as exc: await hass.services.async_call( DOMAIN, service, @@ -133,6 +135,7 @@ async def test_service_validation( blocking=True, return_response=True, ) + assert re.match(error_message, str(exc.value)) @pytest.mark.usefixtures("init_integration") diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 0c3764ce8a8..3459e6fc058 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -550,8 +550,8 @@ async def test_service_call_with_template_topic_renders_invalid_topic( blocking=True, ) assert str(exc.value) == ( - "Unable to publish: topic template 'test/{{ '+' if True else 'topic' }}/topic' " - "produced an invalid topic 'test/+/topic' after rendering " + "Unable to publish: topic template `test/{{ '+' if True else 'topic' }}/topic` " + "produced an invalid topic `test/+/topic` after rendering " "(Wildcards cannot be used in topic names)" ) assert not mqtt_mock.async_publish.called diff --git a/tests/components/todo/test_init.py b/tests/components/todo/test_init.py index 5a8f6183cbb..2b8bb858177 100644 --- a/tests/components/todo/test_init.py +++ b/tests/components/todo/test_init.py @@ -348,12 +348,12 @@ async def test_add_item_service_raises( ( {"item": "Submit forms", "description": "Submit tax forms"}, ServiceValidationError, - "does not support setting field 'description'", + "does not support setting field: description", ), ( {"item": "Submit forms", "due_date": "2023-11-17"}, ServiceValidationError, - "does not support setting field 'due_date'", + "does not support setting field: due_date", ), ( { @@ -361,7 +361,7 @@ async def test_add_item_service_raises( "due_datetime": f"2023-11-17T17:00:00{TEST_OFFSET}", }, ServiceValidationError, - "does not support setting field 'due_datetime'", + "does not support setting field: due_datetime", ), ], ) @@ -376,7 +376,7 @@ async def test_add_item_service_invalid_input( await create_mock_platform(hass, [test_entity]) - with pytest.raises(expected_exception, match=expected_error): + with pytest.raises(expected_exception) as exc: await hass.services.async_call( DOMAIN, "add_item", @@ -385,6 +385,8 @@ async def test_add_item_service_invalid_input( blocking=True, ) + assert expected_error in str(exc.value) + @pytest.mark.parametrize( ("supported_entity_feature", "item_data", "expected_item"), diff --git a/tests/components/water_heater/test_init.py b/tests/components/water_heater/test_init.py index f6f48e65480..f883cf47b19 100644 --- a/tests/components/water_heater/test_init.py +++ b/tests/components/water_heater/test_init.py @@ -175,7 +175,7 @@ async def test_operation_mode_validation( DOMAIN, SERVICE_SET_OPERATION_MODE, data, blocking=True ) assert ( - str(exc.value) == "Operation mode test not valid for entity water_heater.test. " + str(exc.value) == "Operation mode test is not valid for water_heater.test. " "The operation list is not defined" ) assert exc.value.translation_domain == DOMAIN @@ -191,7 +191,7 @@ async def test_operation_mode_validation( DOMAIN, SERVICE_SET_OPERATION_MODE, data, blocking=True ) assert ( - str(exc.value) == "Operation mode test not valid for entity water_heater.test. " + str(exc.value) == "Operation mode test is not valid for water_heater.test. " "Valid operation modes are: gas, eco" ) assert exc.value.translation_domain == DOMAIN