Block Capability and State attributes for template sensor attributes but allow options (#180396)

This commit is contained in:
Petro31
2026-08-28 19:14:17 +02:00
committed by GitHub
parent 3cf056ddb2
commit a633baf481
3 changed files with 69 additions and 2 deletions
+7 -1
View File
@@ -16,6 +16,8 @@ from homeassistant.components.sensor import (
STATE_CLASSES_SCHEMA,
RestoreSensor,
SensorDeviceClass,
SensorEntityCapabilityAttribute,
SensorEntityStateAttribute,
SensorExtraStoredData,
SensorStateClass,
)
@@ -70,7 +72,11 @@ SENSOR_COMMON_SCHEMA = vol.Schema(
}
)
_BLOCKED_ATTRIBUTES = tcv.BlockedTemplateAttributes(device_class=True)
_BLOCKED_ATTRIBUTES = tcv.BlockedTemplateAttributes(
attributes=(SensorEntityCapabilityAttribute, SensorEntityStateAttribute),
device_class=True,
allowed_attributes=(SensorEntityCapabilityAttribute.OPTIONS,),
)
SENSOR_YAML_SCHEMA = vol.All(
vol.Schema(
@@ -32,6 +32,7 @@ class BlockedTemplateAttributes:
*,
attributes: tuple[type[StrEnum], ...] | type[StrEnum] | None = None,
device_class: bool = False,
allowed_attributes: tuple[StrEnum | str, ...] | None = None,
) -> None:
"""Initialize."""
blocked_attributes: set[str]
@@ -42,6 +43,9 @@ class BlockedTemplateAttributes:
else:
blocked_attributes = set(attributes)
if allowed_attributes:
blocked_attributes -= set(allowed_attributes)
if device_class:
blocked_attributes.add("device_class")
+58 -1
View File
@@ -2,6 +2,8 @@
from asyncio import Event
from datetime import datetime
from itertools import chain
from typing import Any
from unittest.mock import ANY, patch
import pytest
@@ -9,6 +11,10 @@ from syrupy.assertion import SnapshotAssertion
from homeassistant.bootstrap import async_from_config_dict
from homeassistant.components import sensor, template
from homeassistant.components.sensor import (
SensorEntityCapabilityAttribute,
SensorEntityStateAttribute,
)
from homeassistant.components.template import DOMAIN
from homeassistant.const import (
ATTR_ENTITY_PICTURE,
@@ -1953,7 +1959,19 @@ async def test_attributes_template(
)
@pytest.mark.parametrize("attribute", ["device_class"])
@pytest.mark.parametrize(
"attribute",
[
*list(
chain(
set(SensorEntityCapabilityAttribute)
- {SensorEntityCapabilityAttribute.OPTIONS},
SensorEntityStateAttribute,
)
),
"device_class",
],
)
@pytest.mark.parametrize(
"style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER]
)
@@ -1979,3 +1997,42 @@ async def test_attributes_template_with_blocked_attributes(
error = f"Unsupported attribute(s) found for {TEST_SENSOR.entity_id}: {attribute}"
assert error in caplog.text
@pytest.mark.parametrize(
("attribute", "set_state", "expected"),
[(SensorEntityCapabilityAttribute.OPTIONS, ["a"], ["a"])],
)
@pytest.mark.parametrize(
"style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER]
)
async def test_attributes_template_with_allowed_attributes(
hass: HomeAssistant,
style: ConfigurationStyle,
attribute: str,
set_state: Any,
expected: Any,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test blocked attributes for a single attributes template."""
await setup_entity(
hass,
TEST_SENSOR,
style,
1,
{
"state": "{{ 'x' }}",
"attributes": f"{{{{ dict({attribute}=state_attr('{TEST_ATTRIBUTE_ENTITY_ID}', '{attribute}')) }}}}",
},
)
await async_trigger(
hass, TEST_ATTRIBUTE_ENTITY_ID, "anything", {attribute: set_state}
)
state = hass.states.get(TEST_SENSOR.entity_id)
assert state.state == "x"
assert state.attributes[attribute] == expected
error = f"Unsupported attribute(s) found for {TEST_SENSOR.entity_id}: {attribute}"
assert error not in caplog.text