Source code for aioafero.v1.models.update_comparison
"""Helpers for suppressing unchanged resource updates."""
from __future__ import annotations
from typing import Any, Protocol, runtime_checkable
from aioafero.v1.models.features import DimmingFeature, OnFeature, OpenFeature
[docs]
@runtime_checkable
class SupportsFeatureUpdateComparison(Protocol):
"""Resource that can resolve Put fields against cached state."""
[docs]
def feature_for_update_comparison(
self, field_name: str, put_feature: Any | None
) -> Any | None:
"""Return the cached feature to compare with ``put_feature``."""
[docs]
def default_feature_for_update_comparison(
elem: Any, field_name: str, put_feature: Any | None
) -> Any | None:
"""Look up a dict-backed feature by instance when Put targets one entry."""
current = getattr(elem, field_name, None)
if isinstance(current, dict) and put_feature is not None:
function_instance = getattr(put_feature, "function_instance", None)
if function_instance in current:
return current[function_instance]
function_class = getattr(put_feature, "function_class", None)
mapped_key = (function_class, function_instance)
if mapped_key in current:
return current[mapped_key]
return current
[docs]
def features_equivalent_for_update(
put_feature: Any | None, cached_feature: Any | None
) -> bool:
"""Return True when Put would not change wire-relevant cached state.
Compares semantic fields for common feature types so synthetic comparison
objects (e.g. channel toggles) stay stable if dataclasses gain metadata.
"""
if put_feature is cached_feature:
return True
if put_feature is None or cached_feature is None:
return False
if isinstance(put_feature, OnFeature) and isinstance(cached_feature, OnFeature):
return (
put_feature.on == cached_feature.on
and put_feature.function_class == cached_feature.function_class
and put_feature.function_instance == cached_feature.function_instance
)
if isinstance(put_feature, OpenFeature) and isinstance(cached_feature, OpenFeature):
return (
put_feature.open == cached_feature.open
and put_feature.function_class == cached_feature.function_class
and put_feature.function_instance == cached_feature.function_instance
)
if isinstance(put_feature, DimmingFeature) and isinstance(
cached_feature, DimmingFeature
):
return (
put_feature.brightness == cached_feature.brightness
and put_feature.function_instance == cached_feature.function_instance
)
return put_feature == cached_feature
[docs]
def resolve_feature_for_update_comparison(
elem: Any, field_name: str, put_feature: Any | None
) -> Any | None:
"""Resolve the cached feature to compare against a Put field."""
if isinstance(elem, SupportsFeatureUpdateComparison):
return elem.feature_for_update_comparison(field_name, put_feature)
return default_feature_for_update_comparison(elem, field_name, put_feature)