From 59a991494f4974032b798b36006a2323a30ffcac Mon Sep 17 00:00:00 2001 From: Scott Divelbiss Date: Tue, 20 Jan 2026 15:30:22 +0100 Subject: [PATCH 1/2] update(httpClient): Add 10 second timeout --- seatsio/httpClient.py | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/seatsio/httpClient.py b/seatsio/httpClient.py index 5f755b6..16e2809 100644 --- a/seatsio/httpClient.py +++ b/seatsio/httpClient.py @@ -12,25 +12,27 @@ def handle_error(request, response): class HttpClient: - def __init__(self, base_url, secret_key, workspace_key, max_retries): + def __init__(self, base_url, secret_key, workspace_key, max_retries, timeout=10): self.base_url = base_url self.secret_key = secret_key self.workspace_key = workspace_key self.max_retries = max_retries + self.timeout = timeout def url(self, relative_url, query_params=None, **path_params): if query_params is None: query_params = {} return ApiResource(self.max_retries, self.secret_key, self.workspace_key, self.base_url, relative_url, - query_params, **path_params) + query_params, self.timeout, **path_params) class ApiResource: - def __init__(self, max_retries, secret_key, workspace_key, base_url, relative_url, query_params, **path_params): + def __init__(self, max_retries, secret_key, workspace_key, base_url, relative_url, query_params, timeout, **path_params): self.max_retries = max_retries self.url = self.__create_full_url(base_url, relative_url, query_params, **path_params) self.secret_key = secret_key self.workspace_key = workspace_key + self.timeout = timeout def __create_full_url(self, base_url, relative_url, query_params, **path_params): for key in path_params: @@ -41,38 +43,39 @@ def __create_full_url(self, base_url, relative_url, query_params, **path_params) return full_url def get(self): - return GET(self.max_retries, self.url, self.secret_key, self.workspace_key).execute() + return GET(self.max_retries, self.url, self.secret_key, self.workspace_key, self.timeout).execute() def get_raw(self): - return GET(self.max_retries, self.url, self.secret_key, self.workspace_key).execute_raw() + return GET(self.max_retries, self.url, self.secret_key, self.workspace_key, self.timeout).execute_raw() def get_as(self, cls): return cls(self.get()) def post(self, body=None): if body is None: - return POST(self.max_retries, self.url, self.secret_key, self.workspace_key).execute() + return POST(self.max_retries, self.url, self.secret_key, self.workspace_key, self.timeout).execute() else: - return POST(self.max_retries, self.url, self.secret_key, self.workspace_key).body(body).execute() + return POST(self.max_retries, self.url, self.secret_key, self.workspace_key, self.timeout).body(body).execute() def post_empty_and_return(self, cls): return cls(self.post().json()) def delete(self, body=None): if body is None: - return DELETE(self.max_retries, self.url, self.secret_key, self.workspace_key).execute() + return DELETE(self.max_retries, self.url, self.secret_key, self.workspace_key, self.timeout).execute() else: - return DELETE(self.max_retries, self.url, self.secret_key, self.workspace_key).body(body).execute() + return DELETE(self.max_retries, self.url, self.secret_key, self.workspace_key, self.timeout).body(body).execute() class GET: - def __init__(self, max_retries, url, secret_key, workspace_key): + def __init__(self, max_retries, url, secret_key, workspace_key, timeout): self.http_method = "GET" self.max_retries = max_retries self.url = url self.secret_key = secret_key self.workspace_key = workspace_key + self.timeout = timeout def execute(self): response = retry(self.try_execute, self.max_retries) @@ -90,19 +93,20 @@ def execute_raw(self): def try_execute(self): try: - return requests.get(self.url, auth=(self.secret_key, ''), headers=(common_headers(self.workspace_key))) + return requests.get(self.url, auth=(self.secret_key, ''), headers=(common_headers(self.workspace_key)), timeout=self.timeout) except Exception as cause: raise SeatsioException(self, cause=cause) class POST: - def __init__(self, max_retries, url, secret_key, workspace_key): + def __init__(self, max_retries, url, secret_key, workspace_key, timeout): self.http_method = "POST" self.max_retries = max_retries self.url = url self.secret_key = secret_key self.workspace_key = workspace_key + self.timeout = timeout self.body_object = None def body(self, body): @@ -123,7 +127,8 @@ def try_execute(self): url=self.url, auth=(self.secret_key, ''), headers=(common_headers(self.workspace_key)), - data=json + data=json, + timeout=self.timeout ) except Exception as cause: raise SeatsioException(self, cause=cause) @@ -131,12 +136,13 @@ def try_execute(self): class DELETE: - def __init__(self, max_retries, url, secret_key, workspace_key): + def __init__(self, max_retries, url, secret_key, workspace_key, timeout): self.http_method = "DELETE" self.max_retries = max_retries self.url = url self.secret_key = secret_key self.workspace_key = workspace_key + self.timeout = timeout self.body_object = None def body(self, body): @@ -157,7 +163,8 @@ def try_execute(self): self.url, auth=(self.secret_key, ''), headers=(common_headers(self.workspace_key)), - data=json + data=json, + timeout=self.timeout ) except Exception as cause: raise SeatsioException(self, cause=cause) From df6524cc4e697f3fb28bd22f19951599187e7f91 Mon Sep 17 00:00:00 2001 From: Scott Divelbiss Date: Tue, 20 Jan 2026 16:11:04 +0100 Subject: [PATCH 2/2] test --- tests/testErrorHandling.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/testErrorHandling.py b/tests/testErrorHandling.py index ebaaa9a..d347822 100644 --- a/tests/testErrorHandling.py +++ b/tests/testErrorHandling.py @@ -27,3 +27,13 @@ def test_weird_error(self): assert_that(e.errors).is_none() assert_that(e.requestId).is_none() assert_that(e.cause).is_not_none() + + def test_timeout_raises_seatsio_exception(self): + from seatsio.httpClient import HttpClient + try: + client = HttpClient("https://httpbin.seatsio.net", "aSecretKey", None, 0, timeout=0.1) + client.url("/delay/1").get() + self.fail("expected exception") + except SeatsioException as e: + assert_that(e.message).is_equal_to("Error while executing GET https://httpbin.seatsio.net/delay/1") + assert_that(e.cause).is_not_none()