Skip to content

Commit d16acbe

Browse files
authored
feat: improve exception messages (#488)
Follow the action error message pattern that we used in hcloud-go.
1 parent ae096ba commit d16acbe

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

hcloud/_exceptions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44

55

66
class HCloudException(Exception):
7-
"""There was an error while using the hcloud library"""
7+
"""There was an error while using the hcloud library.
8+
9+
All exceptions in the hcloud library inherit from this exception. It may be used as
10+
catch-all exception.
11+
"""
812

913

1014
class APIException(HCloudException):
11-
"""There was an error while performing an API Request"""
15+
"""There was an error while performing an API Request."""
1216

1317
def __init__(
1418
self,

hcloud/actions/domain.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,22 @@ class ActionException(HCloudException):
7171
def __init__(self, action: Action | BoundAction):
7272
assert self.__doc__ is not None
7373
message = self.__doc__
74-
if action.error is not None and "message" in action.error:
74+
75+
extras = []
76+
if (
77+
action.error is not None
78+
and "code" in action.error
79+
and "message" in action.error
80+
):
7581
message += f": {action.error['message']}"
7682

83+
extras.append(action.error["code"])
84+
else:
85+
extras.append(action.command)
86+
87+
extras.append(str(action.id))
88+
message += f" ({', '.join(extras)})"
89+
7790
super().__init__(message)
7891
self.message = message
7992
self.action = action

tests/unit/test_exceptions.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
from hcloud import (
6+
APIException,
7+
HCloudException,
8+
)
9+
from hcloud.actions import Action, ActionFailedException, ActionTimeoutException
10+
11+
running_action = Action(
12+
id=12345,
13+
command="action_command",
14+
status=Action.STATUS_RUNNING,
15+
)
16+
17+
failed_action = Action(
18+
id=12345,
19+
command="action_command",
20+
status=Action.STATUS_ERROR,
21+
error={"code": "action_failed", "message": "Action failed"},
22+
)
23+
24+
25+
@pytest.mark.parametrize(
26+
("exception", "expected"),
27+
[
28+
(
29+
# Should never be raised by itself
30+
HCloudException(),
31+
"",
32+
),
33+
(
34+
# Should never be raised by itself
35+
HCloudException("A test error"),
36+
"A test error",
37+
),
38+
(
39+
APIException(code="conflict", message="API error message", details=None),
40+
"API error message (conflict)",
41+
),
42+
(
43+
APIException(
44+
code="conflict",
45+
message="API error message",
46+
details=None,
47+
correlation_id="fddea8fabd02fb21",
48+
),
49+
"API error message (conflict, fddea8fabd02fb21)",
50+
),
51+
(
52+
ActionFailedException(failed_action),
53+
"The pending action failed: Action failed (action_failed, 12345)",
54+
),
55+
(
56+
ActionTimeoutException(running_action),
57+
"The pending action timed out (action_command, 12345)",
58+
),
59+
],
60+
)
61+
def test_exceptions(exception, expected):
62+
assert str(exception) == expected

0 commit comments

Comments
 (0)