Rename and deprecate exception classes (#739)

# Public #
SmartDeviceException -> KasaException
UnsupportedDeviceException(SmartDeviceException) -> UnsupportedDeviceError(KasaException)
TimeoutException(SmartDeviceException, asyncio.TimeoutError) -> TimeoutError(KasaException, asyncio.TimeoutError)

Add new exception for error codes -> DeviceError(KasaException)
AuthenticationException(SmartDeviceException) -> AuthenticationError(DeviceError)

# Internal #
RetryableException(SmartDeviceException) -> _RetryableError(DeviceError)
ConnectionException(SmartDeviceException) -> _ConnectionError(KasaException)
This commit is contained in:
Steven B
2024-02-21 15:52:55 +00:00
committed by GitHub
parent 4beff228c9
commit 8c39e81a40
44 changed files with 393 additions and 361 deletions

View File

@@ -1,7 +1,7 @@
import warnings
from json import loads as json_loads
from kasa import Credentials, DeviceConfig, SmartDeviceException, SmartProtocol
from kasa import Credentials, DeviceConfig, KasaException, SmartProtocol
from kasa.protocol import BaseTransport
@@ -144,7 +144,7 @@ class FakeSmartTransport(BaseTransport):
)
return {"result": missing_result[1], "error_code": 0}
else:
raise SmartDeviceException(f"Fixture doesn't support {method}")
raise KasaException(f"Fixture doesn't support {method}")
elif method == "set_qs_info":
return {"error_code": 0}
elif method[:4] == "set_":

View File

@@ -19,8 +19,8 @@ from ..aestransport import AesEncyptionSession, AesTransport, TransportState
from ..credentials import Credentials
from ..deviceconfig import DeviceConfig
from ..exceptions import (
AuthenticationException,
SmartDeviceException,
AuthenticationError,
KasaException,
SmartErrorCode,
)
from ..httpclient import HttpClient
@@ -49,8 +49,8 @@ status_parameters = pytest.mark.parametrize(
"status_code, error_code, inner_error_code, expectation",
[
(200, 0, 0, does_not_raise()),
(400, 0, 0, pytest.raises(SmartDeviceException)),
(200, -1, 0, pytest.raises(SmartDeviceException)),
(400, 0, 0, pytest.raises(KasaException)),
(200, -1, 0, pytest.raises(KasaException)),
],
ids=("success", "status_code", "error_code"),
)
@@ -101,17 +101,17 @@ async def test_login(mocker, status_code, error_code, inner_error_code, expectat
([SmartErrorCode.LOGIN_ERROR, 0, 0, 0], does_not_raise(), 4),
(
[SmartErrorCode.LOGIN_ERROR, SmartErrorCode.LOGIN_ERROR],
pytest.raises(AuthenticationException),
pytest.raises(AuthenticationError),
3,
),
(
[SmartErrorCode.LOGIN_FAILED_ERROR],
pytest.raises(AuthenticationException),
pytest.raises(AuthenticationError),
1,
),
(
[SmartErrorCode.LOGIN_ERROR, SmartErrorCode.SESSION_TIMEOUT_ERROR],
pytest.raises(SmartDeviceException),
pytest.raises(KasaException),
3,
),
],
@@ -238,7 +238,7 @@ async def test_unencrypted_response_invalid_json(mocker, caplog):
}
caplog.set_level(logging.DEBUG)
msg = f"Unable to decrypt response from {host}, error: Incorrect padding, response: Foobar"
with pytest.raises(SmartDeviceException, match=msg):
with pytest.raises(KasaException, match=msg):
await transport.send(json_dumps(request))
@@ -267,7 +267,7 @@ async def test_passthrough_errors(mocker, error_code):
"requestID": 1,
"terminal_uuid": "foobar",
}
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await transport.send(json_dumps(request))

View File

@@ -7,7 +7,7 @@ from voluptuous import (
Schema,
)
from kasa import Bulb, BulbPreset, DeviceType, SmartDeviceException
from kasa import Bulb, BulbPreset, DeviceType, KasaException
from kasa.iot import IotBulb
from .conftest import (
@@ -51,7 +51,7 @@ async def test_state_attributes(dev: Bulb):
@bulb_iot
async def test_light_state_without_update(dev: IotBulb, monkeypatch):
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
monkeypatch.setitem(
dev._last_update["system"]["get_sysinfo"], "light_state", None
)
@@ -123,9 +123,9 @@ async def test_color_state_information(dev: Bulb):
async def test_hsv_on_non_color(dev: Bulb):
assert not dev.is_color
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.set_hsv(0, 0, 0)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
print(dev.hsv)
@@ -175,13 +175,13 @@ async def test_out_of_range_temperature(dev: Bulb):
@non_variable_temp
async def test_non_variable_temp(dev: Bulb):
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.set_color_temp(2700)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
print(dev.valid_temperature_range)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
print(dev.color_temp)
@@ -238,9 +238,9 @@ async def test_invalid_brightness(dev: Bulb):
async def test_non_dimmable(dev: Bulb):
assert not dev.is_dimmable
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
assert dev.brightness == 0
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.set_brightness(100)
@@ -296,7 +296,7 @@ async def test_modify_preset(dev: IotBulb, mocker):
await dev.save_preset(preset)
assert dev.presets[0].brightness == 10
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.save_preset(
BulbPreset(index=5, hue=0, brightness=0, saturation=0, color_temp=0)
)

View File

@@ -6,12 +6,13 @@ import pytest
from asyncclick.testing import CliRunner
from kasa import (
AuthenticationException,
AuthenticationError,
Credentials,
Device,
DeviceError,
EmeterStatus,
SmartDeviceException,
UnsupportedDeviceException,
KasaException,
UnsupportedDeviceError,
)
from kasa.cli import (
TYPE_TO_CLASS,
@@ -188,15 +189,13 @@ async def test_wifi_join_no_creds(dev):
)
assert res.exit_code != 0
assert isinstance(res.exception, AuthenticationException)
assert isinstance(res.exception, AuthenticationError)
@device_smart
async def test_wifi_join_exception(dev, mocker):
runner = CliRunner()
mocker.patch.object(
dev.protocol, "query", side_effect=SmartDeviceException(error_code=9999)
)
mocker.patch.object(dev.protocol, "query", side_effect=DeviceError(error_code=9999))
res = await runner.invoke(
wifi,
["join", "FOOBAR", "--keytype", "wpa_psk", "--password", "foobar"],
@@ -204,7 +203,7 @@ async def test_wifi_join_exception(dev, mocker):
)
assert res.exit_code != 0
assert isinstance(res.exception, SmartDeviceException)
assert isinstance(res.exception, KasaException)
@device_smart
@@ -509,7 +508,7 @@ async def test_host_unsupported(unsupported_device_info):
)
assert res.exit_code != 0
assert isinstance(res.exception, UnsupportedDeviceException)
assert isinstance(res.exception, UnsupportedDeviceError)
@new_discovery
@@ -522,7 +521,7 @@ async def test_discover_auth_failed(discovery_mock, mocker):
mocker.patch.object(
device_class,
"update",
side_effect=AuthenticationException("Failed to authenticate"),
side_effect=AuthenticationError("Failed to authenticate"),
)
res = await runner.invoke(
cli,
@@ -553,7 +552,7 @@ async def test_host_auth_failed(discovery_mock, mocker):
mocker.patch.object(
device_class,
"update",
side_effect=AuthenticationException("Failed to authenticate"),
side_effect=AuthenticationError("Failed to authenticate"),
)
res = await runner.invoke(
cli,
@@ -569,7 +568,7 @@ async def test_host_auth_failed(discovery_mock, mocker):
)
assert res.exit_code != 0
assert isinstance(res.exception, AuthenticationException)
assert isinstance(res.exception, AuthenticationError)
@pytest.mark.parametrize("device_type", list(TYPE_TO_CLASS))
@@ -616,7 +615,7 @@ async def test_shell(dev: Device, mocker):
async def test_errors(mocker):
runner = CliRunner()
err = SmartDeviceException("Foobar")
err = KasaException("Foobar")
# Test masking
mocker.patch("kasa.Discover.discover", side_effect=err)

View File

@@ -8,7 +8,7 @@ from kasa import (
Credentials,
Device,
Discover,
SmartDeviceException,
KasaException,
)
from kasa.device_factory import connect, get_protocol
from kasa.deviceconfig import (
@@ -110,8 +110,8 @@ async def test_connect_logs_connect_time(
async def test_connect_query_fails(all_fixture_data: dict, mocker):
"""Make sure that connect fails when query fails."""
host = "127.0.0.1"
mocker.patch("kasa.IotProtocol.query", side_effect=SmartDeviceException)
mocker.patch("kasa.SmartProtocol.query", side_effect=SmartDeviceException)
mocker.patch("kasa.IotProtocol.query", side_effect=KasaException)
mocker.patch("kasa.SmartProtocol.query", side_effect=KasaException)
ctype, _ = _get_connection_type_device_class(all_fixture_data)
config = DeviceConfig(
@@ -120,7 +120,7 @@ async def test_connect_query_fails(all_fixture_data: dict, mocker):
protocol_class = get_protocol(config).__class__
close_mock = mocker.patch.object(protocol_class, "close")
assert close_mock.call_count == 0
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await connect(config=config)
assert close_mock.call_count == 1

View File

@@ -8,7 +8,7 @@ from kasa.credentials import Credentials
from kasa.deviceconfig import (
DeviceConfig,
)
from kasa.exceptions import SmartDeviceException
from kasa.exceptions import KasaException
async def test_serialization():
@@ -29,7 +29,7 @@ async def test_serialization():
ids=["invalid-dict", "not-dict"],
)
def test_deserialization_errors(input_value, expected_msg):
with pytest.raises(SmartDeviceException, match=expected_msg):
with pytest.raises(KasaException, match=expected_msg):
DeviceConfig.from_dict(input_value)

View File

@@ -13,14 +13,14 @@ from kasa import (
Device,
DeviceType,
Discover,
SmartDeviceException,
KasaException,
)
from kasa.deviceconfig import (
ConnectionType,
DeviceConfig,
)
from kasa.discover import DiscoveryResult, _DiscoverProtocol, json_dumps
from kasa.exceptions import AuthenticationException, UnsupportedDeviceException
from kasa.exceptions import AuthenticationError, UnsupportedDeviceError
from kasa.iot import IotDevice
from kasa.xortransport import XorEncryption
@@ -94,7 +94,7 @@ async def test_type_detection_lightstrip(dev: Device):
async def test_type_unknown():
invalid_info = {"system": {"get_sysinfo": {"type": "nosuchtype"}}}
with pytest.raises(UnsupportedDeviceException):
with pytest.raises(UnsupportedDeviceError):
Discover._get_device_class(invalid_info)
@@ -151,7 +151,7 @@ async def test_discover_single_hostname(discovery_mock, mocker):
assert update_mock.call_count == 0
mocker.patch("socket.getaddrinfo", side_effect=socket.gaierror())
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
x = await Discover.discover_single(host, credentials=Credentials())
@@ -161,7 +161,7 @@ async def test_discover_single_unsupported(unsupported_device_info, mocker):
# Test with a valid unsupported response
with pytest.raises(
UnsupportedDeviceException,
UnsupportedDeviceError,
):
await Discover.discover_single(host)
@@ -171,7 +171,7 @@ async def test_discover_single_no_response(mocker):
host = "127.0.0.1"
mocker.patch.object(_DiscoverProtocol, "do_discover")
with pytest.raises(
SmartDeviceException, match=f"Timed out getting discovery response for {host}"
KasaException, match=f"Timed out getting discovery response for {host}"
):
await Discover.discover_single(host, discovery_timeout=0)
@@ -198,7 +198,7 @@ async def test_discover_invalid_info(msg, data, mocker):
mocker.patch.object(_DiscoverProtocol, "do_discover", mock_discover)
with pytest.raises(SmartDeviceException, match=msg):
with pytest.raises(KasaException, match=msg):
await Discover.discover_single(host)
@@ -280,11 +280,11 @@ async def test_discover_single_authentication(discovery_mock, mocker):
mocker.patch.object(
device_class,
"update",
side_effect=AuthenticationException("Failed to authenticate"),
side_effect=AuthenticationError("Failed to authenticate"),
)
with pytest.raises(
AuthenticationException,
AuthenticationError,
match="Failed to authenticate",
):
device = await Discover.discover_single(
@@ -315,7 +315,7 @@ async def test_device_update_from_new_discovery_info(discovery_data):
# TODO implement requires_update for SmartDevice
if isinstance(device, IotDevice):
with pytest.raises(
SmartDeviceException,
KasaException,
match=re.escape("You need to await update() to access the data"),
):
assert device.supported_modules
@@ -456,9 +456,9 @@ async def test_discover_propogates_task_exceptions(discovery_mock):
discovery_timeout = 0
async def on_discovered(dev):
raise SmartDeviceException("Dummy exception")
raise KasaException("Dummy exception")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await Discover.discover(
discovery_timeout=discovery_timeout, on_discovered=on_discovered
)

View File

@@ -10,7 +10,7 @@ from voluptuous import (
Schema,
)
from kasa import EmeterStatus, SmartDeviceException
from kasa import EmeterStatus, KasaException
from kasa.iot import IotDevice
from kasa.iot.modules.emeter import Emeter
@@ -38,16 +38,16 @@ CURRENT_CONSUMPTION_SCHEMA = Schema(
async def test_no_emeter(dev):
assert not dev.has_emeter
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.get_emeter_realtime()
# Only iot devices support the historical stats so other
# devices will not implement the methods below
if isinstance(dev, IotDevice):
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.get_emeter_daily()
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.get_emeter_monthly()
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.erase_emeter_stats()

View File

@@ -6,9 +6,9 @@ import pytest
from ..deviceconfig import DeviceConfig
from ..exceptions import (
ConnectionException,
SmartDeviceException,
TimeoutException,
KasaException,
TimeoutError,
_ConnectionError,
)
from ..httpclient import HttpClient
@@ -18,28 +18,28 @@ from ..httpclient import HttpClient
[
(
aiohttp.ServerDisconnectedError(),
ConnectionException,
_ConnectionError,
"Device connection error: ",
),
(
aiohttp.ClientOSError(),
ConnectionException,
_ConnectionError,
"Device connection error: ",
),
(
aiohttp.ServerTimeoutError(),
TimeoutException,
TimeoutError,
"Unable to query the device, timed out: ",
),
(
asyncio.TimeoutError(),
TimeoutException,
TimeoutError,
"Unable to query the device, timed out: ",
),
(Exception(), SmartDeviceException, "Unable to query the device: "),
(Exception(), KasaException, "Unable to query the device: "),
(
aiohttp.ServerFingerprintMismatch("exp", "got", "host", 1),
SmartDeviceException,
KasaException,
"Unable to query the device: ",
),
],

View File

@@ -12,11 +12,11 @@ from ..aestransport import AesTransport
from ..credentials import Credentials
from ..deviceconfig import DeviceConfig
from ..exceptions import (
AuthenticationException,
ConnectionException,
RetryableException,
SmartDeviceException,
TimeoutException,
AuthenticationError,
KasaException,
TimeoutError,
_ConnectionError,
_RetryableError,
)
from ..httpclient import HttpClient
from ..iotprotocol import IotProtocol
@@ -68,7 +68,7 @@ async def test_protocol_retries_via_client_session(
mocker.patch.object(protocol_class, "BACKOFF_SECONDS_AFTER_TIMEOUT", 0)
config = DeviceConfig(host)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
DUMMY_QUERY, retry_count=retry_count
)
@@ -80,11 +80,11 @@ async def test_protocol_retries_via_client_session(
@pytest.mark.parametrize(
"error, retry_expectation",
[
(SmartDeviceException("dummy exception"), False),
(RetryableException("dummy exception"), True),
(TimeoutException("dummy exception"), True),
(KasaException("dummy exception"), False),
(_RetryableError("dummy exception"), True),
(TimeoutError("dummy exception"), True),
],
ids=("SmartDeviceException", "RetryableException", "TimeoutException"),
ids=("KasaException", "_RetryableError", "TimeoutError"),
)
@pytest.mark.parametrize("transport_class", [AesTransport, KlapTransport])
@pytest.mark.parametrize("protocol_class", [IotProtocol, SmartProtocol])
@@ -97,7 +97,7 @@ async def test_protocol_retries_via_httpclient(
mocker.patch.object(protocol_class, "BACKOFF_SECONDS_AFTER_TIMEOUT", 0)
config = DeviceConfig(host)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
DUMMY_QUERY, retry_count=retry_count
)
@@ -115,11 +115,11 @@ async def test_protocol_no_retry_on_connection_error(
conn = mocker.patch.object(
aiohttp.ClientSession,
"post",
side_effect=AuthenticationException("foo"),
side_effect=AuthenticationError("foo"),
)
mocker.patch.object(protocol_class, "BACKOFF_SECONDS_AFTER_TIMEOUT", 0)
config = DeviceConfig(host)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
DUMMY_QUERY, retry_count=5
)
@@ -139,7 +139,7 @@ async def test_protocol_retry_recoverable_error(
side_effect=aiohttp.ClientOSError("foo"),
)
config = DeviceConfig(host)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
DUMMY_QUERY, retry_count=5
)
@@ -159,7 +159,7 @@ async def test_protocol_reconnect(mocker, retry_count, protocol_class, transport
nonlocal remaining
remaining -= 1
if remaining:
raise ConnectionException("Simulated connection failure")
raise _ConnectionError("Simulated connection failure")
return mock_response
@@ -249,7 +249,7 @@ def test_encrypt_unicode():
),
(
Credentials("shouldfail", "shouldfail"),
pytest.raises(AuthenticationException),
pytest.raises(AuthenticationError),
),
],
ids=("client", "blank", "kasa_setup", "shouldfail"),
@@ -350,7 +350,7 @@ async def test_handshake(
assert protocol._transport._handshake_done is True
response_status = 403
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol._transport.perform_handshake()
assert protocol._transport._handshake_done is False
await protocol.close()
@@ -405,37 +405,37 @@ async def test_query(mocker):
pytest.param(
(403, 403, 403),
True,
pytest.raises(SmartDeviceException),
pytest.raises(KasaException),
id="handshake1-403-status",
),
pytest.param(
(200, 403, 403),
True,
pytest.raises(SmartDeviceException),
pytest.raises(KasaException),
id="handshake2-403-status",
),
pytest.param(
(200, 200, 403),
True,
pytest.raises(AuthenticationException),
pytest.raises(AuthenticationError),
id="request-403-status",
),
pytest.param(
(200, 200, 400),
True,
pytest.raises(SmartDeviceException),
pytest.raises(KasaException),
id="request-400-status",
),
pytest.param(
(200, 200, 200),
False,
pytest.raises(AuthenticationException),
pytest.raises(AuthenticationError),
id="handshake1-wrong-auth",
),
pytest.param(
(200, 200, 200),
secrets.token_bytes(16),
pytest.raises(SmartDeviceException),
pytest.raises(KasaException),
id="handshake1-bad-auth-length",
),
],

View File

@@ -1,7 +1,7 @@
import pytest
from kasa import DeviceType
from kasa.exceptions import SmartDeviceException
from kasa.exceptions import KasaException
from kasa.iot import IotLightStrip
from .conftest import lightstrip
@@ -23,7 +23,7 @@ async def test_lightstrip_effect(dev: IotLightStrip):
@lightstrip
async def test_effects_lightstrip_set_effect(dev: IotLightStrip):
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev.set_effect("Not real")
await dev.set_effect("Candy Cane")

View File

@@ -14,7 +14,7 @@ import pytest
from ..aestransport import AesTransport
from ..credentials import Credentials
from ..deviceconfig import DeviceConfig
from ..exceptions import SmartDeviceException
from ..exceptions import KasaException
from ..iotprotocol import IotProtocol, _deprecated_TPLinkSmartHomeProtocol
from ..klaptransport import KlapTransport, KlapTransportV2
from ..protocol import (
@@ -46,7 +46,7 @@ async def test_protocol_retries(mocker, retry_count, protocol_class, transport_c
conn = mocker.patch("asyncio.open_connection", side_effect=aio_mock_writer)
config = DeviceConfig("127.0.0.1")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
{}, retry_count=retry_count
)
@@ -70,7 +70,7 @@ async def test_protocol_no_retry_on_unreachable(
side_effect=OSError(errno.EHOSTUNREACH, "No route to host"),
)
config = DeviceConfig("127.0.0.1")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
{}, retry_count=5
)
@@ -94,7 +94,7 @@ async def test_protocol_no_retry_connection_refused(
side_effect=ConnectionRefusedError,
)
config = DeviceConfig("127.0.0.1")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
{}, retry_count=5
)
@@ -118,7 +118,7 @@ async def test_protocol_retry_recoverable_error(
side_effect=OSError(errno.ECONNRESET, "Connection reset by peer"),
)
config = DeviceConfig("127.0.0.1")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
{}, retry_count=5
)
@@ -553,7 +553,7 @@ async def test_protocol_will_retry_on_connect(
retry_count = 2
conn = mocker.patch("asyncio.open_connection", side_effect=error)
config = DeviceConfig("127.0.0.1")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
{}, retry_count=retry_count
)
@@ -595,7 +595,7 @@ async def test_protocol_will_retry_on_write(
conn = mocker.patch("asyncio.open_connection", side_effect=aio_mock_writer)
write_mock = mocker.patch("asyncio.StreamWriter.write", side_effect=error)
config = DeviceConfig("127.0.0.1")
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await protocol_class(transport=transport_class(config=config)).query(
{}, retry_count=retry_count
)
@@ -609,9 +609,7 @@ def test_deprecated_protocol():
with pytest.deprecated_call():
from kasa import TPLinkSmartHomeProtocol
with pytest.raises(
SmartDeviceException, match="host or transport must be supplied"
):
with pytest.raises(KasaException, match="host or transport must be supplied"):
proto = TPLinkSmartHomeProtocol()
host = "127.0.0.1"
proto = TPLinkSmartHomeProtocol(host=host)

View File

@@ -21,7 +21,7 @@ from voluptuous import (
)
import kasa
from kasa import Credentials, Device, DeviceConfig, SmartDeviceException
from kasa import Credentials, Device, DeviceConfig, KasaException
from kasa.exceptions import SmartErrorCode
from kasa.iot import IotDevice
from kasa.smart import SmartChildDevice, SmartDevice
@@ -67,8 +67,8 @@ async def test_state_info(dev):
@device_iot
async def test_invalid_connection(dev):
with patch.object(
FakeIotProtocol, "query", side_effect=SmartDeviceException
), pytest.raises(SmartDeviceException):
FakeIotProtocol, "query", side_effect=KasaException
), pytest.raises(KasaException):
await dev.update()
@@ -98,7 +98,7 @@ async def test_initial_update_no_emeter(dev, mocker):
@device_iot
async def test_query_helper(dev):
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dev._query_helper("test", "testcmd", {})
# TODO check for unwrapping?
@@ -328,7 +328,7 @@ async def test_update_no_device_info(dev: SmartDevice):
}
msg = f"get_device_info not found in {mock_response} for device 127.0.0.123"
with patch.object(dev.protocol, "query", return_value=mock_response), pytest.raises(
SmartDeviceException, match=msg
KasaException, match=msg
):
await dev.update()
@@ -348,6 +348,16 @@ def test_deprecated_devices(device_class, use_class):
getattr(module, use_class.__name__)
@pytest.mark.parametrize(
"exceptions_class, use_class", kasa.deprecated_exceptions.items()
)
def test_deprecated_exceptions(exceptions_class, use_class):
msg = f"{exceptions_class} is deprecated, use {use_class.__name__} instead"
with pytest.deprecated_call(match=msg):
getattr(kasa, exceptions_class)
getattr(kasa, use_class.__name__)
def check_mac(x):
if re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", x.lower()):
return x

View File

@@ -1,13 +1,10 @@
from itertools import chain
import pytest
from ..credentials import Credentials
from ..deviceconfig import DeviceConfig
from ..exceptions import (
SMART_RETRYABLE_ERRORS,
SMART_TIMEOUT_ERRORS,
SmartDeviceException,
KasaException,
SmartErrorCode,
)
from ..smartprotocol import _ChildProtocolWrapper
@@ -28,13 +25,10 @@ async def test_smart_device_errors(dummy_protocol, mocker, error_code):
dummy_protocol._transport, "send", return_value=mock_response
)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dummy_protocol.query(DUMMY_QUERY, retry_count=2)
if error_code in chain(SMART_TIMEOUT_ERRORS, SMART_RETRYABLE_ERRORS):
expected_calls = 3
else:
expected_calls = 1
expected_calls = 3 if error_code in SMART_RETRYABLE_ERRORS else 1
assert send_mock.call_count == expected_calls
@@ -124,7 +118,7 @@ async def test_childdevicewrapper_error(dummy_protocol, mocker):
mock_response = {"error_code": 0, "result": {"responseData": {"error_code": -1001}}}
mocker.patch.object(wrapped_protocol._transport, "send", return_value=mock_response)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await wrapped_protocol.query(DUMMY_QUERY)
@@ -180,5 +174,5 @@ async def test_childdevicewrapper_multiplerequest_error(dummy_protocol, mocker):
}
mocker.patch.object(dummy_protocol._transport, "send", return_value=mock_response)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
await dummy_protocol.query(DUMMY_QUERY)

View File

@@ -2,7 +2,7 @@ from datetime import datetime
import pytest
from kasa import SmartDeviceException
from kasa import KasaException
from kasa.iot import IotStrip
from .conftest import handle_turn_on, strip, turn_on
@@ -73,7 +73,7 @@ async def test_get_plug_by_name(dev: IotStrip):
name = dev.children[0].alias
assert dev.get_plug_by_name(name) == dev.children[0] # type: ignore[arg-type]
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
dev.get_plug_by_name("NONEXISTING NAME")
@@ -81,10 +81,10 @@ async def test_get_plug_by_name(dev: IotStrip):
async def test_get_plug_by_index(dev: IotStrip):
assert dev.get_plug_by_index(0) == dev.children[0]
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
dev.get_plug_by_index(-1)
with pytest.raises(SmartDeviceException):
with pytest.raises(KasaException):
dev.get_plug_by_index(len(dev.children))