Fix warnings in our test suite (#1246)

Co-authored-by: Steven B <51370195+sdb9696@users.noreply.github.com>
This commit is contained in:
Teemu R. 2024-11-13 17:10:06 +01:00 committed by GitHub
parent 157ad8e807
commit a82ee56a27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 197 additions and 155 deletions

View File

@ -484,11 +484,11 @@ class Device(ABC):
_deprecated_device_type_attributes = {
# is_type
"is_bulb": (Module.Light, DeviceType.Bulb),
"is_dimmer": (Module.Light, DeviceType.Dimmer),
"is_light_strip": (Module.LightEffect, DeviceType.LightStrip),
"is_plug": (Module.Led, DeviceType.Plug),
"is_wallswitch": (Module.Led, DeviceType.WallSwitch),
"is_bulb": (None, DeviceType.Bulb),
"is_dimmer": (None, DeviceType.Dimmer),
"is_light_strip": (None, DeviceType.LightStrip),
"is_plug": (None, DeviceType.Plug),
"is_wallswitch": (None, DeviceType.WallSwitch),
"is_strip": (None, DeviceType.Strip),
"is_strip_socket": (None, DeviceType.StripSocket),
}
@ -503,7 +503,9 @@ class Device(ABC):
return None
for attr in attrs:
if hasattr(check, attr):
# Use dir() as opposed to hasattr() to avoid raising exceptions
# from properties
if attr in dir(check):
return attr
return None
@ -552,10 +554,7 @@ class Device(ABC):
def __getattr__(self, name: str) -> Any:
# is_device_type
if dep_device_type_attr := self._deprecated_device_type_attributes.get(name):
module = dep_device_type_attr[0]
msg = f"{name} is deprecated"
if module:
msg += f", use: {module} in device.modules instead"
msg = f"{name} is deprecated, use device_type property instead"
warn(msg, DeprecationWarning, stacklevel=2)
return self.device_type == dep_device_type_attr[1]
# Other deprecated attributes

View File

@ -33,6 +33,7 @@ class FakeSmartTransport(BaseTransport):
warn_fixture_missing_methods=True,
fix_incomplete_fixture_lists=True,
is_child=False,
get_child_fixtures=True,
):
super().__init__(
config=DeviceConfig(
@ -48,9 +49,10 @@ class FakeSmartTransport(BaseTransport):
# child are then still reflected on the parent's lis of child device in
if not is_child:
self.info = copy.deepcopy(info)
self.child_protocols = self._get_child_protocols(
self.info, self.fixture_name, "get_child_device_list"
)
if get_child_fixtures:
self.child_protocols = self._get_child_protocols(
self.info, self.fixture_name, "get_child_device_list"
)
else:
self.info = info
if not component_nego_not_included:
@ -220,10 +222,7 @@ class FakeSmartTransport(BaseTransport):
"""Handle control_child command."""
device_id = params.get("device_id")
if device_id not in self.child_protocols:
warn(
f"Could not find child fixture {device_id} in {self.fixture_name}",
stacklevel=2,
)
# no need to warn as the warning was raised during protocol init
return self._handle_control_child_missing(params)
child_protocol: SmartProtocol = self.child_protocols[device_id]

View File

@ -1,6 +1,6 @@
import pytest
from kasa import Module, SmartDevice
from kasa import Device, Module
from ...device_fixtures import parametrize
@ -16,7 +16,7 @@ contact = parametrize(
("is_open", bool),
],
)
async def test_contact_features(dev: SmartDevice, feature, type):
async def test_contact_features(dev: Device, feature, type):
"""Test that features are registered and work as expected."""
contact = dev.modules.get(Module.ContactSensor)
assert contact is not None

View File

@ -71,7 +71,7 @@ async def test_light_effect_brightness(
if effect_active:
assert light_effect.is_active
assert light_effect.brightness == dev.brightness
assert light_effect.brightness == light_module.brightness
light_effect_set_brightness.assert_called_with(10)
mock_light_effect_call.assert_called_with(

View File

@ -86,7 +86,7 @@ async def test_light_effect_brightness(
if effect_active:
assert light_effect.is_active
assert light_effect.brightness == dev.brightness
assert light_effect.brightness == light_module.brightness
light_effect_set_brightness.assert_called_with(10)
mock_light_effect_call.assert_called_with(

View File

@ -1,6 +1,6 @@
import pytest
from kasa import Module, SmartDevice
from kasa import Device, Module
from ...device_fixtures import parametrize
@ -16,7 +16,7 @@ motion = parametrize(
("motion_detected", bool),
],
)
async def test_motion_features(dev: SmartDevice, feature, type):
async def test_motion_features(dev: Device, feature, type):
"""Test that features are registered and work as expected."""
motion = dev.modules.get(Module.MotionSensor)
assert motion is not None

View File

@ -13,6 +13,7 @@ from voluptuous import (
from kasa import Device, DeviceType, IotLightPreset, KasaException, LightState, Module
from kasa.iot import IotBulb, IotDimmer
from kasa.iot.modules import LightPreset as IotLightPresetModule
from .conftest import (
bulb,
@ -39,11 +40,6 @@ async def test_bulb_sysinfo(dev: Device):
assert dev.model is not None
# TODO: remove special handling for lightstrip
if not dev.is_light_strip:
assert dev.device_type == DeviceType.Bulb
assert dev.is_bulb
@bulb
async def test_state_attributes(dev: Device):
@ -88,7 +84,9 @@ async def test_hsv(dev: Device, turn_on):
@color_bulb_iot
async def test_set_hsv_transition(dev: IotBulb, mocker):
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
await dev.set_hsv(10, 10, 100, transition=1000)
light = dev.modules.get(Module.Light)
assert light
await light.set_hsv(10, 10, 100, transition=1000)
set_light_state.assert_called_with(
{"hue": 10, "saturation": 10, "brightness": 100, "color_temp": 0},
@ -226,7 +224,9 @@ async def test_try_set_colortemp(dev: Device, turn_on):
@variable_temp_iot
async def test_set_color_temp_transition(dev: IotBulb, mocker):
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
await dev.set_color_temp(2700, transition=100)
light = dev.modules.get(Module.Light)
assert light
await light.set_color_temp(2700, transition=100)
set_light_state.assert_called_with({"color_temp": 2700}, transition=100)
@ -234,8 +234,9 @@ async def test_set_color_temp_transition(dev: IotBulb, mocker):
@variable_temp_iot
async def test_unknown_temp_range(dev: IotBulb, monkeypatch, caplog):
monkeypatch.setitem(dev._sys_info, "model", "unknown bulb")
assert dev.valid_temperature_range == (2700, 5000)
light = dev.modules.get(Module.Light)
assert light
assert light.valid_temperature_range == (2700, 5000)
assert "Unknown color temperature range, fallback to 2700-5000" in caplog.text
@ -278,19 +279,21 @@ async def test_non_variable_temp(dev: Device):
@turn_on
async def test_dimmable_brightness(dev: IotBulb, turn_on):
assert isinstance(dev, (IotBulb, IotDimmer))
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, turn_on)
assert dev._is_dimmable
await dev.set_brightness(50)
await light.set_brightness(50)
await dev.update()
assert dev.brightness == 50
assert light.brightness == 50
await dev.set_brightness(10)
await light.set_brightness(10)
await dev.update()
assert dev.brightness == 10
assert light.brightness == 10
with pytest.raises(TypeError, match="Brightness must be an integer"):
await dev.set_brightness("foo") # type: ignore[arg-type]
await light.set_brightness("foo") # type: ignore[arg-type]
@bulb_iot
@ -308,7 +311,9 @@ async def test_turn_on_transition(dev: IotBulb, mocker):
@bulb_iot
async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
set_light_state = mocker.patch("kasa.iot.IotBulb._set_light_state")
await dev.set_brightness(10, transition=1000)
light = dev.modules.get(Module.Light)
assert light
await light.set_brightness(10, transition=1000)
set_light_state.assert_called_with({"brightness": 10, "on_off": 1}, transition=1000)
@ -316,28 +321,30 @@ async def test_dimmable_brightness_transition(dev: IotBulb, mocker):
@dimmable_iot
async def test_invalid_brightness(dev: IotBulb):
assert dev._is_dimmable
light = dev.modules.get(Module.Light)
assert light
with pytest.raises(
ValueError,
match=re.escape("Invalid brightness value: 110 (valid range: 0-100%)"),
):
await dev.set_brightness(110)
await light.set_brightness(110)
with pytest.raises(
ValueError,
match=re.escape("Invalid brightness value: -100 (valid range: 0-100%)"),
):
await dev.set_brightness(-100)
await light.set_brightness(-100)
@non_dimmable_iot
async def test_non_dimmable(dev: IotBulb):
assert not dev._is_dimmable
light = dev.modules.get(Module.Light)
assert light
with pytest.raises(KasaException):
assert dev.brightness == 0
assert light.brightness == 0
with pytest.raises(KasaException):
await dev.set_brightness(100)
await light.set_brightness(100)
@bulb_iot
@ -357,7 +364,10 @@ async def test_ignore_default_not_set_without_color_mode_change_turn_on(
@bulb_iot
async def test_list_presets(dev: IotBulb):
presets = dev.presets
light_preset = dev.modules.get(Module.LightPreset)
assert light_preset
assert isinstance(light_preset, IotLightPresetModule)
presets = light_preset._deprecated_presets
# Light strip devices may list some light effects along with normal presets but these
# are handled by the LightEffect module so exclude preferred states with id
raw_presets = [
@ -376,9 +386,13 @@ async def test_list_presets(dev: IotBulb):
@bulb_iot
async def test_modify_preset(dev: IotBulb, mocker):
"""Verify that modifying preset calls the and exceptions are raised properly."""
if not dev.presets:
if (
not (light_preset := dev.modules.get(Module.LightPreset))
or not light_preset._deprecated_presets
):
pytest.skip("Some strips do not support presets")
assert isinstance(light_preset, IotLightPresetModule)
data: dict[str, int | None] = {
"index": 0,
"brightness": 10,
@ -394,12 +408,12 @@ async def test_modify_preset(dev: IotBulb, mocker):
assert preset.saturation == 0
assert preset.color_temp == 0
await dev.save_preset(preset)
await light_preset._deprecated_save_preset(preset)
await dev.update()
assert dev.presets[0].brightness == 10
assert light_preset._deprecated_presets[0].brightness == 10
with pytest.raises(KasaException):
await dev.save_preset(
await light_preset._deprecated_save_preset(
IotLightPreset(index=5, hue=0, brightness=0, saturation=0, color_temp=0) # type: ignore[call-arg]
)
@ -420,11 +434,14 @@ async def test_modify_preset(dev: IotBulb, mocker):
)
async def test_modify_preset_payloads(dev: IotBulb, preset, payload, mocker):
"""Test that modify preset payloads ignore none values."""
if not dev.presets:
if (
not (light_preset := dev.modules.get(Module.LightPreset))
or not light_preset._deprecated_presets
):
pytest.skip("Some strips do not support presets")
query_helper = mocker.patch("kasa.iot.IotBulb._query_helper")
await dev.save_preset(preset)
await light_preset._deprecated_save_preset(preset)
query_helper.assert_called_with(dev.LIGHT_SERVICE, "set_preferred_state", payload)
@ -476,6 +493,4 @@ SYSINFO_SCHEMA_BULB = SYSINFO_SCHEMA.extend(
@bulb
def test_device_type_bulb(dev: Device):
if dev.is_light_strip:
pytest.skip("bulb has also lightstrips to test the api")
assert dev.device_type == DeviceType.Bulb
assert dev.device_type in {DeviceType.Bulb, DeviceType.LightStrip}

View File

@ -6,7 +6,7 @@ import importlib
import inspect
import pkgutil
import sys
from contextlib import AbstractContextManager
from contextlib import AbstractContextManager, nullcontext
from unittest.mock import AsyncMock, patch
import pytest
@ -170,15 +170,22 @@ async def _test_attribute(
dev: Device, attribute_name, is_expected, module_name, *args, will_raise=False
):
if is_expected and will_raise:
ctx: AbstractContextManager = pytest.raises(will_raise)
ctx: AbstractContextManager | nullcontext = pytest.raises(will_raise)
dep_context: pytest.WarningsRecorder | nullcontext = pytest.deprecated_call(
match=(f"{attribute_name} is deprecated, use:")
)
elif is_expected:
ctx = pytest.deprecated_call(match=(f"{attribute_name} is deprecated, use:"))
ctx = nullcontext()
dep_context = pytest.deprecated_call(
match=(f"{attribute_name} is deprecated, use:")
)
else:
ctx = pytest.raises(
AttributeError, match=f"Device has no attribute '{attribute_name}'"
)
dep_context = nullcontext()
with ctx:
with dep_context, ctx:
if args:
await getattr(dev, attribute_name)(*args)
else:
@ -267,16 +274,19 @@ async def test_deprecated_light_preset_attributes(dev: Device):
await _test_attribute(dev, "presets", bool(preset), "LightPreset", will_raise=exc)
exc = None
is_expected = bool(preset)
# deprecated save_preset not implemented for smart devices as it's unlikely anyone
# has an existing reliance on this for the newer devices.
if not preset or isinstance(dev, SmartDevice):
exc = AttributeError
elif len(preset.preset_states_list) == 0:
if isinstance(dev, SmartDevice):
is_expected = False
if preset and len(preset.preset_states_list) == 0:
exc = KasaException
await _test_attribute(
dev,
"save_preset",
bool(preset),
is_expected,
"LightPreset",
IotLightPreset(index=0, hue=100, brightness=100, saturation=0, color_temp=0), # type: ignore[call-arg]
will_raise=exc,

View File

@ -1,6 +1,6 @@
import pytest
from kasa import DeviceType
from kasa import DeviceType, Module
from kasa.iot import IotDimmer
from .conftest import dimmer_iot, handle_turn_on, turn_on
@ -8,28 +8,32 @@ from .conftest import dimmer_iot, handle_turn_on, turn_on
@dimmer_iot
async def test_set_brightness(dev):
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, False)
await dev.update()
assert dev.is_on is False
await dev.set_brightness(99)
await light.set_brightness(99)
await dev.update()
assert dev.brightness == 99
assert light.brightness == 99
assert dev.is_on is True
await dev.set_brightness(0)
await light.set_brightness(0)
await dev.update()
assert dev.brightness == 99
assert light.brightness == 99
assert dev.is_on is False
@dimmer_iot
@turn_on
async def test_set_brightness_transition(dev, turn_on, mocker):
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, turn_on)
query_helper = mocker.spy(IotDimmer, "_query_helper")
await dev.set_brightness(99, transition=1000)
await light.set_brightness(99, transition=1000)
query_helper.assert_called_with(
mocker.ANY,
"smartlife.iot.dimmer",
@ -37,39 +41,45 @@ async def test_set_brightness_transition(dev, turn_on, mocker):
{"brightness": 99, "duration": 1000},
)
await dev.update()
assert dev.brightness == 99
assert light.brightness == 99
assert dev.is_on
await dev.set_brightness(0, transition=1000)
await light.set_brightness(0, transition=1000)
await dev.update()
assert dev.is_on is False
@dimmer_iot
async def test_set_brightness_invalid(dev):
light = dev.modules.get(Module.Light)
assert light
for invalid_brightness in [-1, 101]:
with pytest.raises(ValueError, match="Invalid brightness"):
await dev.set_brightness(invalid_brightness)
await light.set_brightness(invalid_brightness)
for invalid_type in [0.5, "foo"]:
with pytest.raises(TypeError, match="Brightness must be an integer"):
await dev.set_brightness(invalid_type)
await light.set_brightness(invalid_type)
@dimmer_iot
async def test_set_brightness_invalid_transition(dev):
light = dev.modules.get(Module.Light)
assert light
for invalid_transition in [-1]:
with pytest.raises(ValueError, match="Transition value .+? is not valid."):
await dev.set_brightness(1, transition=invalid_transition)
await light.set_brightness(1, transition=invalid_transition)
for invalid_type in [0.5, "foo"]:
with pytest.raises(TypeError, match="Transition must be integer"):
await dev.set_brightness(1, transition=invalid_type)
await light.set_brightness(1, transition=invalid_type)
@dimmer_iot
async def test_turn_on_transition(dev, mocker):
light = dev.modules.get(Module.Light)
assert light
query_helper = mocker.spy(IotDimmer, "_query_helper")
original_brightness = dev.brightness
original_brightness = light.brightness
await dev.turn_on(transition=1000)
query_helper.assert_called_with(
@ -80,20 +90,22 @@ async def test_turn_on_transition(dev, mocker):
)
await dev.update()
assert dev.is_on
assert dev.brightness == original_brightness
assert light.brightness == original_brightness
@dimmer_iot
async def test_turn_off_transition(dev, mocker):
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, True)
query_helper = mocker.spy(IotDimmer, "_query_helper")
original_brightness = dev.brightness
original_brightness = light.brightness
await dev.turn_off(transition=1000)
await dev.update()
assert dev.is_off
assert dev.brightness == original_brightness
assert light.brightness == original_brightness
query_helper.assert_called_with(
mocker.ANY,
"smartlife.iot.dimmer",
@ -105,6 +117,8 @@ async def test_turn_off_transition(dev, mocker):
@dimmer_iot
@turn_on
async def test_set_dimmer_transition(dev, turn_on, mocker):
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, turn_on)
query_helper = mocker.spy(IotDimmer, "_query_helper")
@ -117,21 +131,23 @@ async def test_set_dimmer_transition(dev, turn_on, mocker):
)
await dev.update()
assert dev.is_on
assert dev.brightness == 99
assert light.brightness == 99
@dimmer_iot
@turn_on
async def test_set_dimmer_transition_to_off(dev, turn_on, mocker):
light = dev.modules.get(Module.Light)
assert light
await handle_turn_on(dev, turn_on)
original_brightness = dev.brightness
original_brightness = light.brightness
query_helper = mocker.spy(IotDimmer, "_query_helper")
await dev.set_dimmer_transition(0, 1000)
await dev.update()
assert dev.is_off
assert dev.brightness == original_brightness
assert light.brightness == original_brightness
query_helper.assert_called_with(
mocker.ANY,
"smartlife.iot.dimmer",

View File

@ -81,14 +81,14 @@ UNSUPPORTED = {
@wallswitch_iot
async def test_type_detection_switch(dev: Device):
d = Discover._get_device_class(dev._last_update)("localhost")
assert d.is_wallswitch
assert d.device_type == DeviceType.WallSwitch
with pytest.deprecated_call(match="use device_type property instead"):
assert d.is_wallswitch
assert d.device_type is DeviceType.WallSwitch
@plug_iot
async def test_type_detection_plug(dev: Device):
d = Discover._get_device_class(dev._last_update)("localhost")
assert d.is_plug
assert d.device_type == DeviceType.Plug
@ -96,29 +96,26 @@ async def test_type_detection_plug(dev: Device):
async def test_type_detection_bulb(dev: Device):
d = Discover._get_device_class(dev._last_update)("localhost")
# TODO: light_strip is a special case for now to force bulb tests on it
if not d.is_light_strip:
assert d.is_bulb
if d.device_type is not DeviceType.LightStrip:
assert d.device_type == DeviceType.Bulb
@strip_iot
async def test_type_detection_strip(dev: Device):
d = Discover._get_device_class(dev._last_update)("localhost")
assert d.is_strip
assert d.device_type == DeviceType.Strip
@dimmer_iot
async def test_type_detection_dimmer(dev: Device):
d = Discover._get_device_class(dev._last_update)("localhost")
assert d.is_dimmer
assert d.device_type == DeviceType.Dimmer
@lightstrip_iot
async def test_type_detection_lightstrip(dev: Device):
d = Discover._get_device_class(dev._last_update)("localhost")
assert d.is_light_strip
assert d.device_type == DeviceType.LightStrip

View File

@ -10,7 +10,7 @@ from voluptuous import (
Schema,
)
from kasa import Device, EmeterStatus, Module
from kasa import Device, DeviceType, EmeterStatus, Module
from kasa.interfaces.energy import Energy
from kasa.iot import IotDevice, IotStrip
from kasa.iot.modules.emeter import Emeter
@ -61,20 +61,20 @@ async def test_get_emeter_realtime(dev):
if not await mod._check_supported():
pytest.skip(f"Energy module not supported for {dev}.")
assert dev.has_emeter
emeter = dev.modules[Module.Energy]
current_emeter = await dev.get_emeter_realtime()
current_emeter = await emeter.get_status()
CURRENT_CONSUMPTION_SCHEMA(current_emeter)
@has_emeter_iot
@pytest.mark.requires_dummy()
async def test_get_emeter_daily(dev):
assert dev.has_emeter
emeter = dev.modules[Module.Energy]
assert await dev.get_emeter_daily(year=1900, month=1) == {}
assert await emeter.get_daily_stats(year=1900, month=1) == {}
d = await dev.get_emeter_daily()
d = await emeter.get_daily_stats()
assert len(d) > 0
k, v = d.popitem()
@ -82,7 +82,7 @@ async def test_get_emeter_daily(dev):
assert isinstance(v, float)
# Test kwh (energy, energy_wh)
d = await dev.get_emeter_daily(kwh=False)
d = await emeter.get_daily_stats(kwh=False)
k2, v2 = d.popitem()
assert v * 1000 == v2
@ -90,11 +90,11 @@ async def test_get_emeter_daily(dev):
@has_emeter_iot
@pytest.mark.requires_dummy()
async def test_get_emeter_monthly(dev):
assert dev.has_emeter
emeter = dev.modules[Module.Energy]
assert await dev.get_emeter_monthly(year=1900) == {}
assert await emeter.get_monthly_stats(year=1900) == {}
d = await dev.get_emeter_monthly()
d = await emeter.get_monthly_stats()
assert len(d) > 0
k, v = d.popitem()
@ -102,23 +102,26 @@ async def test_get_emeter_monthly(dev):
assert isinstance(v, float)
# Test kwh (energy, energy_wh)
d = await dev.get_emeter_monthly(kwh=False)
d = await emeter.get_monthly_stats(kwh=False)
k2, v2 = d.popitem()
assert v * 1000 == v2
@has_emeter_iot
async def test_emeter_status(dev):
assert dev.has_emeter
emeter = dev.modules[Module.Energy]
d = await dev.get_emeter_realtime()
d = await emeter.get_status()
with pytest.raises(KeyError):
assert d["foo"]
assert d["power_mw"] == d["power"] * 1000
# bulbs have only power according to tplink simulator.
if not dev.is_bulb and not dev.is_light_strip:
if (
dev.device_type is not DeviceType.Bulb
and dev.device_type is not DeviceType.LightStrip
):
assert d["voltage_mv"] == d["voltage"] * 1000
assert d["current_ma"] == d["current"] * 1000
@ -128,19 +131,17 @@ async def test_emeter_status(dev):
@pytest.mark.skip("not clearing your stats..")
@has_emeter
async def test_erase_emeter_stats(dev):
assert dev.has_emeter
emeter = dev.modules[Module.Energy]
await dev.erase_emeter()
await emeter.erase_emeter()
@has_emeter_iot
async def test_current_consumption(dev):
if dev.has_emeter:
x = dev.current_consumption
assert isinstance(x, float)
assert x >= 0.0
else:
assert dev.current_consumption is None
emeter = dev.modules[Module.Energy]
x = emeter.current_consumption
assert isinstance(x, float)
assert x >= 0.0
async def test_emeterstatus_missing_current():
@ -180,7 +181,7 @@ async def test_emeter_daily():
emeter_data["get_daystat"]["day_list"].append(
{"day": now.day, "energy_wh": 500, "month": now.month, "year": now.year}
)
assert emeter.emeter_today == 0.500
assert emeter.consumption_today == 0.500
@has_emeter

View File

@ -16,7 +16,7 @@ from voluptuous import (
Schema,
)
from kasa import KasaException, Module
from kasa import DeviceType, KasaException, Module
from kasa.iot import IotDevice
from kasa.iot.iotmodule import _merge_dict
@ -92,10 +92,8 @@ async def test_state_info(dev):
@pytest.mark.requires_dummy()
@device_iot
async def test_invalid_connection(mocker, dev):
with (
mocker.patch.object(FakeIotProtocol, "query", side_effect=KasaException),
pytest.raises(KasaException),
):
mocker.patch.object(FakeIotProtocol, "query", side_effect=KasaException)
with pytest.raises(KasaException):
await dev.update()
@ -169,7 +167,7 @@ async def test_state(dev, turn_on):
async def test_on_since(dev, turn_on):
await handle_turn_on(dev, turn_on)
orig_state = dev.is_on
if "on_time" not in dev.sys_info and not dev.is_strip:
if "on_time" not in dev.sys_info and dev.device_type is not DeviceType.Strip:
assert dev.on_since is None
elif orig_state:
assert isinstance(dev.on_since, datetime)
@ -179,7 +177,7 @@ async def test_on_since(dev, turn_on):
@device_iot
async def test_time(dev):
assert isinstance(await dev.get_time(), datetime)
assert isinstance(dev.modules[Module.Time].time, datetime)
@device_iot
@ -216,7 +214,7 @@ async def test_representation(dev):
@device_iot
async def test_children(dev):
"""Make sure that children property is exposed by every device."""
if dev.is_strip:
if dev.device_type is DeviceType.Strip:
assert len(dev.children) > 0
else:
assert len(dev.children) == 0

View File

@ -1,35 +1,37 @@
import pytest
from kasa import DeviceType
from kasa import DeviceType, Module
from kasa.iot import IotLightStrip
from kasa.iot.modules import LightEffect
from .conftest import lightstrip_iot
@lightstrip_iot
async def test_lightstrip_length(dev: IotLightStrip):
assert dev.is_light_strip
assert dev.device_type == DeviceType.LightStrip
assert dev.length == dev.sys_info["length"]
@lightstrip_iot
async def test_lightstrip_effect(dev: IotLightStrip):
assert isinstance(dev.effect, dict)
le: LightEffect = dev.modules[Module.LightEffect]
assert isinstance(le._deprecated_effect, dict)
for k in ["brightness", "custom", "enable", "id", "name"]:
assert k in dev.effect
assert k in le._deprecated_effect
@lightstrip_iot
async def test_effects_lightstrip_set_effect(dev: IotLightStrip):
le: LightEffect = dev.modules[Module.LightEffect]
with pytest.raises(
ValueError, match="The effect Not real is not a built in effect"
):
await dev.set_effect("Not real")
await le.set_effect("Not real")
await dev.set_effect("Candy Cane")
await le.set_effect("Candy Cane")
await dev.update()
assert dev.effect["name"] == "Candy Cane"
assert le.effect == "Candy Cane"
@lightstrip_iot
@ -38,12 +40,13 @@ async def test_effects_lightstrip_set_effect_brightness(
dev: IotLightStrip, brightness, mocker
):
query_helper = mocker.patch("kasa.iot.IotLightStrip._query_helper")
le: LightEffect = dev.modules[Module.LightEffect]
# test that default brightness works (100 for candy cane)
if brightness == 100:
await dev.set_effect("Candy Cane")
await le.set_effect("Candy Cane")
else:
await dev.set_effect("Candy Cane", brightness=brightness)
await le.set_effect("Candy Cane", brightness=brightness)
args, kwargs = query_helper.call_args_list[0]
payload = args[2]
@ -56,12 +59,13 @@ async def test_effects_lightstrip_set_effect_transition(
dev: IotLightStrip, transition, mocker
):
query_helper = mocker.patch("kasa.iot.IotLightStrip._query_helper")
le: LightEffect = dev.modules[Module.LightEffect]
# test that default (500 for candy cane) transition works
if transition == 500:
await dev.set_effect("Candy Cane")
await le.set_effect("Candy Cane")
else:
await dev.set_effect("Candy Cane", transition=transition)
await le.set_effect("Candy Cane", transition=transition)
args, kwargs = query_helper.call_args_list[0]
payload = args[2]
@ -70,8 +74,9 @@ async def test_effects_lightstrip_set_effect_transition(
@lightstrip_iot
async def test_effects_lightstrip_has_effects(dev: IotLightStrip):
assert dev.has_effects is True
assert dev.effect_list
le: LightEffect = dev.modules[Module.LightEffect]
assert le is not None
assert le.effect_list
@lightstrip_iot

View File

@ -1,3 +1,5 @@
import pytest
from kasa import DeviceType
from .conftest import plug, plug_iot, plug_smart, switch_smart, wallswitch_iot
@ -16,7 +18,6 @@ async def test_plug_sysinfo(dev):
assert dev.model is not None
assert dev.device_type == DeviceType.Plug or dev.device_type == DeviceType.Strip
assert dev.is_plug or dev.is_strip
@wallswitch_iot
@ -27,37 +28,38 @@ async def test_switch_sysinfo(dev):
assert dev.model is not None
assert dev.device_type == DeviceType.WallSwitch
assert dev.is_wallswitch
@plug_iot
async def test_plug_led(dev):
original = dev.led
with pytest.deprecated_call(match="use: Module.Led in device.modules instead"):
original = dev.led
await dev.set_led(False)
await dev.update()
assert not dev.led
await dev.set_led(False)
await dev.update()
assert not dev.led
await dev.set_led(True)
await dev.update()
assert dev.led
await dev.set_led(True)
await dev.update()
assert dev.led
await dev.set_led(original)
await dev.set_led(original)
@wallswitch_iot
async def test_switch_led(dev):
original = dev.led
with pytest.deprecated_call(match="use: Module.Led in device.modules instead"):
original = dev.led
await dev.set_led(False)
await dev.update()
assert not dev.led
await dev.set_led(False)
await dev.update()
assert not dev.led
await dev.set_led(True)
await dev.update()
assert dev.led
await dev.set_led(True)
await dev.update()
assert dev.led
await dev.set_led(original)
await dev.set_led(original)
@plug_smart

View File

@ -45,10 +45,8 @@ async def test_update_no_device_info(dev: SmartDevice, mocker: MockerFixture):
"get_device_time": {},
}
msg = f"get_device_info not found in {mock_response} for device 127.0.0.123"
with (
mocker.patch.object(dev.protocol, "query", return_value=mock_response),
pytest.raises(KasaException, match=msg),
):
mocker.patch.object(dev.protocol, "query", return_value=mock_response)
with pytest.raises(KasaException, match=msg):
await dev.update()

View File

@ -325,6 +325,7 @@ async def test_smart_protocol_lists_single_request(mocker, list_sum, batch_size)
"foobar",
list_return_size=batch_size,
component_nego_not_included=True,
get_child_fixtures=False,
)
protocol = SmartProtocol(transport=ft)
query_spy = mocker.spy(protocol, "_execute_query")
@ -357,6 +358,7 @@ async def test_smart_protocol_lists_multiple_request(mocker, list_sum, batch_siz
"foobar",
list_return_size=batch_size,
component_nego_not_included=True,
get_child_fixtures=False,
)
protocol = SmartProtocol(transport=ft)
query_spy = mocker.spy(protocol, "_execute_query")