Skip to content

Commit 8475b08

Browse files
committed
Enhance error handling and testing for Overkiz API
- Update `get_current_execution` method to return None for non-existent executions. - Add new exceptions: NoSuchDeviceError and NoSuchActionGroupError. - Introduce error handling probes in `test_error_handling.py` for various invalid inputs. - Add test cases for empty responses and specific error scenarios in `test_client.py`. - Create JSON fixtures for various error responses to improve testing coverage.
1 parent b034971 commit 8475b08

21 files changed

+1112
-14
lines changed

pyoverkiz/client.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,16 @@ async def unregister_event_listener(self) -> None:
447447
self.event_listener_id = None
448448

449449
@retry_on_auth_error
450-
async def get_current_execution(self, exec_id: str) -> Execution:
451-
"""Get a currently running execution by its exec_id."""
450+
async def get_current_execution(self, exec_id: str) -> Execution | None:
451+
"""Get a currently running execution by its exec_id.
452+
453+
Returns None if the execution does not exist.
454+
"""
452455
response = await self._get(f"exec/current/{exec_id}")
456+
457+
if not response or not isinstance(response, dict):
458+
return None
459+
453460
return Execution(**decamelize(response))
454461

455462
@retry_on_auth_error

pyoverkiz/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ class UnknownUserError(BaseOverkizError):
9797
"""Raised when an unknown user is provided."""
9898

9999

100+
class NoSuchDeviceError(BaseOverkizError):
101+
"""Raised when the requested device does not exist."""
102+
103+
104+
class NoSuchActionGroupError(BaseOverkizError):
105+
"""Raised when the requested action group does not exist."""
106+
107+
100108
class UnknownObjectError(BaseOverkizError):
101109
"""Raised when an unknown object is provided."""
102110

pyoverkiz/models.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -805,8 +805,11 @@ class Execution:
805805
id: str
806806
description: str
807807
owner: str = field(repr=obfuscate_email)
808-
state: str
808+
state: ExecutionState
809809
action_group: ActionGroup
810+
start_time: int | None = None
811+
execution_type: ExecutionType | None = None
812+
execution_sub_type: ExecutionSubType | None = None
810813

811814
def __init__(
812815
self,
@@ -815,14 +818,22 @@ def __init__(
815818
owner: str,
816819
state: str,
817820
action_group: dict[str, Any],
821+
start_time: int | None = None,
822+
execution_type: str | None = None,
823+
execution_sub_type: str | None = None,
818824
**_: Any,
819825
):
820826
"""Initialize Execution object from API fields."""
821827
self.id = id
822828
self.description = description
823829
self.owner = owner
824-
self.state = state
830+
self.state = ExecutionState(state)
825831
self.action_group = ActionGroup(**action_group)
832+
self.start_time = start_time
833+
self.execution_type = ExecutionType(execution_type) if execution_type else None
834+
self.execution_sub_type = (
835+
ExecutionSubType(execution_sub_type) if execution_sub_type else None
836+
)
826837

827838

828839
@define(init=False, kw_only=True)
@@ -858,7 +869,7 @@ class ActionGroup:
858869
is composed of one or more commands to be executed on that device.
859870
"""
860871

861-
id: str = field(repr=obfuscate_id)
872+
id: str | None = field(default=None, repr=obfuscate_id)
862873
creation_time: int | None = None
863874
last_update_time: int | None = None
864875
label: str = field(repr=obfuscate_string)
@@ -869,7 +880,7 @@ class ActionGroup:
869880
notification_text: str | None = None
870881
notification_title: str | None = None
871882
actions: list[Action]
872-
oid: str = field(repr=obfuscate_id)
883+
oid: str | None = field(default=None, repr=obfuscate_id)
873884

874885
def __init__(
875886
self,
@@ -888,10 +899,7 @@ def __init__(
888899
**_: Any,
889900
) -> None:
890901
"""Initialize ActionGroup from API data and convert nested actions."""
891-
if oid is None and id is None:
892-
raise ValueError("Either 'oid' or 'id' must be provided")
893-
894-
self.id = cast(str, oid or id)
902+
self.id = oid or id
895903
self.creation_time = creation_time
896904
self.last_update_time = last_update_time
897905
self.label = (
@@ -904,7 +912,7 @@ def __init__(
904912
self.notification_text = notification_text
905913
self.notification_title = notification_title
906914
self.actions = [Action(**action) for action in actions]
907-
self.oid = cast(str, oid or id)
915+
self.oid = oid or id
908916

909917

910918
@define(init=False, kw_only=True)

pyoverkiz/response_handler.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
MissingAPIKeyError,
2323
MissingAuthorizationTokenError,
2424
NoRegisteredEventListenerError,
25+
NoSuchActionGroupError,
26+
NoSuchDeviceError,
2527
NoSuchResourceError,
2628
NoSuchTokenError,
2729
NotAuthenticatedError,
@@ -46,6 +48,8 @@
4648
("INVALID_FIELD_VALUE", None, ActionGroupSetupNotFoundError),
4749
("INVALID_API_CALL", None, NoSuchResourceError),
4850
("EXEC_QUEUE_FULL", None, ExecutionQueueFullError),
51+
("NO_SUCH_DEVICE", None, NoSuchDeviceError),
52+
("NO_SUCH_ACTION_GROUP", None, NoSuchActionGroupError),
4953
# --- errorCode + message substring ---
5054
("AUTHENTICATION_ERROR", "Too many requests", TooManyRequestsError),
5155
("AUTHENTICATION_ERROR", "Bad credentials", BadCredentialsError),

0 commit comments

Comments
 (0)