Skip to content
This repository was archived by the owner on Jun 28, 2024. It is now read-only.

Commit 25d007a

Browse files
authored
fix: Merge pull request #22 from seamapi/better-error-handling
2 parents de66753 + 4533fdd commit 25d007a

File tree

7 files changed

+50
-13
lines changed

7 files changed

+50
-13
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ python = "^3.7"
1010
requests = "^2.26.0"
1111
python-dotenv = "^0.19.2"
1212
dataclasses-json = "^0.5.6"
13-
testcontainers = {extras = ["postgresql"], version = "^3.4.2"}
1413

1514
[tool.poetry.dev-dependencies]
1615
pytest = "^6.2.5"
1716
black = "^21.12b0"
17+
testcontainers = {extras = ["postgresql"], version = "^3.4.2"}
1818

1919
[build-system]
2020
requires = ["poetry-core>=1.0.0"]

seamapi/access_codes.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,4 @@ def delete(
271271
action_attempt = self.seam.action_attempts.poll_until_ready(
272272
res.json()["action_attempt"]["action_attempt_id"]
273273
)
274-
if action_attempt.status == "error" and action_attempt.error:
275-
raise Exception(
276-
f"{action_attempt.error.type}: {action_attempt.error.message}"
277-
)
278274
return action_attempt

seamapi/action_attempts.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
ActionAttemptError,
44
ActionAttempt,
55
AbstractSeam as Seam,
6+
ActionAttemptFailedException,
67
ActionAttemptId,
78
)
89
import time
@@ -87,7 +88,9 @@ def get(
8788
)
8889

8990
def poll_until_ready(
90-
self, action_attempt: Union[ActionAttemptId, ActionAttempt]
91+
self,
92+
action_attempt: Union[ActionAttemptId, ActionAttempt],
93+
should_raise: bool = True,
9194
) -> ActionAttempt:
9295
"""
9396
Polls an action attempt until its status is 'success' or 'error'.
@@ -104,9 +107,22 @@ def poll_until_ready(
104107

105108
updated_action_attempt = None
106109
while (
107-
updated_action_attempt is None
108-
or updated_action_attempt.status == "pending"
110+
updated_action_attempt is None or updated_action_attempt.status == "pending"
109111
):
110112
updated_action_attempt = self.get(action_attempt)
111113
time.sleep(0.25)
114+
115+
if updated_action_attempt.status == "error" and should_raise:
116+
error_type = None
117+
error_message = None
118+
if updated_action_attempt.error is not None:
119+
error_type = updated_action_attempt.error.type
120+
error_message = updated_action_attempt.error.message
121+
raise ActionAttemptFailedException(
122+
action_attempt_id=updated_action_attempt.action_attempt_id,
123+
action_type=updated_action_attempt.action_type,
124+
error_type=error_type,
125+
error_message=error_message,
126+
)
127+
112128
return updated_action_attempt

seamapi/types.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@
1616
WorkspaceId = str
1717

1818

19+
class ActionAttemptFailedException(Exception):
20+
def __init__(
21+
self,
22+
action_attempt_id: Optional[str] = None,
23+
action_type: Optional[str] = None,
24+
error_type: Optional[str] = None,
25+
error_message: Optional[str] = None,
26+
):
27+
self.action_attempt_id = action_attempt_id
28+
self.action_type = action_type
29+
self.error_type = error_type
30+
self.error_message = error_message
31+
super().__init__(
32+
f'Action Attempt for "{action_type}" Failed. {error_type}: {error_message} (action_attempt_id={action_attempt_id})'
33+
)
34+
35+
1936
@dataclass
2037
class Device:
2138
device_id: DeviceId
@@ -100,7 +117,9 @@ def get(
100117

101118
@abc.abstractmethod
102119
def poll_until_ready(
103-
self, action_attempt: Union[ActionAttemptId, ActionAttempt]
120+
self,
121+
action_attempt: Union[ActionAttemptId, ActionAttempt],
122+
should_raise: bool = True,
104123
) -> ActionAttempt:
105124
raise NotImplementedError
106125

@@ -158,7 +177,7 @@ def update(
158177
def delete(
159178
self,
160179
access_code: Union[AccessCodeId, AccessCode],
161-
) -> None:
180+
) -> ActionAttempt:
162181
raise NotImplementedError
163182

164183

tests/access_codes/test_access_codes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from seamapi import Seam
2+
from seamapi.types import ActionAttemptFailedException
23
from tests.fixtures.run_august_factory import run_august_factory
4+
import pytest
35

46

57
def test_access_codes(seam: Seam):
@@ -19,6 +21,9 @@ def test_access_codes(seam: Seam):
1921
access_code = seam.access_codes.get(created_access_code.access_code_id)
2022
assert access_code.code == "4444"
2123

24+
with pytest.raises(ActionAttemptFailedException):
25+
seam.access_codes.create(some_device.device_id, "Duplicate Access Code", "4444")
26+
2227
access_code = seam.access_codes.update(access_code, name="Updated name")
2328
assert access_code.name == "Updated name"
2429

tests/conftest.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ def seam_backend():
3131
db_url = f"postgresql://test:test@{db_host}:{pg.get_exposed_port(pg.port_to_expose)}/postgres"
3232
with DockerContainer("registry.digitalocean.com/seam/seam-connect").with_env(
3333
"DATABASE_URL",
34-
# TODO on mac us docker.host.internal instead of 172.17.0.1 when someone
35-
# with a mac needs to run tests
3634
db_url,
3735
).with_env("POSTGRES_DATABASE", "postgres").with_env(
3836
"NODE_ENV", "test"

tests/fixtures/run_august_factory.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
def run_august_factory(seam: Seam):
7-
factory_res = requests.post(
7+
requests.post(
88
f"{seam.api_url}/internal/scenarios/factories/load",
99
json={
1010
"factory_name": "create_august_devices",
@@ -15,3 +15,6 @@ def run_august_factory(seam: Seam):
1515
"Authorization": f"Bearer {seam.api_key}",
1616
},
1717
)
18+
19+
# TODO remove when sync is supported in /internal/scenarios/factories/load
20+
time.sleep(0.2)

0 commit comments

Comments
 (0)