Improve typing of deCONZ light platform (#69886)

homeassistant/components/deconz/light.py:66: error: Incompatible types in assignment (expression has type "List[Union[ConfigurationTool, Cover, Fan, Light, Lock, Siren]]", variable has type "Optional[List[Light]]")  [assignment]
homeassistant/components/deconz/light.py:68: error: Item "None" of "Optional[List[Light]]" has no attribute "__iter__" (not iterable)  [union-attr]
homeassistant/components/deconz/light.py:159: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode"  [union-attr]
homeassistant/components/deconz/light.py:159: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode"  [union-attr]
homeassistant/components/deconz/light.py:161: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode"  [union-attr]
homeassistant/components/deconz/light.py:161: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode"  [union-attr]
homeassistant/components/deconz/light.py:163: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode"  [union-attr]
homeassistant/components/deconz/light.py:163: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_mode"  [union-attr]
homeassistant/components/deconz/light.py:165: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness"  [union-attr]
homeassistant/components/deconz/light.py:165: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness"  [union-attr]
homeassistant/components/deconz/light.py:174: error: Unused "type: ignore" comment
homeassistant/components/deconz/light.py:174: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness"  [union-attr]
homeassistant/components/deconz/light.py:174: note: Error code "union-attr" not covered by "type: ignore" comment
homeassistant/components/deconz/light.py:174: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "brightness"  [union-attr]
homeassistant/components/deconz/light.py:179: error: Unused "type: ignore" comment
homeassistant/components/deconz/light.py:179: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_temp"  [union-attr]
homeassistant/components/deconz/light.py:179: note: Error code "union-attr" not covered by "type: ignore" comment
homeassistant/components/deconz/light.py:179: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "color_temp"  [union-attr]
homeassistant/components/deconz/light.py:179: error: Incompatible return value type (got "Union[int, None, Any]", expected "int")  [return-value]
homeassistant/components/deconz/light.py:179: note: Error code "return-value" not covered by "type: ignore" comment
homeassistant/components/deconz/light.py:184: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "hue"  [union-attr]
homeassistant/components/deconz/light.py:184: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "hue"  [union-attr]
homeassistant/components/deconz/light.py:184: error: Unsupported operand types for / ("None" and "int")  [operator]
homeassistant/components/deconz/light.py:184: note: Left operand is of type "Union[int, None, Any]"
homeassistant/components/deconz/light.py:184: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "saturation"  [union-attr]
homeassistant/components/deconz/light.py:184: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "saturation"  [union-attr]
homeassistant/components/deconz/light.py:189: error: Unused "type: ignore" comment
homeassistant/components/deconz/light.py:189: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "xy"  [union-attr]
homeassistant/components/deconz/light.py:189: note: Error code "union-attr" not covered by "type: ignore" comment
homeassistant/components/deconz/light.py:189: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "xy"  [union-attr]
homeassistant/components/deconz/light.py:194: error: Unused "type: ignore" comment
homeassistant/components/deconz/light.py:194: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "state"  [union-attr]
homeassistant/components/deconz/light.py:194: note: Error code "union-attr" not covered by "type: ignore" comment
homeassistant/components/deconz/light.py:194: error: Incompatible return value type (got "Union[bool, None, Any]", expected "bool")  [return-value]
homeassistant/components/deconz/light.py:194: note: Error code "return-value" not covered by "type: ignore" comment
homeassistant/components/deconz/light.py:228: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state"  [union-attr]
homeassistant/components/deconz/light.py:228: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state"  [union-attr]
homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Union[str, None, Literal['none', 'select', 'lselect']]"  [arg-type]
homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Optional[int]"  [arg-type]
homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Union[str, None, Literal['colorloop', 'none']]"  [arg-type]
homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Optional[bool]"  [arg-type]
homeassistant/components/deconz/light.py:228: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, float, int, str, Tuple[float, float]]]"; expected "Optional[Tuple[float, float]]"  [arg-type]
homeassistant/components/deconz/light.py:232: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "state"  [union-attr]
homeassistant/components/deconz/light.py:245: error: Item "LightBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state"  [union-attr]
homeassistant/components/deconz/light.py:245: error: Item "SensorBase" of "Union[Group, LightBase, SensorBase]" has no attribute "set_state"  [union-attr]
homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Union[str, None, Literal['none', 'select', 'lselect']]"  [arg-type]
homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Optional[int]"  [arg-type]
homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Union[str, None, Literal['colorloop', 'none']]"  [arg-type]
homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Optional[bool]"  [arg-type]
homeassistant/components/deconz/light.py:245: error: Argument 1 to "set_state" of "Group" has incompatible type "**Dict[str, Union[bool, int, str]]"; expected "Optional[Tuple[float, float]]"  [arg-type]
This commit is contained in:
Robert Svensson 2022-04-14 22:31:48 +02:00 committed by GitHub
parent 87551b7880
commit 66265b6e9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 35 deletions

View file

@ -68,6 +68,7 @@ homeassistant.components.deconz.climate
homeassistant.components.deconz.config_flow
homeassistant.components.deconz.diagnostics
homeassistant.components.deconz.gateway
homeassistant.components.deconz.light
homeassistant.components.deconz.services
homeassistant.components.device_automation.*
homeassistant.components.device_tracker.*

View file

@ -1,7 +1,7 @@
"""Support for deCONZ lights."""
from __future__ import annotations
from typing import Any
from typing import Any, Generic, TypedDict, TypeVar
from pydeconz.group import Group
from pydeconz.light import (
@ -10,6 +10,7 @@ from pydeconz.light import (
EFFECT_COLOR_LOOP,
EFFECT_NONE,
Light,
LightResources,
)
from homeassistant.components.light import (
@ -47,6 +48,22 @@ DECONZ_GROUP = "is_deconz_group"
EFFECT_TO_DECONZ = {EFFECT_COLORLOOP: EFFECT_COLOR_LOOP, "None": EFFECT_NONE}
FLASH_TO_DECONZ = {FLASH_SHORT: ALERT_SHORT, FLASH_LONG: ALERT_LONG}
_L = TypeVar("_L", Group, Light)
class SetStateAttributes(TypedDict, total=False):
"""Attributes available with set state call."""
alert: str
brightness: int
color_temperature: int
effect: str
hue: int
on: bool
saturation: int
transition_time: int
xy: tuple[float, float]
async def async_setup_entry(
hass: HomeAssistant,
@ -58,7 +75,7 @@ async def async_setup_entry(
gateway.entities[DOMAIN] = set()
@callback
def async_add_light(lights: list[Light] | None = None) -> None:
def async_add_light(lights: list[LightResources] | None = None) -> None:
"""Add light from deCONZ."""
entities = []
@ -119,12 +136,14 @@ async def async_setup_entry(
async_add_group()
class DeconzBaseLight(DeconzDevice, LightEntity):
class DeconzBaseLight(Generic[_L], DeconzDevice, LightEntity):
"""Representation of a deCONZ light."""
TYPE = DOMAIN
def __init__(self, device: Group | Light, gateway: DeconzGateway) -> None:
_device: _L
def __init__(self, device: _L, gateway: DeconzGateway) -> None:
"""Set up light."""
super().__init__(device, gateway)
@ -154,7 +173,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
self._attr_effect_list = [EFFECT_COLORLOOP]
@property
def color_mode(self) -> str:
def color_mode(self) -> str | None:
"""Return the color mode of the light."""
if self._device.color_mode == "ct":
color_mode = COLOR_MODE_COLOR_TEMP
@ -174,14 +193,16 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
return self._device.brightness # type: ignore[no-any-return]
@property
def color_temp(self) -> int:
def color_temp(self) -> int | None:
"""Return the CT color value."""
return self._device.color_temp # type: ignore[no-any-return]
@property
def hs_color(self) -> tuple[float, float]:
def hs_color(self) -> tuple[float, float] | None:
"""Return the hs color value."""
return (self._device.hue / 65535 * 360, self._device.saturation / 255 * 100)
if (hue := self._device.hue) and (sat := self._device.saturation):
return (hue / 65535 * 360, sat / 255 * 100)
return None
@property
def xy_color(self) -> tuple[float, float] | None:
@ -189,41 +210,41 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
return self._device.xy # type: ignore[no-any-return]
@property
def is_on(self) -> bool:
def is_on(self) -> bool | None:
"""Return true if light is on."""
return self._device.state # type: ignore[no-any-return]
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on light."""
data: dict[str, bool | float | int | str | tuple[float, float]] = {"on": True}
data: SetStateAttributes = {"on": True}
if (attr_brightness := kwargs.get(ATTR_BRIGHTNESS)) is not None:
data["brightness"] = attr_brightness
if ATTR_BRIGHTNESS in kwargs:
data["brightness"] = kwargs[ATTR_BRIGHTNESS]
if attr_color_temp := kwargs.get(ATTR_COLOR_TEMP):
data["color_temperature"] = attr_color_temp
if ATTR_COLOR_TEMP in kwargs:
data["color_temperature"] = kwargs[ATTR_COLOR_TEMP]
if attr_hs_color := kwargs.get(ATTR_HS_COLOR):
if ATTR_HS_COLOR in kwargs:
if COLOR_MODE_XY in self._attr_supported_color_modes:
data["xy"] = color_hs_to_xy(*attr_hs_color)
data["xy"] = color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
else:
data["hue"] = int(attr_hs_color[0] / 360 * 65535)
data["saturation"] = int(attr_hs_color[1] / 100 * 255)
data["hue"] = int(kwargs[ATTR_HS_COLOR][0] / 360 * 65535)
data["saturation"] = int(kwargs[ATTR_HS_COLOR][1] / 100 * 255)
if ATTR_XY_COLOR in kwargs:
data["xy"] = kwargs[ATTR_XY_COLOR]
if (attr_transition := kwargs.get(ATTR_TRANSITION)) is not None:
data["transition_time"] = int(attr_transition * 10)
if ATTR_TRANSITION in kwargs:
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10)
elif "IKEA" in self._device.manufacturer:
data["transition_time"] = 0
if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH, ""))) is not None:
data["alert"] = alert
if ATTR_FLASH in kwargs and kwargs[ATTR_FLASH] in FLASH_TO_DECONZ:
data["alert"] = FLASH_TO_DECONZ[kwargs[ATTR_FLASH]]
del data["on"]
if (effect := EFFECT_TO_DECONZ.get(kwargs.get(ATTR_EFFECT, ""))) is not None:
data["effect"] = effect
if ATTR_EFFECT in kwargs and kwargs[ATTR_EFFECT] in EFFECT_TO_DECONZ:
data["effect"] = EFFECT_TO_DECONZ[kwargs[ATTR_EFFECT]]
await self._device.set_state(**data)
@ -232,14 +253,14 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
if not self._device.state:
return
data: dict[str, bool | int | str] = {"on": False}
data: SetStateAttributes = {"on": False}
if (attr_transition := kwargs.get(ATTR_TRANSITION)) is not None:
if ATTR_TRANSITION in kwargs:
data["brightness"] = 0
data["transition_time"] = int(attr_transition * 10)
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10)
if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH, ""))) is not None:
data["alert"] = alert
if ATTR_FLASH in kwargs and kwargs[ATTR_FLASH] in FLASH_TO_DECONZ:
data["alert"] = FLASH_TO_DECONZ[kwargs[ATTR_FLASH]]
del data["on"]
await self._device.set_state(**data)
@ -250,7 +271,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
return {DECONZ_GROUP: isinstance(self._device, Group)}
class DeconzLight(DeconzBaseLight):
class DeconzLight(DeconzBaseLight[Light]):
"""Representation of a deCONZ light."""
_device: Light
@ -266,7 +287,7 @@ class DeconzLight(DeconzBaseLight):
return self._device.min_color_temp or super().min_mireds
class DeconzGroup(DeconzBaseLight):
class DeconzGroup(DeconzBaseLight[Group]):
"""Representation of a deCONZ group."""
_device: Group

View file

@ -550,6 +550,17 @@ no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.deconz.light]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.deconz.services]
check_untyped_defs = true
disallow_incomplete_defs = true
@ -2618,9 +2629,6 @@ ignore_errors = true
[mypy-homeassistant.components.deconz.fan]
ignore_errors = true
[mypy-homeassistant.components.deconz.light]
ignore_errors = true
[mypy-homeassistant.components.deconz.lock]
ignore_errors = true

View file

@ -26,7 +26,6 @@ IGNORED_MODULES: Final[list[str]] = [
"homeassistant.components.deconz.binary_sensor",
"homeassistant.components.deconz.cover",
"homeassistant.components.deconz.fan",
"homeassistant.components.deconz.light",
"homeassistant.components.deconz.lock",
"homeassistant.components.deconz.logbook",
"homeassistant.components.deconz.number",