Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate light entity to use contains for LightEntityFeature with deprecation warnings #106622

Merged
merged 2 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 50 additions & 17 deletions homeassistant/components/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,25 +345,25 @@ def filter_turn_off_params(
light: LightEntity, params: dict[str, Any]
) -> dict[str, Any]:
"""Filter out params not used in turn off or not supported by the light."""
supported_features = light.supported_features
supported_features = light.supported_features_compat

if not supported_features & LightEntityFeature.FLASH:
if LightEntityFeature.FLASH not in supported_features:
params.pop(ATTR_FLASH, None)
if not supported_features & LightEntityFeature.TRANSITION:
if LightEntityFeature.TRANSITION not in supported_features:
params.pop(ATTR_TRANSITION, None)

return {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)}


def filter_turn_on_params(light: LightEntity, params: dict[str, Any]) -> dict[str, Any]:
"""Filter out params not supported by the light."""
supported_features = light.supported_features
supported_features = light.supported_features_compat

if not supported_features & LightEntityFeature.EFFECT:
if LightEntityFeature.EFFECT not in supported_features:
params.pop(ATTR_EFFECT, None)
if not supported_features & LightEntityFeature.FLASH:
if LightEntityFeature.FLASH not in supported_features:
params.pop(ATTR_FLASH, None)
if not supported_features & LightEntityFeature.TRANSITION:
if LightEntityFeature.TRANSITION not in supported_features:
params.pop(ATTR_TRANSITION, None)

supported_color_modes = (
Expand Down Expand Up @@ -989,7 +989,7 @@ def effect(self) -> str | None:
def capability_attributes(self) -> dict[str, Any]:
"""Return capability attributes."""
data: dict[str, Any] = {}
supported_features = self.supported_features
supported_features = self.supported_features_compat
supported_color_modes = self._light_internal_supported_color_modes

if ColorMode.COLOR_TEMP in supported_color_modes:
Expand All @@ -1007,7 +1007,7 @@ def capability_attributes(self) -> dict[str, Any]:
data[ATTR_MAX_MIREDS] = color_util.color_temperature_kelvin_to_mired(
self.min_color_temp_kelvin
)
if supported_features & LightEntityFeature.EFFECT:
if LightEntityFeature.EFFECT in supported_features:
data[ATTR_EFFECT_LIST] = self.effect_list

data[ATTR_SUPPORTED_COLOR_MODES] = sorted(supported_color_modes)
Expand Down Expand Up @@ -1061,8 +1061,9 @@ def _light_internal_convert_color(
def state_attributes(self) -> dict[str, Any] | None:
"""Return state attributes."""
data: dict[str, Any] = {}
supported_features = self.supported_features
supported_features = self.supported_features_compat
supported_color_modes = self._light_internal_supported_color_modes
supported_features_value = supported_features.value
color_mode = self._light_internal_color_mode if self.is_on else None

if color_mode and color_mode not in supported_color_modes:
Expand All @@ -1081,7 +1082,7 @@ def state_attributes(self) -> dict[str, Any] | None:
data[ATTR_BRIGHTNESS] = self.brightness
else:
data[ATTR_BRIGHTNESS] = None
elif supported_features & SUPPORT_BRIGHTNESS:
elif supported_features_value & SUPPORT_BRIGHTNESS:
# Backwards compatibility for ambiguous / incomplete states
# Add warning in 2021.6, remove in 2021.10
if self.is_on:
Expand All @@ -1103,7 +1104,7 @@ def state_attributes(self) -> dict[str, Any] | None:
else:
data[ATTR_COLOR_TEMP_KELVIN] = None
data[ATTR_COLOR_TEMP] = None
elif supported_features & SUPPORT_COLOR_TEMP:
elif supported_features_value & SUPPORT_COLOR_TEMP:
# Backwards compatibility
# Add warning in 2021.6, remove in 2021.10
if self.is_on:
Expand Down Expand Up @@ -1133,7 +1134,7 @@ def state_attributes(self) -> dict[str, Any] | None:
if color_mode:
data.update(self._light_internal_convert_color(color_mode))

if supported_features & LightEntityFeature.EFFECT:
if LightEntityFeature.EFFECT in supported_features:
data[ATTR_EFFECT] = self.effect if self.is_on else None

return data
Expand All @@ -1146,14 +1147,15 @@ def _light_internal_supported_color_modes(self) -> set[ColorMode] | set[str]:

# Backwards compatibility for supported_color_modes added in 2021.4
# Add warning in 2021.6, remove in 2021.10
supported_features = self.supported_features
supported_features = self.supported_features_compat
supported_features_value = supported_features.value
supported_color_modes: set[ColorMode] = set()

if supported_features & SUPPORT_COLOR_TEMP:
if supported_features_value & SUPPORT_COLOR_TEMP:
supported_color_modes.add(ColorMode.COLOR_TEMP)
if supported_features & SUPPORT_COLOR:
if supported_features_value & SUPPORT_COLOR:
supported_color_modes.add(ColorMode.HS)
if supported_features & SUPPORT_BRIGHTNESS and not supported_color_modes:
if not supported_color_modes and supported_features_value & SUPPORT_BRIGHTNESS:
supported_color_modes = {ColorMode.BRIGHTNESS}

if not supported_color_modes:
Expand All @@ -1170,3 +1172,34 @@ def supported_color_modes(self) -> set[ColorMode] | set[str] | None:
def supported_features(self) -> LightEntityFeature:
"""Flag supported features."""
return self._attr_supported_features

@property
def supported_features_compat(self) -> LightEntityFeature:
"""Return the supported features as LightEntityFeature.

Remove this compatibility shim in 2025.1 or later.
"""
features = self.supported_features
if type(features) is not int: # noqa: E721
return features
new_features = LightEntityFeature(features)
if self._deprecated_supported_features_reported is True:
return new_features
self._deprecated_supported_features_reported = True
report_issue = self._suggest_report_issue()
report_issue += (
" and reference "
"https://developers.home-assistant.io/blog/2023/12/28/support-feature-magic-numbers-deprecation"
)
_LOGGER.warning(
(
"Entity %s (%s) is using deprecated supported features"
" values which will be removed in HA Core 2025.1. Instead it should use"
" %s and color modes, please %s"
),
self.entity_id,
type(self),
repr(new_features),
report_issue,
)
return new_features
21 changes: 21 additions & 0 deletions tests/components/light/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -2589,3 +2589,24 @@ def test_filter_supported_color_modes() -> None:
# ColorMode.BRIGHTNESS has priority over ColorMode.ONOFF
supported = {light.ColorMode.ONOFF, light.ColorMode.BRIGHTNESS}
assert light.filter_supported_color_modes(supported) == {light.ColorMode.BRIGHTNESS}


def test_deprecated_supported_features_ints(caplog: pytest.LogCaptureFixture) -> None:
"""Test deprecated supported features ints."""

class MockLightEntityEntity(light.LightEntity):
@property
def supported_features(self) -> int:
"""Return supported features."""
return 1

entity = MockLightEntityEntity()
assert entity.supported_features_compat is light.LightEntityFeature(1)
assert "MockLightEntityEntity" in caplog.text
assert "is using deprecated supported features values" in caplog.text
assert "Instead it should use" in caplog.text
assert "LightEntityFeature" in caplog.text
assert "and color modes" in caplog.text
caplog.clear()
assert entity.supported_features_compat is light.LightEntityFeature(1)
assert "is using deprecated supported features values" not in caplog.text
Loading