Skip to content

Commit

Permalink
Use cached_property for expensive, one time calculated properties (#2075
Browse files Browse the repository at this point in the history
)
  • Loading branch information
SukramJ authored Feb 9, 2025
1 parent c0a371a commit 2d6281c
Show file tree
Hide file tree
Showing 9 changed files with 22 additions and 25 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Version 2025.2.7 (2025-02-08)

- Remove @cache and @lru_cache annotations
- Use @cached_property for expensive, one time calculated properties

# Version 2025.2.6 (2025-02-08)

Expand Down
5 changes: 4 additions & 1 deletion hahomematic/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ def get_service_calls(obj: object) -> dict[str, Callable]:
return {
name: getattr(obj, name)
for name in dir(obj)
if not name.startswith("_") and callable(getattr(obj, name)) and hasattr(getattr(obj, name), "ha_service")
if not name.startswith("_")
and name not in ("service_methods", "service_method_names")
and callable(getattr(obj, name))
and hasattr(getattr(obj, name), "ha_service")
}


Expand Down
5 changes: 2 additions & 3 deletions hahomematic/model/calculated/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from collections.abc import Callable
from datetime import datetime
from functools import cached_property
import logging
from typing import Any, Final, cast

Expand All @@ -17,7 +18,6 @@
ParameterType,
ParamsetKey,
)
from hahomematic.decorators import get_service_calls
from hahomematic.model import device as hmd
from hahomematic.model.custom import definition as hmed
from hahomematic.model.data_point import BaseDataPoint, NoneTypeDataPoint
Expand Down Expand Up @@ -66,7 +66,6 @@ def __init__(
self._unit: str | None = None
self._multiplier: float = 1.0
self._init_data_point_fields()
self._service_methods = get_service_calls(obj=self)

def _init_data_point_fields(self) -> None:
"""Init the data point fields."""
Expand Down Expand Up @@ -112,7 +111,7 @@ def default(self) -> ParameterT:
"""Return default value."""
return self._default

@property
@cached_property
def dpk(self) -> DataPointKey:
"""Return data_point key value."""
return DataPointKey(
Expand Down
2 changes: 0 additions & 2 deletions hahomematic/model/custom/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from typing import Any, Final, cast

from hahomematic.const import CALLBACK_TYPE, INIT_DATETIME, CallSource, DataPointKey, DataPointUsage
from hahomematic.decorators import get_service_calls
from hahomematic.model import device as hmd
from hahomematic.model.custom import definition as hmed
from hahomematic.model.custom.const import CDPD, DeviceProfile, Field
Expand Down Expand Up @@ -59,7 +58,6 @@ def __init__(
self._data_points: Final[dict[Field, hmge.GenericDataPoint]] = {}
self._init_data_points()
self._init_data_point_fields()
self._service_methods = get_service_calls(obj=self)

def _init_data_point_fields(self) -> None:
"""Init the data point fields."""
Expand Down
20 changes: 9 additions & 11 deletions hahomematic/model/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from collections.abc import Callable, Mapping
from contextvars import Token
from datetime import datetime
from functools import partial, wraps
from functools import cached_property, partial, wraps
from inspect import getfullargspec
import logging
from typing import Any, Final, cast
Expand Down Expand Up @@ -128,7 +128,6 @@ def __init__(self, central: hmcu.CentralUnit, unique_id: str) -> None:
self._refreshed_at: datetime = INIT_DATETIME
self._temporary_modified_at: datetime = INIT_DATETIME
self._temporary_refreshed_at: datetime = INIT_DATETIME
self._service_methods: dict[str, Callable] = {}

@state_property
def additional_information(self) -> dict[str, Any]:
Expand Down Expand Up @@ -199,7 +198,7 @@ def usage(self) -> DataPointUsage:
"""Return the data_point usage."""
return DataPointUsage.DATA_POINT

@property
@cached_property
def enabled_default(self) -> bool:
"""Return, if data_point should be enabled based on usage attribute."""
return self.usage in (
Expand All @@ -225,15 +224,15 @@ def state_path(self) -> str:
return self._path_data.state_path

# @property
@property
@cached_property
def service_methods(self) -> Mapping[str, Callable]:
"""Return all service methods."""
return self._service_methods
return get_service_calls(obj=self)

@property
@cached_property
def service_method_names(self) -> tuple[str, ...]:
"""Return all service methods."""
return tuple(self._service_methods.keys())
return tuple(self.service_methods.keys())

def register_internal_data_point_updated_callback(self, cb: Callable) -> CALLBACK_TYPE:
"""Register internal data_point updated callback."""
Expand Down Expand Up @@ -460,7 +459,6 @@ def __init__(
self._state_uncertain: bool = True
self._is_forced_sensor: bool = False
self._assign_parameter_data(parameter_data=parameter_data)
self._service_methods = get_service_calls(obj=self)

def _assign_parameter_data(self, parameter_data: ParameterData) -> None:
"""Assign parameter data to instance variables."""
Expand Down Expand Up @@ -503,7 +501,7 @@ def is_un_ignored(self) -> bool:
"""Return if the parameter is un ignored."""
return self._is_un_ignored

@property
@cached_property
def dpk(self) -> DataPointKey:
"""Return data_point key value."""
return DataPointKey(
Expand Down Expand Up @@ -543,7 +541,7 @@ def raw_unit(self) -> str | None:
"""Return raw unit value."""
return self._raw_unit

@property
@cached_property
def requires_polling(self) -> bool:
"""Return whether the data_point requires polling."""
return not self._channel.device.client.supports_push_updates or (
Expand Down Expand Up @@ -631,7 +629,7 @@ def visible(self) -> bool:
"""Return the if data_point is visible in ccu."""
return self._visible

@property
@cached_property
def _enabled_by_channel_operation_mode(self) -> bool | None:
"""Return, if the data_point/event must be enabled."""
if self._channel.type_name not in _CONFIGURABLE_CHANNEL:
Expand Down
4 changes: 2 additions & 2 deletions hahomematic/model/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from collections.abc import Callable, Mapping
from copy import copy
from datetime import datetime
from functools import partial
from functools import cached_property, partial
import logging
import os
import random
Expand Down Expand Up @@ -389,7 +389,7 @@ async def remove_central_links(self) -> None:
for channel in self._channels.values():
await channel.remove_central_link()

@property
@cached_property
def relevant_for_central_link_management(self) -> bool:
"""Return if channel is relevant for central link management."""
return (
Expand Down
3 changes: 2 additions & 1 deletion hahomematic/model/generic/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from functools import cached_property
import logging
from typing import Any, Final

Expand Down Expand Up @@ -36,7 +37,7 @@ def __init__(
parameter_data=parameter_data,
)

@property
@cached_property
def usage(self) -> DataPointUsage:
"""Return the data_point usage."""
if self._is_forced_sensor or self._is_un_ignored:
Expand Down
4 changes: 1 addition & 3 deletions hahomematic/model/hub/data_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
SystemVariableData,
SysvarType,
)
from hahomematic.decorators import get_service_calls, inspector
from hahomematic.decorators import inspector
from hahomematic.model.data_point import CallbackDataPoint
from hahomematic.model.decorators import config_property, state_property
from hahomematic.model.device import Channel
Expand Down Expand Up @@ -119,7 +119,6 @@ def __init__(
self._current_value: SYSVAR_TYPE = data.value
self._previous_value: SYSVAR_TYPE = None
self._temporary_value: SYSVAR_TYPE = None
self._service_methods = get_service_calls(obj=self)

@property
def data_type(self) -> SysvarType | None:
Expand Down Expand Up @@ -263,7 +262,6 @@ def __init__(
self._is_internal: bool = data.is_internal
self._last_execute_time: str = data.last_execute_time
self._state_uncertain: bool = True
self._service_methods = get_service_calls(obj=self)

@state_property
def is_active(self) -> bool:
Expand Down
3 changes: 1 addition & 2 deletions hahomematic/model/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
DataPointCategory,
Interface,
)
from hahomematic.decorators import get_service_calls, inspector
from hahomematic.decorators import inspector
from hahomematic.exceptions import HaHomematicException
from hahomematic.model import device as hmd
from hahomematic.model.data_point import CallbackDataPoint
Expand Down Expand Up @@ -42,7 +42,6 @@ def __init__(self, device: hmd.Device) -> None:
unique_id=generate_unique_id(central=device.central, address=device.address, parameter="Update"),
)
self._set_modified_at()
self._service_methods = get_service_calls(obj=self)

@state_property
def available(self) -> bool:
Expand Down

0 comments on commit 2d6281c

Please sign in to comment.