Skip to content

Commit 13ca41d

Browse files
authored
Add ActionGroupSetupNotFoundException and DuplicateActionOnDeviceException (#1919)
This pull request enhances error handling in the Overkiz client by introducing two new custom exceptions and updating the response checking logic to catch and raise these exceptions based on specific API error messages. Additionally, it refines and clarifies the error message comments for better maintainability. **Error handling improvements:** * Added two new exception classes, `DuplicateActionOnDeviceException` and `ActionGroupSetupNotFoundException`, to `pyoverkiz/exceptions.py` for handling specific API error cases. * Updated `pyoverkiz/client.py` to import the new exceptions. * Modified the `check_response` function in `pyoverkiz/client.py` to detect error messages indicating a duplicate action on a device or a missing action group setup, and to raise the corresponding new exceptions. **Documentation and code clarity:** * Updated comments in `check_response` to use consistent JSON-style formatting for API error messages, improving readability and maintainability. [[1]](diffhunk://#diff-11513003e65960c0b1a4bccb3c6bf2b7dea08c03923a8e53b8dea1a05f213aa2L876-R885) [[2]](diffhunk://#diff-11513003e65960c0b1a4bccb3c6bf2b7dea08c03923a8e53b8dea1a05f213aa2L892-R921) [[3]](diffhunk://#diff-11513003e65960c0b1a4bccb3c6bf2b7dea08c03923a8e53b8dea1a05f213aa2L935-R944) Fixes #1918
1 parent 0aaf7c5 commit 13ca41d

File tree

5 files changed

+44
-9
lines changed

5 files changed

+44
-9
lines changed

pyoverkiz/client.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@
4242
from pyoverkiz.enums import APIType, Server
4343
from pyoverkiz.exceptions import (
4444
AccessDeniedToGatewayException,
45+
ActionGroupSetupNotFoundException,
4546
BadCredentialsException,
4647
CozyTouchBadCredentialsException,
4748
CozyTouchServiceException,
49+
DuplicateActionOnDeviceException,
4850
ExecutionQueueFullException,
4951
InvalidCommandException,
5052
InvalidEventListenerIdException,
@@ -860,8 +862,15 @@ async def check_response(response: ClientResponse) -> None:
860862
# An error message can have an empty (None) message
861863
message = message.strip('".') if (message := result.get("error")) else ""
862864

863-
# {"errorCode": "AUTHENTICATION_ERROR",
864-
# "error": "Too many requests, try again later : login with xxx@xxx.tld"}
865+
# {"errorCode": "DUPLICATE_FIELD_OR_VALUE", "error": "Another action exists on the same device : rts://1234-5689-1234/123456"}
866+
if message.startswith("Another action exists on the same device"):
867+
raise DuplicateActionOnDeviceException(message)
868+
869+
# {"errorCode": "INVALID_FIELD_VALUE", "error": "Unable to determine action group setup (no setup for gateway #1234-5678-1234)"}
870+
if message.startswith("Unable to determine action group setup"):
871+
raise ActionGroupSetupNotFoundException(message)
872+
873+
# {"errorCode": "AUTHENTICATION_ERROR", "error": "Too many requests, try again later : login with xxx@xxx.tld"}
865874
if "Too many requests" in message:
866875
raise TooManyRequestsException(message)
867876

@@ -873,7 +882,7 @@ async def check_response(response: ClientResponse) -> None:
873882
if message == "Not authenticated":
874883
raise NotAuthenticatedException(message)
875884

876-
# {'errorCode': 'AUTHENTICATION_ERROR', 'error': 'An API key is required to access this setup'}
885+
# {"errorCode": "AUTHENTICATION_ERROR", "error": "An API key is required to access this setup"}
877886
if message == "An API key is required to access this setup":
878887
raise MissingAPIKeyException(message)
879888

@@ -889,27 +898,27 @@ async def check_response(response: ClientResponse) -> None:
889898
if "No such command" in message:
890899
raise InvalidCommandException(message)
891900

892-
# {'errorCode': 'UNSPECIFIED_ERROR', 'error': 'Invalid event listener id : ...'}
901+
# {"errorCode": "UNSPECIFIED_ERROR", "error": "Invalid event listener id : ..."}
893902
if "Invalid event listener id" in message:
894903
raise InvalidEventListenerIdException(message)
895904

896-
# {'errorCode': 'UNSPECIFIED_ERROR', 'error': 'No registered event listener'}
905+
# {"errorCode": "UNSPECIFIED_ERROR", "error": "No registered event listener"}
897906
if message == "No registered event listener":
898907
raise NoRegisteredEventListenerException(message)
899908

900-
# {'errorCode': 'AUTHENTICATION_ERROR', 'error': 'No such user account : xxxxx'}
909+
# {"errorCode": "AUTHENTICATION_ERROR", "error": "No such user account : xxxxx"}
901910
if "No such user account" in message:
902911
raise UnknownUserException(message)
903912

904-
# {'errorCode': 'INVALID_API_CALL', 'error': 'No such resource'}
913+
# {"errorCode": "INVALID_API_CALL", "error": "No such resource"}
905914
if message == "No such resource":
906915
raise NoSuchResourceException(message)
907916

908917
# {"errorCode": "RESOURCE_ACCESS_DENIED", "error": "too many concurrent requests"}
909918
if message == "too many concurrent requests":
910919
raise TooManyConcurrentRequestsException(message)
911920

912-
# {'errorCode': 'EXEC_QUEUE_FULL', 'error': 'Execution queue is full on gateway: #xxx-yyyy-zzzz (soft limit: 10)'}
921+
# {"errorCode": "EXEC_QUEUE_FULL", "error": "Execution queue is full on gateway: #xxx-yyyy-zzzz (soft limit: 10)"}
913922
if "Execution queue is full on gateway" in message:
914923
raise ExecutionQueueFullException(message)
915924

@@ -932,7 +941,7 @@ async def check_response(response: ClientResponse) -> None:
932941
if message == "Unknown object":
933942
raise UnknownObjectException(message)
934943

935-
# {'errorCode': 'RESOURCE_ACCESS_DENIED', 'error': 'Access denied to gateway #1234-5678-1234 for action ADD_TOKEN'}
944+
# {"errorCode": "RESOURCE_ACCESS_DENIED", "error": "Access denied to gateway #1234-5678-1234 for action ADD_TOKEN"}
936945
if "Access denied to gateway" in message:
937946
raise AccessDeniedToGatewayException(message)
938947

pyoverkiz/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ class InvalidCommandException(BaseOverkizException):
1717
"""Raised when an invalid command is provided."""
1818

1919

20+
class DuplicateActionOnDeviceException(BaseOverkizException):
21+
"""Raised when another action already exists for the same device."""
22+
23+
24+
class ActionGroupSetupNotFoundException(BaseOverkizException):
25+
"""Raised when an action group setup cannot be determined for a gateway."""
26+
27+
2028
class NoSuchResourceException(BaseOverkizException):
2129
"""Raised when an invalid API call is made."""
2230

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"error": "Unable to determine action group setup (no setup for gateway #1234-5678-1234)",
3+
"errorCode": "INVALID_FIELD_VALUE"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"error": "Another action exists on the same device : rts://1234-5678-1234/123456",
3+
"errorCode": "DUPLICATE_FIELD_OR_VALUE"
4+
}

tests/test_client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,16 @@ async def test_get_diagnostic_data(self, client: OverkizClient, fixture_name: st
311311
exceptions.OverkizException,
312312
400,
313313
),
314+
(
315+
"local/400-duplicate-action-on-device.json",
316+
exceptions.DuplicateActionOnDeviceException,
317+
400,
318+
),
319+
(
320+
"local/400-action-group-setup-not-found.json",
321+
exceptions.ActionGroupSetupNotFoundException,
322+
400,
323+
),
314324
(
315325
"local/400-no-registered-event-listener.json",
316326
exceptions.NoRegisteredEventListenerException,

0 commit comments

Comments
 (0)