Skip to content

Commit

Permalink
Add exception-translations rule to quality_scale pytest validation (h…
Browse files Browse the repository at this point in the history
…ome-assistant#131914)

* Add exception-translations rule to quality_scale pytest validation

* Adjust

* Return empty dict if file is missing

* Fix

* Improve typing

* Address comments

* Update tests/components/conftest.py

* Update tests/components/conftest.py

* Update tests/components/conftest.py

---------

Co-authored-by: Robert Resch <[email protected]>
  • Loading branch information
epenet and edenhaus authored Jan 9, 2025
1 parent dd57c75 commit ee865d2
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 4 deletions.
31 changes: 29 additions & 2 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
from contextlib import asynccontextmanager, contextmanager, suppress
from datetime import UTC, datetime, timedelta
from enum import Enum
from enum import Enum, StrEnum
import functools as ft
from functools import lru_cache
from io import StringIO
Expand Down Expand Up @@ -108,7 +108,7 @@
from homeassistant.util.signal_type import SignalType
import homeassistant.util.ulid as ulid_util
from homeassistant.util.unit_system import METRIC_SYSTEM
import homeassistant.util.yaml.loader as yaml_loader
from homeassistant.util.yaml import load_yaml_dict, loader as yaml_loader

from .testing_config.custom_components.test_constant_deprecation import (
import_deprecated_constant,
Expand All @@ -122,6 +122,14 @@
CLIENT_REDIRECT_URI = "https://example.com/app/callback"


class QualityScaleStatus(StrEnum):
"""Source of core configuration."""

DONE = "done"
EXEMPT = "exempt"
TODO = "todo"


async def async_get_device_automations(
hass: HomeAssistant,
automation_type: device_automation.DeviceAutomationType,
Expand Down Expand Up @@ -1832,3 +1840,22 @@ def reset_translation_cache(hass: HomeAssistant, components: list[str]) -> None:
for loaded_components in loaded_categories.values():
for component_to_unload in components:
loaded_components.pop(component_to_unload, None)


@lru_cache
def get_quality_scale(integration: str) -> dict[str, QualityScaleStatus]:
"""Load quality scale for integration."""
quality_scale_file = pathlib.Path(
f"homeassistant/components/{integration}/quality_scale.yaml"
)
if not quality_scale_file.exists():
return {}
raw = load_yaml_dict(quality_scale_file)
return {
rule: (
QualityScaleStatus(details)
if isinstance(details, str)
else QualityScaleStatus(details["status"])
)
for rule, details in raw["rules"].items()
}
30 changes: 28 additions & 2 deletions tests/components/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from functools import lru_cache
from importlib.util import find_spec
from pathlib import Path
import re
import string
from typing import TYPE_CHECKING, Any
from unittest.mock import AsyncMock, MagicMock, patch
Expand Down Expand Up @@ -42,6 +43,8 @@
from homeassistant.helpers.translation import async_get_translations
from homeassistant.util import yaml

from tests.common import QualityScaleStatus, get_quality_scale

if TYPE_CHECKING:
from homeassistant.components.hassio import AddonManager

Expand All @@ -51,6 +54,9 @@
from .sensor.common import MockSensor
from .switch.common import MockSwitch

# Regex for accessing the integration name from the test path
RE_REQUEST_DOMAIN = re.compile(r".*tests\/components\/([^/]+)\/.*")


@pytest.fixture(scope="session", autouse=find_spec("zeroconf") is not None)
def patch_zeroconf_multiple_catcher() -> Generator[None]:
Expand Down Expand Up @@ -804,12 +810,29 @@ async def _check_create_issue_translations(
)


def _get_request_quality_scale(
request: pytest.FixtureRequest, rule: str
) -> QualityScaleStatus:
if not (match := RE_REQUEST_DOMAIN.match(str(request.path))):
return QualityScaleStatus.TODO
integration = match.groups(1)[0]
return get_quality_scale(integration).get(rule, QualityScaleStatus.TODO)


async def _check_exception_translation(
hass: HomeAssistant,
exception: HomeAssistantError,
translation_errors: dict[str, str],
request: pytest.FixtureRequest,
) -> None:
if exception.translation_key is None:
if (
_get_request_quality_scale(request, "exception-translations")
is QualityScaleStatus.DONE
):
translation_errors["quality_scale"] = (
f"Found untranslated {type(exception).__name__} exception: {exception}"
)
return
await _validate_translation(
hass,
Expand All @@ -823,13 +846,14 @@ async def _check_exception_translation(

@pytest.fixture(autouse=True)
async def check_translations(
ignore_translations: str | list[str],
ignore_translations: str | list[str], request: pytest.FixtureRequest
) -> AsyncGenerator[None]:
"""Check that translation requirements are met.
Current checks:
- data entry flow results (ConfigFlow/OptionsFlow/RepairFlow)
- issue registry entries
- action (service) exceptions
"""
if not isinstance(ignore_translations, list):
ignore_translations = [ignore_translations]
Expand Down Expand Up @@ -887,7 +911,9 @@ async def _service_registry_async_call(
)
except HomeAssistantError as err:
translation_coros.add(
_check_exception_translation(self._hass, err, translation_errors)
_check_exception_translation(
self._hass, err, translation_errors, request
)
)
raise

Expand Down

0 comments on commit ee865d2

Please sign in to comment.