Deprecate legacy light module is_capability checks (#1297)

Deprecate the `is_color`, `is_dimmable`, `is_variable_color_temp`, `valid_temperate_range`,
and `has_effects` attributes from the `Light` module, as consumers should use
`has_feature("hsv")`, `has_feature("brightness")`, `has_feature("color_temp")`,
`get_feature("color_temp").range`, and `Module.LightEffect in dev.modules` respectively.

Calling the deprecated attributes will emit a `DeprecationWarning`
and type checkers will fail them.
This commit is contained in:
Steven B.
2025-01-22 10:26:37 +00:00
committed by GitHub
parent a03a4b1d63
commit fa0f7157c6
5 changed files with 161 additions and 109 deletions

View File

@@ -65,8 +65,10 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Annotated, NamedTuple
from typing import TYPE_CHECKING, Annotated, Any, NamedTuple
from warnings import warn
from ..exceptions import KasaException
from ..module import FeatureAttribute, Module
@@ -100,34 +102,6 @@ class HSV(NamedTuple):
class Light(Module, ABC):
"""Base class for TP-Link Light."""
@property
@abstractmethod
def is_dimmable(self) -> bool:
"""Whether the light supports brightness changes."""
@property
@abstractmethod
def is_color(self) -> bool:
"""Whether the bulb supports color changes."""
@property
@abstractmethod
def is_variable_color_temp(self) -> bool:
"""Whether the bulb supports color temperature changes."""
@property
@abstractmethod
def valid_temperature_range(self) -> ColorTempRange:
"""Return the device-specific white temperature range (in Kelvin).
:return: White temperature range in Kelvin (minimum, maximum)
"""
@property
@abstractmethod
def has_effects(self) -> bool:
"""Return True if the device supports effects."""
@property
@abstractmethod
def hsv(self) -> Annotated[HSV, FeatureAttribute()]:
@@ -197,3 +171,44 @@ class Light(Module, ABC):
@abstractmethod
async def set_state(self, state: LightState) -> dict:
"""Set the light state."""
def _deprecated_valid_temperature_range(self) -> ColorTempRange:
if not (temp := self.get_feature("color_temp")):
raise KasaException("Color temperature not supported")
return ColorTempRange(temp.minimum_value, temp.maximum_value)
def _deprecated_attributes(self, dep_name: str) -> str | None:
map: dict[str, str] = {
"is_color": "hsv",
"is_dimmable": "brightness",
"is_variable_color_temp": "color_temp",
}
return map.get(dep_name)
if not TYPE_CHECKING:
def __getattr__(self, name: str) -> Any:
if name == "valid_temperature_range":
msg = (
"valid_temperature_range is deprecated, use "
'get_feature("color_temp") minimum_value '
" and maximum_value instead"
)
warn(msg, DeprecationWarning, stacklevel=2)
res = self._deprecated_valid_temperature_range()
return res
if name == "has_effects":
msg = (
"has_effects is deprecated, check `Module.LightEffect "
"in device.modules` instead"
)
warn(msg, DeprecationWarning, stacklevel=2)
return Module.LightEffect in self._device.modules
if attr := self._deprecated_attributes(name):
msg = f'{name} is deprecated, use has_feature("{attr}") instead'
warn(msg, DeprecationWarning, stacklevel=2)
return self.has_feature(attr)
raise AttributeError(f"Energy module has no attribute {name!r}")