Remove support for excluding attributes in recorder platforms (#100679)

pull/100802/head
Erik Montnemery 2023-09-24 14:45:06 +02:00 committed by GitHub
parent 1b1901cb6d
commit 0dc21504f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 18 additions and 55 deletions

View File

@ -27,9 +27,7 @@ from .const import ( # noqa: F401
DOMAIN,
EVENT_RECORDER_5MIN_STATISTICS_GENERATED,
EVENT_RECORDER_HOURLY_STATISTICS_GENERATED,
EXCLUDE_ATTRIBUTES,
INTEGRATION_PLATFORM_COMPILE_STATISTICS,
INTEGRATION_PLATFORM_EXCLUDE_ATTRIBUTES,
INTEGRATION_PLATFORMS_LOAD_IN_RECORDER_THREAD,
SQLITE_URL_PREFIX,
SupportedDialect,
@ -132,8 +130,6 @@ def is_entity_recorded(hass: HomeAssistant, entity_id: str) -> bool:
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the recorder."""
exclude_attributes_by_domain: dict[str, set[str]] = {}
hass.data[EXCLUDE_ATTRIBUTES] = exclude_attributes_by_domain
conf = config[DOMAIN]
entity_filter = convert_include_exclude_filter(conf).get_filter()
auto_purge = conf[CONF_AUTO_PURGE]
@ -161,7 +157,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
db_retry_wait=db_retry_wait,
entity_filter=entity_filter,
exclude_event_types=exclude_event_types,
exclude_attributes_by_domain=exclude_attributes_by_domain,
)
instance.async_initialize()
instance.async_register()
@ -170,17 +165,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
websocket_api.async_setup(hass)
entity_registry.async_setup(hass)
await _async_setup_integration_platform(
hass, instance, exclude_attributes_by_domain
)
await _async_setup_integration_platform(hass, instance)
return await instance.async_db_ready
async def _async_setup_integration_platform(
hass: HomeAssistant,
instance: Recorder,
exclude_attributes_by_domain: dict[str, set[str]],
hass: HomeAssistant, instance: Recorder
) -> None:
"""Set up a recorder integration platform."""
@ -188,15 +179,6 @@ async def _async_setup_integration_platform(
hass: HomeAssistant, domain: str, platform: Any
) -> None:
"""Process a recorder platform."""
# We need to add this before as soon as the component is loaded
# to ensure by the time the state is recorded that the excluded
# attributes are known. This is safe to modify in the event loop
# since exclude_attributes_by_domain is never iterated over.
if exclude_attributes := getattr(
platform, INTEGRATION_PLATFORM_EXCLUDE_ATTRIBUTES, None
):
exclude_attributes_by_domain[domain] = exclude_attributes(hass)
# If the platform has a compile_statistics method, we need to
# add it to the recorder queue to be processed.
if any(

View File

@ -40,10 +40,6 @@ ATTR_APPLY_FILTER = "apply_filter"
KEEPALIVE_TIME = 30
EXCLUDE_ATTRIBUTES = f"{DOMAIN}_exclude_attributes_by_domain"
STATISTICS_ROWS_SCHEMA_VERSION = 23
CONTEXT_ID_AS_BINARY_SCHEMA_VERSION = 36
EVENT_TYPE_IDS_SCHEMA_VERSION = 37
@ -51,9 +47,6 @@ STATES_META_SCHEMA_VERSION = 38
LEGACY_STATES_EVENT_ID_INDEX_SCHEMA_VERSION = 28
INTEGRATION_PLATFORM_EXCLUDE_ATTRIBUTES = "exclude_attributes"
INTEGRATION_PLATFORM_COMPILE_STATISTICS = "compile_statistics"
INTEGRATION_PLATFORM_VALIDATE_STATISTICS = "validate_statistics"
INTEGRATION_PLATFORM_LIST_STATISTIC_IDS = "list_statistic_ids"

View File

@ -177,7 +177,6 @@ class Recorder(threading.Thread):
db_retry_wait: int,
entity_filter: Callable[[str], bool],
exclude_event_types: set[str],
exclude_attributes_by_domain: dict[str, set[str]],
) -> None:
"""Initialize the recorder."""
threading.Thread.__init__(self, name="Recorder")
@ -221,9 +220,7 @@ class Recorder(threading.Thread):
self.event_data_manager = EventDataManager(self)
self.event_type_manager = EventTypeManager(self)
self.states_meta_manager = StatesMetaManager(self)
self.state_attributes_manager = StateAttributesManager(
self, exclude_attributes_by_domain
)
self.state_attributes_manager = StateAttributesManager(self)
self.statistics_meta_manager = StatisticsMetaManager(self)
self.event_session: Session | None = None

View File

@ -39,7 +39,7 @@ from homeassistant.const import (
MAX_LENGTH_STATE_ENTITY_ID,
MAX_LENGTH_STATE_STATE,
)
from homeassistant.core import Context, Event, EventOrigin, State, split_entity_id
from homeassistant.core import Context, Event, EventOrigin, State
from homeassistant.helpers.entity import EntityInfo
from homeassistant.helpers.json import JSON_DUMP, json_bytes, json_bytes_strip_null
import homeassistant.util.dt as dt_util
@ -560,7 +560,6 @@ class StateAttributes(Base):
def shared_attrs_bytes_from_event(
event: Event,
entity_sources: dict[str, EntityInfo],
exclude_attrs_by_domain: dict[str, set[str]],
dialect: SupportedDialect | None,
) -> bytes:
"""Create shared_attrs from a state_changed event."""
@ -568,14 +567,7 @@ class StateAttributes(Base):
# None state means the state was removed from the state machine
if state is None:
return b"{}"
domain = split_entity_id(state.entity_id)[0]
exclude_attrs = set(ALL_DOMAIN_EXCLUDE_ATTRS)
if base_platform_attrs := exclude_attrs_by_domain.get(domain):
exclude_attrs |= base_platform_attrs
if (entity_info := entity_sources.get(state.entity_id)) and (
integration_attrs := exclude_attrs_by_domain.get(entity_info["domain"])
):
exclude_attrs |= integration_attrs
if state_info := state.state_info:
exclude_attrs |= state_info["unrecorded_attributes"]
encoder = json_bytes_strip_null if dialect == PSQL_DIALECT else json_bytes

View File

@ -34,13 +34,10 @@ _LOGGER = logging.getLogger(__name__)
class StateAttributesManager(BaseLRUTableManager[StateAttributes]):
"""Manage the StateAttributes table."""
def __init__(
self, recorder: Recorder, exclude_attributes_by_domain: dict[str, set[str]]
) -> None:
def __init__(self, recorder: Recorder) -> None:
"""Initialize the event type manager."""
super().__init__(recorder, CACHE_SIZE)
self.active = True # always active
self._exclude_attributes_by_domain = exclude_attributes_by_domain
self._entity_sources = entity_sources(recorder.hass)
def serialize_from_event(self, event: Event) -> bytes | None:
@ -49,7 +46,6 @@ class StateAttributesManager(BaseLRUTableManager[StateAttributes]):
return StateAttributes.shared_attrs_bytes_from_event(
event,
self._entity_sources,
self._exclude_attributes_by_domain,
self.recorder.dialect_name,
)
except JSON_ENCODE_EXCEPTIONS as ex:

View File

@ -119,7 +119,6 @@ def _default_recorder(hass):
db_retry_wait=3,
entity_filter=CONFIG_SCHEMA({DOMAIN: {}}),
exclude_event_types=set(),
exclude_attributes_by_domain={},
)
@ -2264,17 +2263,14 @@ async def test_connect_args_priority(hass: HomeAssistant, config_url) -> None:
assert connect_params[0]["charset"] == "utf8mb4"
@pytest.mark.parametrize("core_state", [CoreState.starting, CoreState.running])
async def test_excluding_attributes_by_integration(
recorder_mock: Recorder,
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
core_state: CoreState,
) -> None:
"""Test that an integration's recorder platform can exclude attributes."""
hass.state = core_state
"""Test that an entity can exclude attributes from being recorded."""
state = "restoring_from_db"
attributes = {"test_attr": 5, "excluded": 10}
attributes = {"test_attr": 5, "excluded_component": 10, "excluded_integration": 20}
mock_platform(
hass,
"fake_integration.recorder",
@ -2284,10 +2280,17 @@ async def test_excluding_attributes_by_integration(
hass.bus.async_fire(EVENT_COMPONENT_LOADED, {"component": "fake_integration"})
await hass.async_block_till_done()
class EntityWithExcludedAttributes(MockEntity):
_entity_component_unrecorded_attributes = frozenset({"excluded_component"})
_unrecorded_attributes = frozenset({"excluded_integration"})
entity_id = "test.fake_integration_recorder"
platform = MockEntityPlatform(hass, platform_name="fake_integration")
entity_platform = MockEntity(entity_id=entity_id, extra_state_attributes=attributes)
await platform.async_add_entities([entity_platform])
entity_platform = MockEntityPlatform(hass, platform_name="fake_integration")
entity = EntityWithExcludedAttributes(
entity_id=entity_id,
extra_state_attributes=attributes,
)
await entity_platform.async_add_entities([entity])
await hass.async_block_till_done()
await async_wait_recording_done(hass)

View File

@ -77,7 +77,7 @@ def test_from_event_to_db_state_attributes() -> None:
dialect = SupportedDialect.MYSQL
db_attrs.shared_attrs = StateAttributes.shared_attrs_bytes_from_event(
event, {}, {}, dialect
event, {}, dialect
)
assert db_attrs.to_native() == attrs