Skip to content
This repository was archived by the owner on Jun 28, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ python = "^3.7"
requests = "^2.26.0"
python-dotenv = "^0.19.2"
dataclasses-json = "^0.5.6"
testcontainers = {extras = ["postgresql"], version = "^3.4.2"}

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

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
4 changes: 0 additions & 4 deletions seamapi/access_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,4 @@ def delete(
action_attempt = self.seam.action_attempts.poll_until_ready(
res.json()["action_attempt"]["action_attempt_id"]
)
if action_attempt.status == "error" and action_attempt.error:
raise Exception(
f"{action_attempt.error.type}: {action_attempt.error.message}"
)
return action_attempt
22 changes: 19 additions & 3 deletions seamapi/action_attempts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ActionAttemptError,
ActionAttempt,
AbstractSeam as Seam,
ActionAttemptFailedException,
ActionAttemptId,
)
import time
Expand Down Expand Up @@ -87,7 +88,9 @@ def get(
)

def poll_until_ready(
self, action_attempt: Union[ActionAttemptId, ActionAttempt]
self,
action_attempt: Union[ActionAttemptId, ActionAttempt],
should_raise: bool = True,
) -> ActionAttempt:
"""
Polls an action attempt until its status is 'success' or 'error'.
Expand All @@ -104,9 +107,22 @@ def poll_until_ready(

updated_action_attempt = None
while (
updated_action_attempt is None
or updated_action_attempt.status == "pending"
updated_action_attempt is None or updated_action_attempt.status == "pending"
):
updated_action_attempt = self.get(action_attempt)
time.sleep(0.25)

if updated_action_attempt.status == "error" and should_raise:
error_type = None
error_message = None
if updated_action_attempt.error is not None:
error_type = updated_action_attempt.error.type
error_message = updated_action_attempt.error.message
raise ActionAttemptFailedException(
action_attempt_id=updated_action_attempt.action_attempt_id,
action_type=updated_action_attempt.action_type,
error_type=error_type,
error_message=error_message,
)

return updated_action_attempt
23 changes: 21 additions & 2 deletions seamapi/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@
WorkspaceId = str


class ActionAttemptFailedException(Exception):
def __init__(
self,
action_attempt_id: Optional[str] = None,
action_type: Optional[str] = None,
error_type: Optional[str] = None,
error_message: Optional[str] = None,
):
self.action_attempt_id = action_attempt_id
self.action_type = action_type
self.error_type = error_type
self.error_message = error_message
super().__init__(
f'Action Attempt for "{action_type}" Failed. {error_type}: {error_message} (action_attempt_id={action_attempt_id})'
)


@dataclass
class Device:
device_id: DeviceId
Expand Down Expand Up @@ -100,7 +117,9 @@ def get(

@abc.abstractmethod
def poll_until_ready(
self, action_attempt: Union[ActionAttemptId, ActionAttempt]
self,
action_attempt: Union[ActionAttemptId, ActionAttempt],
should_raise: bool = True,
) -> ActionAttempt:
raise NotImplementedError

Expand Down Expand Up @@ -158,7 +177,7 @@ def update(
def delete(
self,
access_code: Union[AccessCodeId, AccessCode],
) -> None:
) -> ActionAttempt:
raise NotImplementedError


Expand Down
5 changes: 5 additions & 0 deletions tests/access_codes/test_access_codes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from seamapi import Seam
from seamapi.types import ActionAttemptFailedException
from tests.fixtures.run_august_factory import run_august_factory
import pytest


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

with pytest.raises(ActionAttemptFailedException):
seam.access_codes.create(some_device.device_id, "Duplicate Access Code", "4444")

access_code = seam.access_codes.update(access_code, name="Updated name")
assert access_code.name == "Updated name"

Expand Down
2 changes: 0 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ def seam_backend():
db_url = f"postgresql://test:test@{db_host}:{pg.get_exposed_port(pg.port_to_expose)}/postgres"
with DockerContainer("registry.digitalocean.com/seam/seam-connect").with_env(
"DATABASE_URL",
# TODO on mac us docker.host.internal instead of 172.17.0.1 when someone
# with a mac needs to run tests
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove bc already added on line 30

db_url,
).with_env("POSTGRES_DATABASE", "postgres").with_env(
"NODE_ENV", "test"
Expand Down
5 changes: 4 additions & 1 deletion tests/fixtures/run_august_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def run_august_factory(seam: Seam):
factory_res = requests.post(
requests.post(
f"{seam.api_url}/internal/scenarios/factories/load",
json={
"factory_name": "create_august_devices",
Expand All @@ -15,3 +15,6 @@ def run_august_factory(seam: Seam):
"Authorization": f"Bearer {seam.api_key}",
},
)

# TODO remove when sync is supported in /internal/scenarios/factories/load
time.sleep(0.2)