Skip to content

Commit

Permalink
Add filter to translation event listeners to avoid creating tasks (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco committed Feb 16, 2024
1 parent 6f74ea9 commit 2cb0249
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 15 deletions.
62 changes: 48 additions & 14 deletions homeassistant/helpers/translation.py
Expand Up @@ -5,7 +5,7 @@
from collections.abc import Iterable, Mapping
import logging
import string
from typing import Any
from typing import TYPE_CHECKING, Any

from homeassistant.const import (
EVENT_COMPONENT_LOADED,
Expand Down Expand Up @@ -205,6 +205,11 @@ def __init__(self, hass: HomeAssistant) -> None:
self.cache: dict[str, dict[str, dict[str, dict[str, str]]]] = {}
self.lock = asyncio.Lock()

@callback
def async_is_loaded(self, language: str, components: set[str]) -> bool:
"""Return if the given components are loaded for the language."""
return components.issubset(self.loaded.get(language, set()))

async def async_load(
self,
language: str,
Expand Down Expand Up @@ -465,20 +470,41 @@ def async_setup(hass: HomeAssistant) -> None:
Listeners load translations for every loaded component and after config change.
"""
cache = _TranslationCache(hass)
current_language = hass.config.language
hass.data[TRANSLATION_FLATTEN_CACHE] = cache

hass.data[TRANSLATION_FLATTEN_CACHE] = _TranslationCache(hass)

async def load_translations(event: Event) -> None:
if "language" in event.data:
language = hass.config.language
_LOGGER.debug("Loading translations for language: %s", language)
await _async_load_state_translations_to_cache(hass, language, None)
@callback
def _async_load_translations_filter(event: Event) -> bool:
"""Filter out unwanted events."""
nonlocal current_language
if (
new_language := event.data.get("language")
) and new_language != current_language:
current_language = new_language
return True
return False

async def _async_load_translations(event: Event) -> None:
new_language = event.data["language"]
_LOGGER.debug("Loading translations for language: %s", new_language)
await _async_load_state_translations_to_cache(hass, new_language, None)

async def load_translations_for_component(event: Event) -> None:
component = event.data.get("component")
@callback
def _async_load_translations_for_component_filter(event: Event) -> bool:
"""Filter out unwanted events."""
component: str | None = event.data.get("component")
# Platforms don't have their own translations, skip them
if component is None or "." in str(component):
return
return bool(
component
and "." not in component
and not cache.async_is_loaded(hass.config.language, {component})
)

async def _async_load_translations_for_component(event: Event) -> None:
component: str | None = event.data.get("component")
if TYPE_CHECKING:
assert component is not None
language = hass.config.language
_LOGGER.debug(
"Loading translations for language: %s and component: %s",
Expand All @@ -487,8 +513,16 @@ async def load_translations_for_component(event: Event) -> None:
)
await _async_load_state_translations_to_cache(hass, language, component)

hass.bus.async_listen(EVENT_COMPONENT_LOADED, load_translations_for_component)
hass.bus.async_listen(EVENT_CORE_CONFIG_UPDATE, load_translations)
hass.bus.async_listen(
EVENT_COMPONENT_LOADED,
_async_load_translations_for_component,
event_filter=_async_load_translations_for_component_filter,
)
hass.bus.async_listen(
EVENT_CORE_CONFIG_UPDATE,
_async_load_translations,
event_filter=_async_load_translations_filter,
)


@callback
Expand Down
11 changes: 10 additions & 1 deletion tests/helpers/test_translation.py
Expand Up @@ -602,12 +602,21 @@ async def test_setup(hass: HomeAssistant):
await hass.async_block_till_done()
mock.assert_not_called()

# Should not be called if the language is the current language
with patch(
"homeassistant.helpers.translation._async_load_state_translations_to_cache",
) as mock:
hass.bus.async_fire(EVENT_CORE_CONFIG_UPDATE, {"language": "en"})
await hass.async_block_till_done()
mock.assert_called_once_with(hass, hass.config.language, None)
mock.assert_not_called()

# Should be called if the language is different
with patch(
"homeassistant.helpers.translation._async_load_state_translations_to_cache",
) as mock:
hass.bus.async_fire(EVENT_CORE_CONFIG_UPDATE, {"language": "es"})
await hass.async_block_till_done()
mock.assert_called_once_with(hass, "es", None)

with patch(
"homeassistant.helpers.translation._async_load_state_translations_to_cache",
Expand Down

0 comments on commit 2cb0249

Please sign in to comment.