Split light fixture from implementation to only import when fixture is actually used (#113892)

* Split light fixture from implementation to only import when fixture is actually used

* Non-local import
This commit is contained in:
Jan-Philipp Benecke 2024-03-21 10:49:32 +01:00 committed by GitHub
parent e1897906cc
commit ff6812a798
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 160 additions and 160 deletions

View File

@ -1,11 +1,16 @@
"""Fixtures for component testing."""
from collections.abc import Generator
from typing import Any
from typing import TYPE_CHECKING, Any
from unittest.mock import MagicMock, patch
import pytest
from homeassistant.const import STATE_OFF, STATE_ON
if TYPE_CHECKING:
from tests.components.light.common import MockLight, SetupLightPlatformCallable
@pytest.fixture(scope="session", autouse=True)
def patch_zeroconf_multiple_catcher() -> Generator[None, None, None]:
@ -101,3 +106,23 @@ def prevent_ffmpeg_subprocess() -> Generator[None, None, None]:
"homeassistant.components.ffmpeg.FFVersion.get_version", return_value="6.0"
):
yield
@pytest.fixture
def mock_light_entities() -> list["MockLight"]:
"""Return mocked light entities."""
from tests.components.light.common import MockLight
return [
MockLight("Ceiling", STATE_ON),
MockLight("Ceiling", STATE_OFF),
MockLight(None, STATE_OFF),
]
@pytest.fixture
def setup_light_platform() -> "SetupLightPlatformCallable":
"""Return a callable to set up the mock light entity component."""
from tests.components.light.common import setup_light_platform
return setup_light_platform

View File

@ -45,7 +45,7 @@ from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component
from tests.common import async_capture_events, get_fixture_path
from tests.fixtures.pytest.light import MockLight, SetupLightPlatformCallable
from tests.components.light.common import MockLight, SetupLightPlatformCallable
async def test_default_state(
@ -269,7 +269,7 @@ async def test_brightness(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.BRIGHTNESS}
@ -342,7 +342,7 @@ async def test_color_hs(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.HS}
@ -414,7 +414,7 @@ async def test_color_rgb(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.RGB}
@ -488,7 +488,7 @@ async def test_color_rgbw(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.RGBW}
@ -562,7 +562,7 @@ async def test_color_rgbww(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.RGBWW}
@ -636,7 +636,7 @@ async def test_white(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.HS, ColorMode.WHITE}
@ -695,7 +695,7 @@ async def test_color_temp(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.COLOR_TEMP}
@ -767,7 +767,7 @@ async def test_emulated_color_temp_group(
MockLight("test2", STATE_OFF),
MockLight("test3", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.COLOR_TEMP}
@ -835,7 +835,7 @@ async def test_min_max_mireds(
MockLight("test1", STATE_ON),
MockLight("test2", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.COLOR_TEMP}
@ -1014,7 +1014,7 @@ async def test_supported_color_modes(
MockLight("test2", STATE_OFF),
MockLight("test3", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.HS}
@ -1064,7 +1064,7 @@ async def test_color_mode(
MockLight("test2", STATE_OFF),
MockLight("test3", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {ColorMode.COLOR_TEMP, ColorMode.HS}
@ -1142,7 +1142,7 @@ async def test_color_mode2(
MockLight("test5", STATE_ON),
MockLight("test6", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity = entities[0]
entity.supported_color_modes = {ColorMode.COLOR_TEMP}
@ -1265,7 +1265,7 @@ async def test_service_calls(
MockLight("ceiling_lights", STATE_OFF),
MockLight("kitchen_lights", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {supported_color_modes}

View File

@ -3,6 +3,7 @@
All containing methods are legacy helpers that should not be used by new
components. Instead call the service directly.
"""
from collections.abc import Callable
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
@ -21,6 +22,8 @@ from homeassistant.components.light import (
ATTR_WHITE,
ATTR_XY_COLOR,
DOMAIN,
ColorMode,
LightEntity,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
@ -29,8 +32,13 @@ from homeassistant.const import (
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.loader import bind_hass
from tests.common import MockPlatform, MockToggleEntity, mock_platform
@bind_hass
def turn_on(
@ -217,3 +225,87 @@ async def async_toggle(
}
await hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data, blocking=True)
TURN_ON_ARG_TO_COLOR_MODE = {
"hs_color": ColorMode.HS,
"xy_color": ColorMode.XY,
"rgb_color": ColorMode.RGB,
"rgbw_color": ColorMode.RGBW,
"rgbww_color": ColorMode.RGBWW,
"color_temp_kelvin": ColorMode.COLOR_TEMP,
}
class MockLight(MockToggleEntity, LightEntity):
"""Mock light class."""
_attr_max_color_temp_kelvin = 6500
_attr_min_color_temp_kelvin = 2000
supported_features = 0
brightness = None
color_temp_kelvin = None
hs_color = None
rgb_color = None
rgbw_color = None
rgbww_color = None
xy_color = None
def __init__(
self,
name,
state,
unique_id=None,
supported_color_modes: set[ColorMode] | None = None,
):
"""Initialize the mock light."""
super().__init__(name, state, unique_id)
if supported_color_modes is None:
supported_color_modes = {ColorMode.ONOFF}
self._attr_supported_color_modes = supported_color_modes
color_mode = ColorMode.UNKNOWN
if len(supported_color_modes) == 1:
color_mode = next(iter(supported_color_modes))
self._attr_color_mode = color_mode
def turn_on(self, **kwargs):
"""Turn the entity on."""
super().turn_on(**kwargs)
for key, value in kwargs.items():
if key in [
"brightness",
"hs_color",
"xy_color",
"rgb_color",
"rgbw_color",
"rgbww_color",
"color_temp_kelvin",
]:
setattr(self, key, value)
if key == "white":
setattr(self, "brightness", value)
if key in TURN_ON_ARG_TO_COLOR_MODE:
self._attr_color_mode = TURN_ON_ARG_TO_COLOR_MODE[key]
SetupLightPlatformCallable = Callable[[HomeAssistant, list[MockLight]], None]
def setup_light_platform(hass: HomeAssistant, entities: list[MockLight]) -> None:
"""Set up the mock light entity platform."""
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up test light platform."""
async_add_entities(entities)
mock_platform(
hass,
f"test.{DOMAIN}",
MockPlatform(async_setup_platform=async_setup_platform),
)

View File

@ -22,7 +22,7 @@ from tests.common import (
async_get_device_automations,
async_mock_service,
)
from tests.fixtures.pytest.light import SetupLightPlatformCallable
from tests.components.light.common import MockLight, SetupLightPlatformCallable
@pytest.fixture(autouse=True, name="stub_blueprint_populate")
@ -325,6 +325,7 @@ async def test_if_fires_on_for_condition(
entity_registry: er.EntityRegistry,
calls,
setup_light_platform: SetupLightPlatformCallable,
mock_light_entities: list[MockLight],
) -> None:
"""Test for firing if condition is on with delay."""
config_entry = MockConfigEntry(domain="test", data={})
@ -343,7 +344,7 @@ async def test_if_fires_on_for_condition(
point2 = point1 + timedelta(seconds=10)
point3 = point2 + timedelta(seconds=10)
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
await hass.async_block_till_done()

View File

@ -22,7 +22,7 @@ from homeassistant.setup import async_setup_component
import homeassistant.util.color as color_util
from tests.common import MockEntityPlatform, MockUser, async_mock_service
from tests.fixtures.pytest.light import MockLight, SetupLightPlatformCallable
from tests.components.light.common import MockLight, SetupLightPlatformCallable
orig_Profiles = light.Profiles
@ -114,7 +114,7 @@ async def test_services(
mock_light_entities: list[MockLight],
) -> None:
"""Test the provided services."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
@ -515,7 +515,7 @@ async def test_light_profiles(
mock_light_entities: list[MockLight],
) -> None:
"""Test light profiles."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
profile_mock_data = {
"test": (0.4, 0.6, 100, 0),
@ -564,7 +564,7 @@ async def test_default_profiles_group(
mock_light_entities: list[MockLight],
) -> None:
"""Test default turn-on light profile for all lights."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
@ -790,7 +790,7 @@ async def test_default_profiles_light(
mock_light_entities: list[MockLight],
) -> None:
"""Test default turn-on light profile for a specific light."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
@ -857,9 +857,10 @@ async def test_light_context(
hass: HomeAssistant,
hass_admin_user: MockUser,
setup_light_platform: SetupLightPlatformCallable,
mock_light_entities: list[MockLight],
) -> None:
"""Test that light context works."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
await hass.async_block_till_done()
@ -885,9 +886,10 @@ async def test_light_turn_on_auth(
hass: HomeAssistant,
hass_read_only_user: MockUser,
setup_light_platform: SetupLightPlatformCallable,
mock_light_entities: list[MockLight],
) -> None:
"""Test that light context works."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
await hass.async_block_till_done()
@ -916,7 +918,7 @@ async def test_light_brightness_step(
MockLight("Test_1", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_features = light.SUPPORT_BRIGHTNESS
@ -987,7 +989,7 @@ async def test_light_brightness_pct_conversion(
mock_light_entities: list[MockLight],
) -> None:
"""Test that light brightness percent conversion."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
entity = mock_light_entities[0]
entity.supported_features = light.SUPPORT_BRIGHTNESS
@ -1183,7 +1185,7 @@ async def test_light_backwards_compatibility_supported_color_modes(
entity4.supported_color_modes = None
entity4.color_mode = None
setup_light_platform(entities)
setup_light_platform(hass, entities)
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
await hass.async_block_till_done()
@ -1272,7 +1274,7 @@ async def test_light_backwards_compatibility_color_mode(
entity4.hs_color = (240, 100)
entity4.color_temp_kelvin = 10000
setup_light_platform(entities)
setup_light_platform(hass, entities)
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
await hass.async_block_till_done()
@ -1312,7 +1314,7 @@ async def test_light_service_call_rgbw(
entity0 = MockLight("Test_rgbw", STATE_ON)
entity0.supported_color_modes = {light.ColorMode.RGBW}
setup_light_platform([entity0])
setup_light_platform(hass, [entity0])
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
await hass.async_block_till_done()
@ -1345,7 +1347,7 @@ async def test_light_state_off(
MockLight("Test_ct", STATE_OFF),
MockLight("Test_rgbw", STATE_OFF),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {light.ColorMode.ONOFF}
@ -1413,7 +1415,7 @@ async def test_light_state_rgbw(
) -> None:
"""Test rgbw color conversion in state updates."""
entity0 = MockLight("Test_rgbw", STATE_ON)
setup_light_platform([entity0])
setup_light_platform(hass, [entity0])
entity0.brightness = 255
entity0.supported_color_modes = {light.ColorMode.RGBW}
@ -1446,7 +1448,7 @@ async def test_light_state_rgbww(
) -> None:
"""Test rgbww color conversion in state updates."""
entity0 = MockLight("Test_rgbww", STATE_ON)
setup_light_platform([entity0])
setup_light_platform(hass, [entity0])
entity0.supported_color_modes = {light.ColorMode.RGBWW}
entity0.color_mode = light.ColorMode.RGBWW
@ -1488,7 +1490,7 @@ async def test_light_service_call_color_conversion(
MockLight("Test_rgbww", STATE_ON),
MockLight("Test_temperature", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {light.ColorMode.HS}
@ -1932,7 +1934,7 @@ async def test_light_service_call_color_conversion_named_tuple(
MockLight("Test_rgbw", STATE_ON),
MockLight("Test_rgbww", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {light.ColorMode.HS}
@ -2008,7 +2010,7 @@ async def test_light_service_call_color_temp_emulation(
MockLight("Test_hs", STATE_ON),
MockLight("Test_hs_white", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {light.ColorMode.COLOR_TEMP, light.ColorMode.HS}
@ -2067,7 +2069,7 @@ async def test_light_service_call_color_temp_conversion(
MockLight("Test_rgbww_ct", STATE_ON),
MockLight("Test_rgbww", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {
@ -2200,7 +2202,7 @@ async def test_light_mired_color_temp_conversion(
MockLight("Test_rgbww_ct", STATE_ON),
MockLight("Test_rgbww", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {
@ -2246,7 +2248,7 @@ async def test_light_service_call_white_mode(
"""Test color_mode white in service calls."""
entity0 = MockLight("Test_white", STATE_ON)
entity0.supported_color_modes = {light.ColorMode.HS, light.ColorMode.WHITE}
setup_light_platform([entity0])
setup_light_platform(hass, [entity0])
assert await async_setup_component(hass, "light", {"light": {"platform": "test"}})
await hass.async_block_till_done()
@ -2351,7 +2353,7 @@ async def test_light_state_color_conversion(
MockLight("Test_xy", STATE_ON),
MockLight("Test_legacy", STATE_ON),
]
setup_light_platform(entities)
setup_light_platform(hass, entities)
entity0 = entities[0]
entity0.supported_color_modes = {light.ColorMode.HS}
@ -2416,7 +2418,7 @@ async def test_services_filter_parameters(
mock_light_entities: list[MockLight],
) -> None:
"""Test turn_on and turn_off filters unsupported parameters."""
setup_light_platform()
setup_light_platform(hass, mock_light_entities)
assert await async_setup_component(
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}

View File

@ -114,10 +114,6 @@ asyncio.set_event_loop_policy(runner.HassEventLoopPolicy(False))
# Disable fixtures overriding our beautiful policy
asyncio.set_event_loop_policy = lambda policy: None
pytest_plugins = [
"tests.fixtures.pytest.light",
]
def pytest_addoption(parser: pytest.Parser) -> None:
"""Register custom pytest options."""

View File

@ -1 +0,0 @@
"""Fixtures for tests."""

View File

@ -1,115 +0,0 @@
"""Fixtures for the light entity component tests."""
from collections.abc import Callable
import pytest
from homeassistant.components.light import DOMAIN, ColorMode, LightEntity
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from tests.common import MockPlatform, MockToggleEntity, mock_platform
TURN_ON_ARG_TO_COLOR_MODE = {
"hs_color": ColorMode.HS,
"xy_color": ColorMode.XY,
"rgb_color": ColorMode.RGB,
"rgbw_color": ColorMode.RGBW,
"rgbww_color": ColorMode.RGBWW,
"color_temp_kelvin": ColorMode.COLOR_TEMP,
}
class MockLight(MockToggleEntity, LightEntity):
"""Mock light class."""
_attr_max_color_temp_kelvin = 6500
_attr_min_color_temp_kelvin = 2000
supported_features = 0
brightness = None
color_temp_kelvin = None
hs_color = None
rgb_color = None
rgbw_color = None
rgbww_color = None
xy_color = None
def __init__(
self,
name,
state,
unique_id=None,
supported_color_modes: set[ColorMode] | None = None,
):
"""Initialize the mock light."""
super().__init__(name, state, unique_id)
if supported_color_modes is None:
supported_color_modes = {ColorMode.ONOFF}
self._attr_supported_color_modes = supported_color_modes
color_mode = ColorMode.UNKNOWN
if len(supported_color_modes) == 1:
color_mode = next(iter(supported_color_modes))
self._attr_color_mode = color_mode
def turn_on(self, **kwargs):
"""Turn the entity on."""
super().turn_on(**kwargs)
for key, value in kwargs.items():
if key in [
"brightness",
"hs_color",
"xy_color",
"rgb_color",
"rgbw_color",
"rgbww_color",
"color_temp_kelvin",
]:
setattr(self, key, value)
if key == "white":
setattr(self, "brightness", value)
if key in TURN_ON_ARG_TO_COLOR_MODE:
self._attr_color_mode = TURN_ON_ARG_TO_COLOR_MODE[key]
SetupLightPlatformCallable = Callable[[list[MockLight] | None], None]
@pytest.fixture
async def mock_light_entities() -> list[MockLight]:
"""Return mocked light entities."""
return [
MockLight("Ceiling", STATE_ON),
MockLight("Ceiling", STATE_OFF),
MockLight(None, STATE_OFF),
]
@pytest.fixture
async def setup_light_platform(
hass: HomeAssistant, mock_light_entities: list[MockLight]
) -> SetupLightPlatformCallable:
"""Set up the mock light entity platform."""
def _setup(entities: list[MockLight] | None = None) -> None:
"""Set up the mock light entity platform."""
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up test light platform."""
async_add_entities(
entities if entities is not None else mock_light_entities
)
mock_platform(
hass,
f"test.{DOMAIN}",
MockPlatform(async_setup_platform=async_setup_platform),
)
return _setup