Add MockToggleEntity type hints in tests (#120075)

This commit is contained in:
epenet 2024-06-21 12:32:03 +02:00 committed by GitHub
parent fa1e4a225d
commit 904cf26d31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 27 additions and 24 deletions

View File

@ -17,7 +17,7 @@ import pathlib
import threading import threading
import time import time
from types import FrameType, ModuleType from types import FrameType, ModuleType
from typing import Any, NoReturn from typing import Any, Literal, NoReturn
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
from aiohttp.test_utils import unused_port as get_test_instance_port # noqa: F401 from aiohttp.test_utils import unused_port as get_test_instance_port # noqa: F401
@ -959,41 +959,41 @@ class MockEntityPlatform(entity_platform.EntityPlatform):
class MockToggleEntity(entity.ToggleEntity): class MockToggleEntity(entity.ToggleEntity):
"""Provide a mock toggle device.""" """Provide a mock toggle device."""
def __init__(self, name, state, unique_id=None): def __init__(self, name: str | None, state: Literal["on", "off"] | None) -> None:
"""Initialize the mock entity.""" """Initialize the mock entity."""
self._name = name or DEVICE_DEFAULT_NAME self._name = name or DEVICE_DEFAULT_NAME
self._state = state self._state = state
self.calls = [] self.calls: list[tuple[str, dict[str, Any]]] = []
@property @property
def name(self): def name(self) -> str:
"""Return the name of the entity if any.""" """Return the name of the entity if any."""
self.calls.append(("name", {})) self.calls.append(("name", {}))
return self._name return self._name
@property @property
def state(self): def state(self) -> Literal["on", "off"] | None:
"""Return the state of the entity if any.""" """Return the state of the entity if any."""
self.calls.append(("state", {})) self.calls.append(("state", {}))
return self._state return self._state
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return true if entity is on.""" """Return true if entity is on."""
self.calls.append(("is_on", {})) self.calls.append(("is_on", {}))
return self._state == STATE_ON return self._state == STATE_ON
def turn_on(self, **kwargs): def turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on.""" """Turn the entity on."""
self.calls.append(("turn_on", kwargs)) self.calls.append(("turn_on", kwargs))
self._state = STATE_ON self._state = STATE_ON
def turn_off(self, **kwargs): def turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off.""" """Turn the entity off."""
self.calls.append(("turn_off", kwargs)) self.calls.append(("turn_off", kwargs))
self._state = STATE_OFF self._state = STATE_OFF
def last_call(self, method=None): def last_call(self, method: str | None = None) -> tuple[str, dict[str, Any]]:
"""Return the last call.""" """Return the last call."""
if not self.calls: if not self.calls:
return None return None

View File

@ -13,7 +13,7 @@ from homeassistant.components.conversation import default_agent
from homeassistant.components.conversation.models import ConversationInput from homeassistant.components.conversation.models import ConversationInput
from homeassistant.components.cover import SERVICE_OPEN_COVER from homeassistant.components.cover import SERVICE_OPEN_COVER
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.const import ATTR_FRIENDLY_NAME from homeassistant.const import ATTR_FRIENDLY_NAME, STATE_ON
from homeassistant.core import Context, HomeAssistant from homeassistant.core import Context, HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
@ -269,7 +269,7 @@ async def test_http_processing_intent_entity_renamed(
We want to ensure that renaming an entity later busts the cache We want to ensure that renaming an entity later busts the cache
so that the new name is used. so that the new name is used.
""" """
entity = MockLight("kitchen light", "on") entity = MockLight("kitchen light", STATE_ON)
entity._attr_unique_id = "1234" entity._attr_unique_id = "1234"
entity.entity_id = "light.kitchen" entity.entity_id = "light.kitchen"
setup_test_component_platform(hass, LIGHT_DOMAIN, [entity]) setup_test_component_platform(hass, LIGHT_DOMAIN, [entity])
@ -357,7 +357,7 @@ async def test_http_processing_intent_entity_exposed(
We want to ensure that manually exposing an entity later busts the cache We want to ensure that manually exposing an entity later busts the cache
so that the new setting is used. so that the new setting is used.
""" """
entity = MockLight("kitchen light", "on") entity = MockLight("kitchen light", STATE_ON)
entity._attr_unique_id = "1234" entity._attr_unique_id = "1234"
entity.entity_id = "light.kitchen" entity.entity_id = "light.kitchen"
setup_test_component_platform(hass, LIGHT_DOMAIN, [entity]) setup_test_component_platform(hass, LIGHT_DOMAIN, [entity])
@ -458,7 +458,7 @@ async def test_http_processing_intent_conversion_not_expose_new(
# Disable exposing new entities to the default agent # Disable exposing new entities to the default agent
expose_new(hass, False) expose_new(hass, False)
entity = MockLight("kitchen light", "on") entity = MockLight("kitchen light", STATE_ON)
entity._attr_unique_id = "1234" entity._attr_unique_id = "1234"
entity.entity_id = "light.kitchen" entity.entity_id = "light.kitchen"
setup_test_component_platform(hass, LIGHT_DOMAIN, [entity]) setup_test_component_platform(hass, LIGHT_DOMAIN, [entity])

View File

@ -4,6 +4,8 @@ All containing methods are legacy helpers that should not be used by new
components. Instead call the service directly. components. Instead call the service directly.
""" """
from typing import Any, Literal
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS,
ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS_PCT,
@ -250,13 +252,12 @@ class MockLight(MockToggleEntity, LightEntity):
def __init__( def __init__(
self, self,
name, name: str | None,
state, state: Literal["on", "off"] | None,
unique_id=None,
supported_color_modes: set[ColorMode] | None = None, supported_color_modes: set[ColorMode] | None = None,
) -> None: ) -> None:
"""Initialize the mock light.""" """Initialize the mock light."""
super().__init__(name, state, unique_id) super().__init__(name, state)
if supported_color_modes is None: if supported_color_modes is None:
supported_color_modes = {ColorMode.ONOFF} supported_color_modes = {ColorMode.ONOFF}
self._attr_supported_color_modes = supported_color_modes self._attr_supported_color_modes = supported_color_modes
@ -265,7 +266,7 @@ class MockLight(MockToggleEntity, LightEntity):
color_mode = next(iter(supported_color_modes)) color_mode = next(iter(supported_color_modes))
self._attr_color_mode = color_mode self._attr_color_mode = color_mode
def turn_on(self, **kwargs): def turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on.""" """Turn the entity on."""
super().turn_on(**kwargs) super().turn_on(**kwargs)
for key, value in kwargs.items(): for key, value in kwargs.items():

View File

@ -1,5 +1,6 @@
"""The tests for the Light component.""" """The tests for the Light component."""
from typing import Literal
from unittest.mock import MagicMock, mock_open, patch from unittest.mock import MagicMock, mock_open, patch
import pytest import pytest
@ -1144,7 +1145,7 @@ invalid_no_brightness_no_color_no_transition,,,
@pytest.mark.parametrize("light_state", [STATE_ON, STATE_OFF]) @pytest.mark.parametrize("light_state", [STATE_ON, STATE_OFF])
async def test_light_backwards_compatibility_supported_color_modes( async def test_light_backwards_compatibility_supported_color_modes(
hass: HomeAssistant, light_state hass: HomeAssistant, light_state: Literal["on", "off"]
) -> None: ) -> None:
"""Test supported_color_modes if not implemented by the entity.""" """Test supported_color_modes if not implemented by the entity."""
entities = [ entities = [

View File

@ -3,6 +3,8 @@
Call init before using it in your tests to ensure clean test data. Call init before using it in your tests to ensure clean test data.
""" """
from typing import Any, Literal
from homeassistant.components.light import ColorMode, LightEntity from homeassistant.components.light import ColorMode, LightEntity
from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -67,13 +69,12 @@ class MockLight(MockToggleEntity, LightEntity):
def __init__( def __init__(
self, self,
name, name: str | None,
state, state: Literal["on", "off"] | None,
unique_id=None,
supported_color_modes: set[ColorMode] | None = None, supported_color_modes: set[ColorMode] | None = None,
) -> None: ) -> None:
"""Initialize the mock light.""" """Initialize the mock light."""
super().__init__(name, state, unique_id) super().__init__(name, state)
if supported_color_modes is None: if supported_color_modes is None:
supported_color_modes = {ColorMode.ONOFF} supported_color_modes = {ColorMode.ONOFF}
self._attr_supported_color_modes = supported_color_modes self._attr_supported_color_modes = supported_color_modes
@ -82,7 +83,7 @@ class MockLight(MockToggleEntity, LightEntity):
color_mode = next(iter(supported_color_modes)) color_mode = next(iter(supported_color_modes))
self._attr_color_mode = color_mode self._attr_color_mode = color_mode
def turn_on(self, **kwargs): def turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on.""" """Turn the entity on."""
super().turn_on(**kwargs) super().turn_on(**kwargs)
for key, value in kwargs.items(): for key, value in kwargs.items():