unique_sdk 0.9.11__py3-none-any.whl → 0.9.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unique_sdk/_api_requestor.py +40 -15
- unique_sdk/_api_resource.py +2 -0
- unique_sdk/_error.py +13 -2
- unique_sdk/_http_client.py +8 -4
- unique_sdk/_util.py +17 -6
- unique_sdk/_version.py +1 -1
- {unique_sdk-0.9.11.dist-info → unique_sdk-0.9.13.dist-info}/METADATA +7 -1
- {unique_sdk-0.9.11.dist-info → unique_sdk-0.9.13.dist-info}/RECORD +10 -10
- {unique_sdk-0.9.11.dist-info → unique_sdk-0.9.13.dist-info}/LICENSE +0 -0
- {unique_sdk-0.9.11.dist-info → unique_sdk-0.9.13.dist-info}/WHEEL +0 -0
unique_sdk/_api_requestor.py
CHANGED
|
@@ -339,13 +339,14 @@ class APIRequestor(object):
|
|
|
339
339
|
rcode,
|
|
340
340
|
rheaders,
|
|
341
341
|
)
|
|
342
|
-
except Exception:
|
|
342
|
+
except Exception as e:
|
|
343
343
|
raise _error.APIError(
|
|
344
344
|
"Invalid response body from API: %s "
|
|
345
345
|
"(HTTP response code was %d)" % (rbody, rcode),
|
|
346
346
|
cast(bytes, rbody),
|
|
347
347
|
rcode,
|
|
348
348
|
rheaders,
|
|
349
|
+
original_error=e,
|
|
349
350
|
)
|
|
350
351
|
if self._should_handle_code_as_error(rcode):
|
|
351
352
|
self.handle_error_response(rbody, rcode, resp.data, rheaders)
|
|
@@ -374,33 +375,57 @@ class APIRequestor(object):
|
|
|
374
375
|
raise err
|
|
375
376
|
|
|
376
377
|
def specific_api_error(self, rbody, rcode, resp, rheaders, error_data):
|
|
378
|
+
cause = error_data.get("cause", {})
|
|
379
|
+
status = cause.get("status", rcode)
|
|
380
|
+
|
|
377
381
|
_util.log_info(
|
|
378
382
|
"Unique error received",
|
|
379
|
-
error_code=
|
|
383
|
+
error_code=status,
|
|
380
384
|
error_type=error_data.get("type"),
|
|
381
385
|
error_message=error_data.get("message"),
|
|
382
386
|
error_params=error_data.get("params"),
|
|
383
387
|
)
|
|
384
388
|
|
|
385
|
-
if
|
|
389
|
+
error = cause.get("error", {}) if cause else {}
|
|
390
|
+
error_code = error.get("code", "<Unknown code>")
|
|
391
|
+
error_message = error.get("message", "<No message>")
|
|
392
|
+
original_error = f"{error_code}: {error_message}"
|
|
393
|
+
|
|
394
|
+
if status in [400, 404]:
|
|
386
395
|
return _error.InvalidRequestError(
|
|
387
|
-
error_data.get("message"),
|
|
388
|
-
error_data.get("params"),
|
|
389
|
-
error_data.get("code"),
|
|
390
|
-
rbody,
|
|
391
|
-
rcode,
|
|
392
|
-
resp,
|
|
393
|
-
rheaders,
|
|
396
|
+
message=error_data.get("message"),
|
|
397
|
+
params=error_data.get("params"),
|
|
398
|
+
code=error_data.get("code"),
|
|
399
|
+
http_body=rbody,
|
|
400
|
+
http_status=rcode,
|
|
401
|
+
json_body=resp,
|
|
402
|
+
headers=rheaders,
|
|
403
|
+
original_error=original_error,
|
|
394
404
|
)
|
|
395
|
-
elif
|
|
405
|
+
elif status == 401:
|
|
396
406
|
return _error.AuthenticationError(
|
|
397
|
-
error_data.get("message"),
|
|
407
|
+
message=error_data.get("message"),
|
|
408
|
+
http_body=rbody,
|
|
409
|
+
http_status=status,
|
|
410
|
+
json_body=resp,
|
|
411
|
+
headers=rheaders,
|
|
412
|
+
original_error=original_error,
|
|
398
413
|
)
|
|
399
|
-
elif
|
|
414
|
+
elif status == 403:
|
|
400
415
|
return _error.PermissionError(
|
|
401
|
-
error_data.get("message"),
|
|
416
|
+
message=error_data.get("message"),
|
|
417
|
+
http_body=rbody,
|
|
418
|
+
http_status=status,
|
|
419
|
+
json_body=resp,
|
|
420
|
+
headers=rheaders,
|
|
421
|
+
original_error=original_error,
|
|
402
422
|
)
|
|
403
423
|
else:
|
|
404
424
|
return _error.APIError(
|
|
405
|
-
error_data.get("message"),
|
|
425
|
+
message=error_data.get("message"),
|
|
426
|
+
http_body=rbody,
|
|
427
|
+
http_status=status,
|
|
428
|
+
json_body=resp,
|
|
429
|
+
headers=rheaders,
|
|
430
|
+
original_error=original_error,
|
|
406
431
|
)
|
unique_sdk/_api_resource.py
CHANGED
|
@@ -22,10 +22,12 @@ retry_dict = {
|
|
|
22
22
|
"error_messages": [
|
|
23
23
|
"problem proxying the request",
|
|
24
24
|
"Upstream service reached a hard timeout",
|
|
25
|
+
"Invalid response body from API",
|
|
25
26
|
],
|
|
26
27
|
"max_retries": 3,
|
|
27
28
|
"backoff_factor": 2,
|
|
28
29
|
"initial_delay": 1,
|
|
30
|
+
"should_retry_5xx": True,
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
|
unique_sdk/_error.py
CHANGED
|
@@ -9,6 +9,7 @@ class UniqueError(Exception):
|
|
|
9
9
|
headers: Optional[Dict[str, str]]
|
|
10
10
|
code: Optional[str]
|
|
11
11
|
request_id: Optional[str]
|
|
12
|
+
original_error: Optional[Exception | str]
|
|
12
13
|
|
|
13
14
|
def __init__(
|
|
14
15
|
self,
|
|
@@ -18,6 +19,7 @@ class UniqueError(Exception):
|
|
|
18
19
|
json_body: Optional[object] = None,
|
|
19
20
|
headers: Optional[Dict[str, str]] = None,
|
|
20
21
|
code: Optional[str] = None,
|
|
22
|
+
original_error: Optional[Exception | str] = None,
|
|
21
23
|
):
|
|
22
24
|
super(UniqueError, self).__init__(message)
|
|
23
25
|
|
|
@@ -38,6 +40,13 @@ class UniqueError(Exception):
|
|
|
38
40
|
self.headers = headers or {}
|
|
39
41
|
self.code = code
|
|
40
42
|
self.request_id = self.headers.get("request-id", None)
|
|
43
|
+
self.original_error = original_error
|
|
44
|
+
|
|
45
|
+
def __str__(self):
|
|
46
|
+
msg = self._message or "<empty message>"
|
|
47
|
+
if self.original_error:
|
|
48
|
+
msg += f"\n(Original error) {str(self.original_error)}"
|
|
49
|
+
return msg
|
|
41
50
|
|
|
42
51
|
|
|
43
52
|
class UniqueErrorWithParamsCode(UniqueError):
|
|
@@ -72,9 +81,10 @@ class APIConnectionError(UniqueError):
|
|
|
72
81
|
headers=None,
|
|
73
82
|
code=None,
|
|
74
83
|
should_retry=False,
|
|
84
|
+
original_error=None,
|
|
75
85
|
):
|
|
76
86
|
super(APIConnectionError, self).__init__(
|
|
77
|
-
message, http_body, http_status, json_body, headers, code
|
|
87
|
+
message, http_body, http_status, json_body, headers, code, original_error
|
|
78
88
|
)
|
|
79
89
|
self.should_retry = should_retry
|
|
80
90
|
|
|
@@ -97,9 +107,10 @@ class InvalidRequestError(UniqueErrorWithParamsCode):
|
|
|
97
107
|
http_status=None,
|
|
98
108
|
json_body=None,
|
|
99
109
|
headers=None,
|
|
110
|
+
original_error=None,
|
|
100
111
|
):
|
|
101
112
|
super(InvalidRequestError, self).__init__(
|
|
102
|
-
message, http_body, http_status, json_body, headers, code
|
|
113
|
+
message, http_body, http_status, json_body, headers, code, original_error
|
|
103
114
|
)
|
|
104
115
|
self.params = params
|
|
105
116
|
|
unique_sdk/_http_client.py
CHANGED
|
@@ -130,11 +130,12 @@ class RequestsClient(HTTPClient):
|
|
|
130
130
|
content = result.content
|
|
131
131
|
status_code = result.status_code
|
|
132
132
|
|
|
133
|
-
except Exception:
|
|
133
|
+
except Exception as e:
|
|
134
134
|
raise _error.APIConnectionError(
|
|
135
135
|
"Unexpected error communicating with Unique. "
|
|
136
136
|
"If this problem persists, let us know at support@unique.ch",
|
|
137
137
|
http_status=500,
|
|
138
|
+
original_error=e,
|
|
138
139
|
)
|
|
139
140
|
|
|
140
141
|
return content, status_code, result.headers
|
|
@@ -186,11 +187,12 @@ class HTTPXClient(HTTPClient):
|
|
|
186
187
|
args, kwargs = self._get_request_args_kwargs(method, url, headers, post_data)
|
|
187
188
|
try:
|
|
188
189
|
response = self._client.request(*args, **kwargs)
|
|
189
|
-
except Exception:
|
|
190
|
+
except Exception as e:
|
|
190
191
|
raise _error.APIConnectionError(
|
|
191
192
|
"Unexpected error communicating with Unique. "
|
|
192
193
|
"If this problem persists, let us know at support@unique.ch",
|
|
193
194
|
http_status=500,
|
|
195
|
+
original_error=e,
|
|
194
196
|
)
|
|
195
197
|
|
|
196
198
|
content = response.content
|
|
@@ -208,11 +210,12 @@ class HTTPXClient(HTTPClient):
|
|
|
208
210
|
args, kwargs = self._get_request_args_kwargs(method, url, headers, post_data)
|
|
209
211
|
try:
|
|
210
212
|
response = await self._client_async.request(*args, **kwargs)
|
|
211
|
-
except Exception:
|
|
213
|
+
except Exception as e:
|
|
212
214
|
raise _error.APIConnectionError(
|
|
213
215
|
"Unexpected error communicating with Unique. "
|
|
214
216
|
"If this problem persists, let us know at support@unique.ch",
|
|
215
217
|
http_status=500,
|
|
218
|
+
original_error=e,
|
|
216
219
|
)
|
|
217
220
|
|
|
218
221
|
content = response.content
|
|
@@ -297,11 +300,12 @@ class AIOHTTPClient(HTTPClient):
|
|
|
297
300
|
args, kwargs = self._get_request_args_kwargs(method, url, headers, post_data)
|
|
298
301
|
try:
|
|
299
302
|
response = await self._session.request(*args, **kwargs)
|
|
300
|
-
except Exception:
|
|
303
|
+
except Exception as e:
|
|
301
304
|
raise _error.APIConnectionError(
|
|
302
305
|
"Unexpected error communicating with Unique. "
|
|
303
306
|
"If this problem persists, let us know at support@unique.ch",
|
|
304
307
|
http_status=500,
|
|
308
|
+
original_error=e,
|
|
305
309
|
)
|
|
306
310
|
|
|
307
311
|
content = response.content
|
unique_sdk/_util.py
CHANGED
|
@@ -200,6 +200,7 @@ def retry_on_error(
|
|
|
200
200
|
initial_delay: int = 1,
|
|
201
201
|
backoff_factor: int = 2,
|
|
202
202
|
error_class=APIError,
|
|
203
|
+
should_retry_5xx=False,
|
|
203
204
|
):
|
|
204
205
|
def decorator(func: Callable) -> Callable:
|
|
205
206
|
@wraps(func)
|
|
@@ -209,10 +210,15 @@ def retry_on_error(
|
|
|
209
210
|
try:
|
|
210
211
|
return await func(*args, **kwargs)
|
|
211
212
|
except Exception as e:
|
|
212
|
-
|
|
213
|
+
should_retry = any(
|
|
213
214
|
err_msg.lower() in str(e).lower() for err_msg in error_messages
|
|
214
|
-
)
|
|
215
|
-
|
|
215
|
+
)
|
|
216
|
+
# Add 5xx check if `should_retry_5xx` is True
|
|
217
|
+
if should_retry_5xx and hasattr(e, "status_code"):
|
|
218
|
+
should_retry = should_retry or (500 <= e.status_code < 600)
|
|
219
|
+
|
|
220
|
+
if not should_retry:
|
|
221
|
+
raise e # Raise the error if no retry condition is met
|
|
216
222
|
|
|
217
223
|
attempts += 1
|
|
218
224
|
if attempts >= max_retries:
|
|
@@ -229,10 +235,15 @@ def retry_on_error(
|
|
|
229
235
|
try:
|
|
230
236
|
return func(*args, **kwargs)
|
|
231
237
|
except Exception as e:
|
|
232
|
-
|
|
238
|
+
should_retry = any(
|
|
233
239
|
err_msg.lower() in str(e).lower() for err_msg in error_messages
|
|
234
|
-
)
|
|
235
|
-
|
|
240
|
+
)
|
|
241
|
+
# Add 5xx check if `should_retry_5xx` is True
|
|
242
|
+
if should_retry_5xx and hasattr(e, "status_code"):
|
|
243
|
+
should_retry = should_retry or (500 <= e.status_code < 600)
|
|
244
|
+
|
|
245
|
+
if not should_retry:
|
|
246
|
+
raise e # Raise the error if no retry condition is met
|
|
236
247
|
|
|
237
248
|
attempts += 1
|
|
238
249
|
if attempts >= max_retries:
|
unique_sdk/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = "0.9.
|
|
1
|
+
VERSION = "0.9.13"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_sdk
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.13
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Martin Fadler
|
|
@@ -899,6 +899,12 @@ All notable changes to this project will be documented in this file.
|
|
|
899
899
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
900
900
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
901
901
|
|
|
902
|
+
## [0.9.13] - 2024-10-23
|
|
903
|
+
- Add retry for `5xx` errors, add additional error message.
|
|
904
|
+
|
|
905
|
+
## [0.9.12] - 2024-11-21
|
|
906
|
+
- Include original error message in returned exceptions
|
|
907
|
+
|
|
902
908
|
## [0.9.11] - 2024-11-18
|
|
903
909
|
- Add `ingestionConfig` to `UpsertParams.Input` parameters
|
|
904
910
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
unique_sdk/__init__.py,sha256=Cv42hZ3dlsNACMIza7LDARXiY-w7a_ijlSuY_jADJD8,3072
|
|
2
|
-
unique_sdk/_api_requestor.py,sha256
|
|
3
|
-
unique_sdk/_api_resource.py,sha256=
|
|
2
|
+
unique_sdk/_api_requestor.py,sha256=O6iF_d_jc1ceTYVa3kOQHXjYKdmBp0kGW_pfMw1ClwE,14543
|
|
3
|
+
unique_sdk/_api_resource.py,sha256=tE3J9sC5qwOdIMGLYEyvHjdQRYX-1unrLatO7CzgSfk,6185
|
|
4
4
|
unique_sdk/_api_version.py,sha256=Ku4JPdeyJtnX5eJJvRCEc1_u44UObdVrvrL1T-WwWCs,46
|
|
5
|
-
unique_sdk/_error.py,sha256=
|
|
6
|
-
unique_sdk/_http_client.py,sha256=
|
|
5
|
+
unique_sdk/_error.py,sha256=j-deT0PJ-exLCwUkqORRaxaLLrGunDag9bKJSmBBKZI,3343
|
|
6
|
+
unique_sdk/_http_client.py,sha256=CSc2gduhQ42v6G1oh4Jyg8XL7Sa3YQ7WdTpc6kAyTBI,10369
|
|
7
7
|
unique_sdk/_list_object.py,sha256=k3fqWhD-37XHh6gZMHnuqOc1Bomq265Lmy2T7Rapxrk,3949
|
|
8
8
|
unique_sdk/_object_classes.py,sha256=udAQucYaJBpgo7BAvga_JXAK92hu4Ohl2mOq1aN9J_A,270
|
|
9
9
|
unique_sdk/_request_options.py,sha256=oHh2AKka6j9pO53Htur3Wj0VJSusEjq8zkXYY179B_E,255
|
|
10
10
|
unique_sdk/_unique_object.py,sha256=PLaIzb6NPYghfMKHqDx_ZyojcDcuQzTrATXrktLqMa0,11442
|
|
11
11
|
unique_sdk/_unique_ql.py,sha256=aUYXhYPA-_kPfImTapilCyDvB_53YpLd51kxILe7fDA,1707
|
|
12
12
|
unique_sdk/_unique_response.py,sha256=q19hIxlsrkLAQylfHA0webp6bsCCHXkDJDwaC69Iev8,576
|
|
13
|
-
unique_sdk/_util.py,sha256=
|
|
14
|
-
unique_sdk/_version.py,sha256=
|
|
13
|
+
unique_sdk/_util.py,sha256=J8L4ynMM6_zzN5uaIxriShr9lYpYa_5RMQAWKuqIcC0,8806
|
|
14
|
+
unique_sdk/_version.py,sha256=K80rxBhBBS3zPRQP96Dx9umWIad1LHJr2TPbKxFCbgE,19
|
|
15
15
|
unique_sdk/_webhook.py,sha256=GYxbUibQN_W4XlNTHaMIksT9FQJk4LJmlKcxOu3jqiU,2855
|
|
16
16
|
unique_sdk/api_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
unique_sdk/api_resources/_acronyms.py,sha256=GIU1XH1flGWQYcpsFqTYwg4ioIGxVmb15tux84nmhEg,891
|
|
@@ -28,7 +28,7 @@ unique_sdk/utils/chat_history.py,sha256=5UqL9hF1O9pV7skbNOlEibF5rHdYsmG3m5-YEPUo
|
|
|
28
28
|
unique_sdk/utils/file_io.py,sha256=tcS-5NA97AyiJPhKpWs3i0qKNFsZlttToxrvnWRDJrs,3857
|
|
29
29
|
unique_sdk/utils/sources.py,sha256=wfboE-neMKa0Wuq9QzfAEFMkNLrIrmm0v-QF33sLo6k,4952
|
|
30
30
|
unique_sdk/utils/token.py,sha256=AzKuAA1AwBtnvSFxGcsHLpxXr_wWE5Mj4jYBbOz2ljA,1740
|
|
31
|
-
unique_sdk-0.9.
|
|
32
|
-
unique_sdk-0.9.
|
|
33
|
-
unique_sdk-0.9.
|
|
34
|
-
unique_sdk-0.9.
|
|
31
|
+
unique_sdk-0.9.13.dist-info/LICENSE,sha256=EJCWoHgrXVBUb47PnjeV4MFIEOR71MAdCOIgv61J-4k,1065
|
|
32
|
+
unique_sdk-0.9.13.dist-info/METADATA,sha256=FKP4b3n6sn6qVS3DUOoTIueOHBol5SodfydJ6hMcUrc,28143
|
|
33
|
+
unique_sdk-0.9.13.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
34
|
+
unique_sdk-0.9.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|