Rework entity description functions in Tessie (#106287)

* use lamdba to return the library function

* Rename mocks

* lambda number

* Lambda button

* Add missing

* Remove context manager
This commit is contained in:
Brett Adams 2023-12-23 22:45:06 +10:00 committed by GitHub
parent ea7c839423
commit 043f3e640c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 51 additions and 57 deletions

View File

@ -33,21 +33,27 @@ class TessieButtonEntityDescription(ButtonEntityDescription):
DESCRIPTIONS: tuple[TessieButtonEntityDescription, ...] = ( DESCRIPTIONS: tuple[TessieButtonEntityDescription, ...] = (
TessieButtonEntityDescription(key="wake", func=wake, icon="mdi:sleep-off"), TessieButtonEntityDescription(key="wake", func=lambda: wake, icon="mdi:sleep-off"),
TessieButtonEntityDescription( TessieButtonEntityDescription(
key="flash_lights", func=flash_lights, icon="mdi:flashlight" key="flash_lights", func=lambda: flash_lights, icon="mdi:flashlight"
), ),
TessieButtonEntityDescription(key="honk", func=honk, icon="mdi:bullhorn"), TessieButtonEntityDescription(key="honk", func=honk, icon="mdi:bullhorn"),
TessieButtonEntityDescription( TessieButtonEntityDescription(
key="trigger_homelink", func=trigger_homelink, icon="mdi:garage" key="trigger_homelink", func=lambda: trigger_homelink, icon="mdi:garage"
), ),
TessieButtonEntityDescription( TessieButtonEntityDescription(
key="enable_keyless_driving", func=enable_keyless_driving, icon="mdi:car-key" key="enable_keyless_driving",
func=lambda: enable_keyless_driving,
icon="mdi:car-key",
), ),
TessieButtonEntityDescription(key="boombox", func=boombox, icon="mdi:volume-high"),
TessieButtonEntityDescription(key="frunk", func=open_front_trunk, icon="mdi:car"),
TessieButtonEntityDescription( TessieButtonEntityDescription(
key="trunk", func=open_close_rear_trunk, icon="mdi:car-back" key="boombox", func=lambda: boombox, icon="mdi:volume-high"
),
TessieButtonEntityDescription(
key="frunk", func=lambda: open_front_trunk, icon="mdi:car"
),
TessieButtonEntityDescription(
key="trunk", func=lambda: open_close_rear_trunk, icon="mdi:car-back"
), ),
) )
@ -81,4 +87,4 @@ class TessieButtonEntity(TessieEntity, ButtonEntity):
async def async_press(self) -> None: async def async_press(self) -> None:
"""Press the button.""" """Press the button."""
await self.run(self.entity_description.func) await self.run(self.entity_description.func())

View File

@ -48,7 +48,7 @@ DESCRIPTIONS: tuple[TessieNumberEntityDescription, ...] = (
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=NumberDeviceClass.CURRENT, device_class=NumberDeviceClass.CURRENT,
max_key="charge_state_charge_current_request_max", max_key="charge_state_charge_current_request_max",
func=set_charging_amps, func=lambda: set_charging_amps,
arg="amps", arg="amps",
), ),
TessieNumberEntityDescription( TessieNumberEntityDescription(
@ -60,7 +60,7 @@ DESCRIPTIONS: tuple[TessieNumberEntityDescription, ...] = (
device_class=NumberDeviceClass.BATTERY, device_class=NumberDeviceClass.BATTERY,
min_key="charge_state_charge_limit_soc_min", min_key="charge_state_charge_limit_soc_min",
max_key="charge_state_charge_limit_soc_max", max_key="charge_state_charge_limit_soc_max",
func=set_charge_limit, func=lambda: set_charge_limit,
arg="percent", arg="percent",
), ),
TessieNumberEntityDescription( TessieNumberEntityDescription(
@ -73,7 +73,7 @@ DESCRIPTIONS: tuple[TessieNumberEntityDescription, ...] = (
mode=NumberMode.BOX, mode=NumberMode.BOX,
min_key="vehicle_state_speed_limit_mode_min_limit_mph", min_key="vehicle_state_speed_limit_mode_min_limit_mph",
max_key="vehicle_state_speed_limit_mode_max_limit_mph", max_key="vehicle_state_speed_limit_mode_max_limit_mph",
func=set_speed_limit, func=lambda: set_speed_limit,
arg="mph", arg="mph",
), ),
) )
@ -132,6 +132,6 @@ class TessieNumberEntity(TessieEntity, NumberEntity):
async def async_set_native_value(self, value: float) -> None: async def async_set_native_value(self, value: float) -> None:
"""Set new value.""" """Set new value."""
await self.run( await self.run(
self.entity_description.func, **{self.entity_description.arg: value} self.entity_description.func(), **{self.entity_description.arg: value}
) )
self.set((self.key, value)) self.set((self.key, value))

View File

@ -43,32 +43,32 @@ class TessieSwitchEntityDescription(SwitchEntityDescription):
DESCRIPTIONS: tuple[TessieSwitchEntityDescription, ...] = ( DESCRIPTIONS: tuple[TessieSwitchEntityDescription, ...] = (
TessieSwitchEntityDescription( TessieSwitchEntityDescription(
key="charge_state_charge_enable_request", key="charge_state_charge_enable_request",
on_func=start_charging, on_func=lambda: start_charging,
off_func=stop_charging, off_func=lambda: stop_charging,
icon="mdi:ev-station", icon="mdi:ev-station",
), ),
TessieSwitchEntityDescription( TessieSwitchEntityDescription(
key="climate_state_defrost_mode", key="climate_state_defrost_mode",
on_func=start_defrost, on_func=lambda: start_defrost,
off_func=stop_defrost, off_func=lambda: stop_defrost,
icon="mdi:snowflake", icon="mdi:snowflake",
), ),
TessieSwitchEntityDescription( TessieSwitchEntityDescription(
key="vehicle_state_sentry_mode", key="vehicle_state_sentry_mode",
on_func=enable_sentry_mode, on_func=lambda: enable_sentry_mode,
off_func=disable_sentry_mode, off_func=lambda: disable_sentry_mode,
icon="mdi:shield-car", icon="mdi:shield-car",
), ),
TessieSwitchEntityDescription( TessieSwitchEntityDescription(
key="vehicle_state_valet_mode", key="vehicle_state_valet_mode",
on_func=enable_valet_mode, on_func=lambda: enable_valet_mode,
off_func=disable_valet_mode, off_func=lambda: disable_valet_mode,
icon="mdi:car-key", icon="mdi:car-key",
), ),
TessieSwitchEntityDescription( TessieSwitchEntityDescription(
key="climate_state_steering_wheel_heater", key="climate_state_steering_wheel_heater",
on_func=start_steering_wheel_heater, on_func=lambda: start_steering_wheel_heater,
off_func=stop_steering_wheel_heater, off_func=lambda: stop_steering_wheel_heater,
icon="mdi:steering", icon="mdi:steering",
), ),
) )
@ -112,10 +112,10 @@ class TessieSwitchEntity(TessieEntity, SwitchEntity):
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the Switch.""" """Turn on the Switch."""
await self.run(self.entity_description.on_func) await self.run(self.entity_description.on_func())
self.set((self.entity_description.key, True)) self.set((self.entity_description.key, True))
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the Switch.""" """Turn off the Switch."""
await self.run(self.entity_description.off_func) await self.run(self.entity_description.off_func())
self.set((self.entity_description.key, False)) self.set((self.entity_description.key, False))

View File

@ -1,8 +1,7 @@
"""Tessie common helpers for tests.""" """Tessie common helpers for tests."""
from contextlib import contextmanager
from http import HTTPStatus from http import HTTPStatus
from unittest.mock import AsyncMock, patch from unittest.mock import patch
from aiohttp import ClientConnectionError, ClientResponseError from aiohttp import ClientConnectionError, ClientResponseError
from aiohttp.client import RequestInfo from aiohttp.client import RequestInfo
@ -10,7 +9,6 @@ from aiohttp.client import RequestInfo
from homeassistant.components.tessie.const import DOMAIN from homeassistant.components.tessie.const import DOMAIN
from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityDescription
from tests.common import MockConfigEntry, load_json_object_fixture from tests.common import MockConfigEntry, load_json_object_fixture
@ -61,16 +59,3 @@ async def setup_platform(hass: HomeAssistant, side_effect=None):
await hass.async_block_till_done() await hass.async_block_till_done()
return mock_entry return mock_entry
@contextmanager
def patch_description(
key: str, attr: str, descriptions: tuple[EntityDescription]
) -> AsyncMock:
"""Patch a description."""
to_patch = next(filter(lambda x: x.key == key, descriptions))
original = to_patch.func
mock = AsyncMock()
object.__setattr__(to_patch, attr, mock)
yield mock
object.__setattr__(to_patch, attr, original)

View File

@ -1,11 +1,11 @@
"""Test the Tessie button platform.""" """Test the Tessie button platform."""
from unittest.mock import patch
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.tessie.button import DESCRIPTIONS
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .common import patch_description, setup_platform from .common import setup_platform
async def test_buttons(hass: HomeAssistant) -> None: async def test_buttons(hass: HomeAssistant) -> None:
@ -14,7 +14,9 @@ async def test_buttons(hass: HomeAssistant) -> None:
await setup_platform(hass) await setup_platform(hass)
# Test wake button # Test wake button
with patch_description("wake", "func", DESCRIPTIONS) as mock_wake: with patch(
"homeassistant.components.tessie.button.wake",
) as mock_wake:
await hass.services.async_call( await hass.services.async_call(
BUTTON_DOMAIN, BUTTON_DOMAIN,
SERVICE_PRESS, SERVICE_PRESS,

View File

@ -1,12 +1,13 @@
"""Test the Tessie number platform.""" """Test the Tessie number platform."""
from unittest.mock import patch
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN, SERVICE_SET_VALUE from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN, SERVICE_SET_VALUE
from homeassistant.components.tessie.number import DESCRIPTIONS from homeassistant.components.tessie.number import DESCRIPTIONS
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .common import TEST_VEHICLE_STATE_ONLINE, patch_description, setup_platform from .common import TEST_VEHICLE_STATE_ONLINE, setup_platform
async def test_numbers(hass: HomeAssistant) -> None: async def test_numbers(hass: HomeAssistant) -> None:
@ -33,8 +34,8 @@ async def test_numbers(hass: HomeAssistant) -> None:
) )
# Test number set value functions # Test number set value functions
with patch_description( with patch(
"charge_state_charge_current_request", "func", DESCRIPTIONS "homeassistant.components.tessie.number.set_charging_amps",
) as mock_set_charging_amps: ) as mock_set_charging_amps:
await hass.services.async_call( await hass.services.async_call(
NUMBER_DOMAIN, NUMBER_DOMAIN,
@ -45,8 +46,8 @@ async def test_numbers(hass: HomeAssistant) -> None:
assert hass.states.get("number.test_charge_current").state == "16.0" assert hass.states.get("number.test_charge_current").state == "16.0"
mock_set_charging_amps.assert_called_once() mock_set_charging_amps.assert_called_once()
with patch_description( with patch(
"charge_state_charge_limit_soc", "func", DESCRIPTIONS "homeassistant.components.tessie.number.set_charge_limit",
) as mock_set_charge_limit: ) as mock_set_charge_limit:
await hass.services.async_call( await hass.services.async_call(
NUMBER_DOMAIN, NUMBER_DOMAIN,
@ -57,8 +58,8 @@ async def test_numbers(hass: HomeAssistant) -> None:
assert hass.states.get("number.test_charge_limit").state == "80.0" assert hass.states.get("number.test_charge_limit").state == "80.0"
mock_set_charge_limit.assert_called_once() mock_set_charge_limit.assert_called_once()
with patch_description( with patch(
"vehicle_state_speed_limit_mode_current_limit_mph", "func", DESCRIPTIONS "homeassistant.components.tessie.number.set_speed_limit",
) as mock_set_speed_limit: ) as mock_set_speed_limit:
await hass.services.async_call( await hass.services.async_call(
NUMBER_DOMAIN, NUMBER_DOMAIN,

View File

@ -30,9 +30,8 @@ async def test_switches(hass: HomeAssistant) -> None:
) )
with patch( with patch(
"homeassistant.components.tessie.entity.TessieEntity.run", "homeassistant.components.tessie.switch.start_charging",
return_value=True, ) as mock_start_charging:
) as mock_run:
# Test Switch On # Test Switch On
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
@ -40,9 +39,10 @@ async def test_switches(hass: HomeAssistant) -> None:
{ATTR_ENTITY_ID: ["switch.test_charge"]}, {ATTR_ENTITY_ID: ["switch.test_charge"]},
blocking=True, blocking=True,
) )
mock_run.assert_called_once() mock_start_charging.assert_called_once()
mock_run.reset_mock() with patch(
"homeassistant.components.tessie.switch.stop_charging",
) as mock_stop_charging:
# Test Switch Off # Test Switch Off
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
@ -50,4 +50,4 @@ async def test_switches(hass: HomeAssistant) -> None:
{ATTR_ENTITY_ID: ["switch.test_charge"]}, {ATTR_ENTITY_ID: ["switch.test_charge"]},
blocking=True, blocking=True,
) )
mock_run.assert_called_once() mock_stop_charging.assert_called_once()