8000 Refactor exception classes · python-kasa/python-kasa@277ac5d · GitHub
[go: up one dir, main page]

Skip to content

Commit 277ac5d

Browse files
committed
Refactor exception classes
1 parent 4beff22 commit 277ac5d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+353
-344
lines changed

devtools/dump_devinfo.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222

2323
from devtools.helpers.smartrequests import SmartRequest, get_component_requests
2424
from kasa import (
25-
AuthenticationException,
25+
AuthenticationError,
2626
Credentials,
2727
Device,
2828
Discover,
29-
SmartDeviceException,
30-
TimeoutException,
29+
KasaException,
30+
TimeoutError,
3131
)< 93D4 /div>
3232
from kasa.discover import DiscoveryResult
3333
from kasa.exceptions import SmartErrorCode
@@ -303,19 +303,16 @@ async def _make_requests_or_exit(
303303
for method, result in responses.items():
304304
final[method] = result
305305
return final
306-
except AuthenticationException as ex:
306+
except AuthenticationError as ex:
307307
_echo_error(
308308
f"Unable to query the device due to an authentication error: {ex}",
309309
)
310310
exit(1)
311-
except SmartDeviceException as ex:
311+
except KasaException as ex:
312312
_echo_error(
313313
f"Unable to query {name} at once: {ex}",
314314
)
315-
if (
316-
isinstance(ex, TimeoutException)
317-
or ex.error_code == SmartErrorCode.SESSION_TIMEOUT_ERROR
318-
):
315+
if isinstance(ex, TimeoutError):
319316
_echo_error(
320317
"Timeout, try reducing the batch size via --batch-size option.",
321318
)
@@ -400,7 +397,7 @@ async def get_smart_fixture(device: SmartDevice, batch_size: int):
400397
response = await device.protocol.query(
401398
SmartRequest._create_request_dict(test_call.request)
402399
)
403-
except AuthenticationException as ex:
400+
except AuthenticationError as ex:
404401
_echo_error(
405402
f"Unable to query the device due to an authentication error: {ex}",
406403
)

kasa/__init__.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
For device type specific actions `SmartBulb`, `SmartPlug`, or `SmartStrip`
99
should be used instead.
1010
11-
Module-specific errors are raised as `SmartDeviceException` and are expected
11+
Module-specific errors are raised as `KasaException` and are expected
1212
to be handled by the user of the library.
1313
"""
1414
from importlib.metadata import version
@@ -28,10 +28,11 @@
2828
from kasa.discover import Discover
2929
from kasa.emeterstatus import EmeterStatus
3030
from kasa.exceptions import (
31-
AuthenticationException,
32-
SmartDeviceException,
33-
TimeoutException,
34-
UnsupportedDeviceException,
31+
AuthenticationError,
32+
DeviceError,
33+
KasaException,
34+
TimeoutError,
35+
UnsupportedDeviceError,
3536
)
3637
from kasa.feature import Feature, FeatureType
3738
from kasa.iot.iotbulb import BulbPreset, TurnOnBehavior, TurnOnBehaviors
@@ -61,10 +62,11 @@
6162
"Device",
6263
"Bulb",
6364
"Plug",
64-
"SmartDeviceException",
65-
"AuthenticationException",
66-
"UnsupportedDeviceException",
67-
"TimeoutException",
65+
"KasaException",
66+
"AuthenticationError",
67+
"DeviceError",
68+
"UnsupportedDeviceError",
69+
"TimeoutError",
6870
"Credentials",
6971
"DeviceConfig",
7072
"ConnectionType",
@@ -84,6 +86,12 @@
8486
"SmartDimmer": iot.IotDimmer,
8587
"SmartBulbPreset": BulbPreset,
8688
}
89+
deprecated_exceptions = {
90+
"SmartDeviceException": KasaException,
91+
"UnsupportedDeviceException": UnsupportedDeviceError,
92+
"AuthenticationException": AuthenticationError,
93+
"TimeoutException": TimeoutError,
94+
}
8795

8896

8997
def __getattr__(name):
@@ -101,6 +109,11 @@ def __getattr__(name):
101109
stacklevel=1,
102110
)
103111
return new_class
112+
if name in deprecated_exceptions:
113+
new_class = deprecated_exceptions[name]
114+
msg = f"{name} is deprecated, use {new_class.__name__} instead"
115+
warn(msg, DeprecationWarning, stacklevel=1)
116+
return new_class
104117
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
105118

106119

@@ -112,6 +125,11 @@ def __getattr__(name):
112125
SmartStrip = iot.IotStrip
113126
SmartDimmer = iot.IotDimmer
114127
SmartBulbPreset = BulbPreset
128+
129+
SmartDeviceException = KasaException
130+
UnsupportedDeviceException = UnsupportedDeviceError
131+
AuthenticationException = AuthenticationError
132+
TimeoutException = TimeoutError
115133
# Instanstiate all classes so the type checkers catch abstract issues
116134
from . import smart
117135

kasa/aestransport.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,11 @@
2222
from .exceptions import (
2323
SMART_AUTHENTICATION_ERRORS,
2424
SMART_RETRYABLE_ERRORS,
25-
SMART_TIMEOUT_ERRORS,
26-
AuthenticationException,
27-
RetryableException,
28-
SmartDeviceException,
25+
AuthenticationError,
26+
DeviceError,
27+
KasaException,
2928
SmartErrorCode,
30-
TimeoutException,
29+
_RetryableError,
3130
)
3231
from .httpclient import HttpClient
3332
from .json import dumps as json_dumps
@@ -141,14 +140,12 @@ def _handle_response_error_code(self, resp_dict: Any, msg: str) -> None:
141140
if error_code == SmartErrorCode.SUCCESS:
142141
return
143142
msg = f"{msg}: {self._host}: {error_code.name}({error_code.value})"
144-
if error_code in SMART_TIMEOUT_ERRORS:
145-
raise TimeoutException(msg, error_code=error_code)
146143
if error_code in SMART_RETRYABLE_ERRORS:
147-
raise RetryableException(msg, error_code=error_code)
144+
raise _RetryableError(msg, error_code=error_code)
148145
if error_code in SMART_AUTHENTICATION_ERRORS:
149146
self._state = TransportState.HANDSHAKE_REQUIRED
150-
raise AuthenticationException(msg, error_code=error_code)
151-
raise SmartDeviceException(msg, error_code=error_code)
147+
raise AuthenticationError(msg, error_code=error_code)
148+
raise DeviceError(msg, error_code=error_code)
152149

153150
async def send_secure_passthrough(self, request: str) -> Dict[str, Any]:
154151
"""Send encrypted message as passthrough."""
@@ -171,7 +168,7 @@ async def send_secure_passthrough(self, request: str) -> Dict[str, Any]:
171168
# _LOGGER.debug(f"se 98D cure_passthrough response is {status_code}: {resp_dict}")
172169

173170
if status_code != 200:
174-
raise SmartDeviceException(
171+
raise KasaException(
175172
f"{self._host} responded with an unexpected "
176173
+ f"status code {status_code} to passthrough"
177174
)
@@ -197,7 +194,7 @@ async def send_secure_passthrough(self, request: str) -> Dict[str, Any]:
197194
self._host,
198195
)
199196
except Exception:
200-
raise SmartDeviceException(
197+
raise KasaException(
201198
f"Unable to decrypt response from {self._host}, "
202199
+ f"error: {ex}, response: {raw_response}",
203200
ex,
@@ -208,7 +205,7 @@ async def perform_login(self):
208205
"""Login to the device."""
209206
try:
210207
await self.try_login(self._login_params)
211-
except AuthenticationException as aex:
208+
except AuthenticationError as aex:
212209
try:
213210
if aex.error_code is not SmartErrorCode.LOGIN_ERROR:
214211
raise aex
@@ -223,10 +220,10 @@ async def perform_login(self):
223220
"%s: logged in with default credentials",
224221
self._host,
225222
)
226-
except AuthenticationException:
223+
except AuthenticationError:
227224
raise
228225
except Exception as ex:
229-
raise SmartDeviceException(
226+
raise KasaException(
230227
"Unable to login and trying default "
231228
+ f"login raised another exception: {ex}",
232229
ex,
@@ -292,7 +289,7 @@ async def perform_handshake(self) -> None:
292289
_LOGGER.debug("Device responded with: %s", resp_dict)
293290

294291
if status_code != 200:
295-
raise SmartDeviceException(
292+
raise KasaException(
296293
f"{self._host} responded with an unexpected "
297294
+ f"status code {status_code} to handshake"
298295
)
@@ -347,7 +344,7 @@ async def send(self, request: str) -> Dict[str, Any]:
347344
await self.perform_login()
348345
# After a login failure handshake needs to
349346
# be redone or a 9999 error is received.
350-
except AuthenticationException as ex:
347+
except AuthenticationError as ex:
351348
self._state = TransportState.HANDSHAKE_REQUIRED
352349
raise ex
353350

kasa/cli.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import asyncclick as click
1414

1515
from kasa import (
16-
AuthenticationException,
16+
AuthenticationError,
1717
Bulb,
1818
ConnectionType,
1919
Credentials,
@@ -22,8 +22,8 @@
2222
DeviceFamilyType,
2323
Discover,
2424
EncryptType,
25-
SmartDeviceException,
26-
UnsupportedDeviceException,
25+
KasaException,
26+
UnsupportedDeviceError,
2727
)
2828
from kasa.discover import DiscoveryResult
2929
from kasa.iot import IotBulb, IotDevice, IotDimmer, IotLightStrip, IotPlug, IotStrip
@@ -458,7 +458,7 @@ async def discover(ctx):
458458
unsupported = []
459459
auth_failed = []
460460

461-
async def print_unsupported(unsupported_exception: UnsupportedDeviceException):
461+
async def print_unsupported(unsupported_exception: UnsupportedDeviceError):
462462
unsupported.append(unsupported_exception)
463463
async with sem:
464464
if unsupported_exception.discovery_result:
@@ -476,7 +476,7 @@ async def print_discovered(dev: Device):
476476
async with sem:
477477
try:
478478
await dev.update()
479-
except AuthenticationException:
479+
except AuthenticationError:
480480
auth_failed.append(dev._discovery_info)
481481
echo("== Authentication failed for device ==")
482482
_echo_discovery_info(dev._discovery_info)
@@ -677,7 +677,7 @@ async def cmd_command(dev: Device, module, command, parameters):
677677
elif isinstance(dev, SmartDevice):
678678
res = await dev._query_helper(command, parameters)
679679
else:
680-
raise SmartDeviceException("Unexpected device type %s.", dev)
680+
raise KasaException("Unexpected device type %s.", dev)
681681
echo(json.dumps(res))
682682
return res
683683

kasa/device.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .device_type import DeviceType
1010
from .deviceconfig import DeviceConfig
1111
from .emeterstatus import EmeterStatus
12-
from .exceptions import SmartDeviceException
12+
from .exceptions import KasaException
1313
from .feature import Feature
1414
from .iotprotocol import IotProtocol
1515
from .protocol import BaseProtocol
@@ -242,12 +242,12 @@ def get_plug_by_name(self, name: str) -> "Device":
242242
if p.alias == name:
243243
return p
244244

245-
raise SmartDeviceException(f"Device has no child with {name}")
245+
raise KasaException(f"Device has no child with {name}")
246246

247247
def get_plug_by_index(self, index: int) -> "Device":
248248
"""Return child device for the given index."""
249249
if index + 1 > len(self.children) or index < 0:
250-
raise SmartDeviceException(
250+
raise KasaException(
251251
f"Invalid index {index}, device has {len(self.children)} plugs"
252252
)
253253
return self.children[index]
@@ -306,7 +306,7 @@ def _add_feature(self, feature: Feature):
306306
"""Add a new feature to the device."""
307307
desc_name = feature.name.lower().replace(" ", "_")
308308
if desc_name in self._features:
309-
raise SmartDeviceException("Duplicate feature name %s" % desc_name)
309+
raise KasaException("Duplicate feature name %s" % desc_name)
310310
self._features[desc_name] = feature
311311

312312
@property

kasa/device_factory.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .aestransport import AesTransport
77
from .device import Device
88
from .deviceconfig import DeviceConfig
9-
from .exceptions import SmartDeviceException, UnsupportedDeviceException
9+
from .exceptions import KasaException, UnsupportedDeviceError
1010
from .iot import IotBulb, IotDevice, IotDimmer, IotLightStrip, IotPlug, IotStrip
1111
from .iotprotocol import IotProtocol
1212
from .klaptransport import KlapTransport, KlapTransportV2
@@ -45,12 +45,12 @@ async def connect(*, host: Optional[str] = None, config: DeviceConfig) -> "Devic
4545
:return: Object for querying/controlling found device.
4646
"""
4747
if host and config or (not host and not config):
48-
raise SmartDeviceException("One of host or config must be provded and not both")
48+
raise KasaException("One of host or config must be provded and not both")
4949
if host:
5050
config = DeviceConfig(host=host)
5151

5252
if (protocol := get_protocol(config=config)) is None:
53-
raise UnsupportedDeviceException(
53+
raise UnsupportedDeviceError(
5454
f"Unsupported device for {config.host}: "
5555
+ f"{config.connection_type.device_family.value}"
5656
)
@@ -99,7 +99,7 @@ def _perf_log(has_params, perf_type):
9999
_perf_log(True, "update")
100100
return device
101101
else:
102-
raise UnsupportedDeviceException(
102+
raise UnsupportedDeviceError(
103103
f"Unsupported device for {config.host}: "
104104
+ f"{config.connection_type.device_family.value}"
105105
)
@@ -108,12 +108,12 @@ def _perf_log(has_params, perf_type):
108108
def get_device_class_from_sys_info(info: Dict[str, Any]) -> Type[IotDevice]:
109109
"""Find SmartDevice subclass for device described by passed data."""
110110
if "system" not in info or "get_sysinfo" not in info["system"]:
111-
raise SmartDeviceException("No 'system' or 'get_sysinfo' in response")
111+
raise KasaException("No 'system' or 'get_sysinfo' in response")
112112

113113
sysinfo: Dict[str, Any] = info["system"]["get_sysinfo"]
114114
type_: Optional[str] = sysinfo.get("type", sysinfo.get("mic_type"))
115115
if type_ is None:
116-
raise SmartDeviceException("Unable to find the device type field!")
116+
raise KasaException("Unable to find the device type field!")
117117

118118
if "dev_name" in sysinfo and "Dimmer" in sysinfo["dev_name"]:
119119
return IotDimmer
@@ -129,7 +129,7 @@ def get_device_class_from_sys_info(info: Dict[str, Any]) -> Type[IotDevice]:
129129
return IotLightStrip
130130

131131
return IotBulb
132-
raise UnsupportedDeviceException("Unknown device type: %s" % type_)
132+
raise UnsupportedDeviceError("Unknown device type: %s" % type_)
133133

134134

135135
def get_device_class_from_family(device_type: str) -> Optional[Type[Device]]:

kasa/deviceconfig.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing import TYPE_CHECKING, Dict, Optional, Union
66

77
from .credentials import Credentials
8-
from .exceptions import SmartDeviceException
8+
from .exceptions import KasaException
99

1010
if TYPE_CHECKING:
1111
from aiohttp import ClientSession
@@ -46,7 +46,7 @@ def _dataclass_from_dict(klass, in_val):
4646
fieldtypes[dict_key], in_val[dict_key]
4747
)
4848
else:
49-
raise SmartDeviceException(
49+
raise KasaException(
5050
f"Cannot create dataclass from dict, unknown key: {dict_key}"
5151
)
5252
return klass(**val)
@@ -92,7 +92,7 @@ def from_values(
9292
login_version,
9393
)
9494
except (ValueError, TypeError) as ex:
95-
raise SmartDeviceException(
95+
raise KasaException(
9696
f"Invalid connection parameters for {device_family}."
9797
+ f"{encryption_type}.{login_version}"
9898
) from ex
@@ -113,9 +113,7 @@ def from_dict(connection_type_dict: Dict[str, str]) -> "ConnectionType":
113113
login_version, # type: ignore[arg-type]
114114
)
115115

116-
raise SmartDeviceException(
117-
f"Invalid connection type data for {connection_type_dict}"
118-
)
116+
raise KasaException(f"Invalid connection type data for {connection_type_dict}")
119117

120118
def to_dict(self) -> Dict[str, Union[str, int]]:
121119
"""Convert connection params to dict."""
@@ -185,4 +183,4 @@ def from_dict(config_dict: Dict[str, Dict[str, str]]) -> "DeviceConfig":
185183
"""Return device config from dict."""
186184
if isinstance(config_dict, dict):
187185
return _dataclass_from_dict(DeviceConfig, config_dict)
188-
raise SmartDeviceException(f"Invalid device config data: {config_dict}")
186+
raise KasaException(f"Invalid device config data: {config_dict}")

0 commit comments

Comments
 (0)
0