dcipher 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {dcipher-0.3.1 → dcipher-0.3.3}/LICENSE +0 -0
- {dcipher-0.3.1 → dcipher-0.3.3}/PKG-INFO +4 -8
- {dcipher-0.3.1 → dcipher-0.3.3}/README.md +0 -0
- {dcipher-0.3.1 → dcipher-0.3.3}/dcipher/__init__.py +0 -0
- {dcipher-0.3.1 → dcipher-0.3.3}/dcipher/async_client.py +20 -6
- {dcipher-0.3.1 → dcipher-0.3.3}/dcipher/client.py +24 -10
- {dcipher-0.3.1 → dcipher-0.3.3}/dcipher/constants.py +5 -1
- {dcipher-0.3.1 → dcipher-0.3.3}/dcipher/exceptions.py +0 -0
- {dcipher-0.3.1 → dcipher-0.3.3}/pyproject.toml +1 -1
- {dcipher-0.3.1 → dcipher-0.3.3}/dcipher/logger.py +0 -0
|
File without changes
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: dcipher
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: The official Python client library for the Dcipher Workflows API
|
|
5
|
-
Home-page: https://github.com/kairosfuture/dcipher-workflows-api-python
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: Dcipher Analytics AB
|
|
8
7
|
Author-email: dev@dcipheranalytics.com
|
|
@@ -20,17 +19,14 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
25
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
-
Classifier: Programming Language :: Python :: 3.
|
|
27
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
28
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
29
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
25
|
Classifier: Typing :: Typed
|
|
31
26
|
Requires-Dist: httpx (>=0.23.0,<1)
|
|
32
27
|
Requires-Dist: requests (>=2.28.2,<3.0.0)
|
|
33
28
|
Requires-Dist: tenacity (>=8.2.3,<9.0.0)
|
|
29
|
+
Project-URL: Homepage, https://github.com/kairosfuture/dcipher-workflows-api-python
|
|
34
30
|
Project-URL: Repository, https://github.com/kairosfuture/dcipher-workflows-api-python
|
|
35
31
|
Description-Content-Type: text/markdown
|
|
36
32
|
|
|
File without changes
|
|
File without changes
|
|
@@ -19,10 +19,13 @@ logger = setup_logger()
|
|
|
19
19
|
|
|
20
20
|
class AsyncDcipher(Dcipher):
|
|
21
21
|
|
|
22
|
-
async def run_flow(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
async def run_flow(
|
|
23
|
+
self,
|
|
24
|
+
flow_id: str,
|
|
25
|
+
params: Dict[str, Any],
|
|
26
|
+
save_path: Optional[str] = None,
|
|
27
|
+
wait_until_completion: bool = False,
|
|
28
|
+
) -> Dict[str, str]:
|
|
26
29
|
|
|
27
30
|
request_params = self._prepare_request_params(
|
|
28
31
|
flow_id=flow_id, params=params)
|
|
@@ -47,6 +50,14 @@ class AsyncDcipher(Dcipher):
|
|
|
47
50
|
running_task_id = response["taskId"]
|
|
48
51
|
logger.debug(f"Running taskId: {running_task_id}")
|
|
49
52
|
|
|
53
|
+
result = {
|
|
54
|
+
"task_id": running_task_id,
|
|
55
|
+
"signed_response_url": response_url,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if not wait_until_completion:
|
|
59
|
+
return result
|
|
60
|
+
|
|
50
61
|
await asyncio.sleep(3)
|
|
51
62
|
|
|
52
63
|
@retry(wait=wait_random_exponential(min=1, max=15),
|
|
@@ -72,8 +83,9 @@ class AsyncDcipher(Dcipher):
|
|
|
72
83
|
message = status_response.get("message", "")
|
|
73
84
|
|
|
74
85
|
if status == "SUCCEEDED":
|
|
75
|
-
logger.debug("Workflow has SUCCEEDED.
|
|
76
|
-
|
|
86
|
+
logger.debug("Workflow has SUCCEEDED.")
|
|
87
|
+
if save_path is not None:
|
|
88
|
+
self._save_result(url=response_url, save_path=save_path)
|
|
77
89
|
break
|
|
78
90
|
|
|
79
91
|
if status == "FAILED":
|
|
@@ -82,3 +94,5 @@ class AsyncDcipher(Dcipher):
|
|
|
82
94
|
|
|
83
95
|
logger.debug(f"Status is {status}. Waiting for 3 more seconds")
|
|
84
96
|
await asyncio.sleep(3)
|
|
97
|
+
|
|
98
|
+
return result
|
|
@@ -32,6 +32,8 @@ logger = setup_logger()
|
|
|
32
32
|
|
|
33
33
|
class Dcipher:
|
|
34
34
|
|
|
35
|
+
BASE_URL = "https://api.dcipheranalytics.com"
|
|
36
|
+
|
|
35
37
|
def __init__(self, api_key: Optional[str], max_retries: int = 100):
|
|
36
38
|
self.api_key = api_key or os.environ.get("DCIPHER_API_KEY")
|
|
37
39
|
if not self.api_key:
|
|
@@ -45,9 +47,8 @@ class Dcipher:
|
|
|
45
47
|
"Authorization": f"Api-Key {self.api_key}",
|
|
46
48
|
"Content-Type": "application/json",
|
|
47
49
|
}
|
|
48
|
-
|
|
50
|
+
endpoint_url = f"{self.BASE_URL}/flows/{flow_id}/run"
|
|
49
51
|
|
|
50
|
-
endpoint_url = endpoint_url_template.format(flow_id)
|
|
51
52
|
body = {
|
|
52
53
|
"pipelineParams": params,
|
|
53
54
|
}
|
|
@@ -62,18 +63,20 @@ class Dcipher:
|
|
|
62
63
|
"Authorization": f"Api-Key {self.api_key}",
|
|
63
64
|
"Content-Type": "application/json",
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
status_endpoint_url = status_endpoint_url_template.format(flow_id)
|
|
66
|
+
status_endpoint_url = f"{self.BASE_URL}/flows/{flow_id}/status" # noqa
|
|
67
67
|
url = f"{status_endpoint_url}?taskId={task_id}"
|
|
68
68
|
return {
|
|
69
69
|
"url": url,
|
|
70
70
|
"headers": headers,
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
def run_flow(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
def run_flow(
|
|
74
|
+
self,
|
|
75
|
+
flow_id: str,
|
|
76
|
+
params: Dict[str, Any],
|
|
77
|
+
save_path: Optional[str] = None,
|
|
78
|
+
wait_until_completion: bool = False,
|
|
79
|
+
) -> Dict[str, str]:
|
|
77
80
|
|
|
78
81
|
request_params = self._prepare_request_params(
|
|
79
82
|
flow_id=flow_id, params=params)
|
|
@@ -97,6 +100,14 @@ class Dcipher:
|
|
|
97
100
|
running_task_id = response["taskId"]
|
|
98
101
|
logger.debug(f"Running taskId: {running_task_id}")
|
|
99
102
|
|
|
103
|
+
result = {
|
|
104
|
+
"task_id": running_task_id,
|
|
105
|
+
"signed_response_url": response_url,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if not wait_until_completion:
|
|
109
|
+
return result
|
|
110
|
+
|
|
100
111
|
sleep(5)
|
|
101
112
|
|
|
102
113
|
@retry(wait=wait_random_exponential(min=1, max=15),
|
|
@@ -120,8 +131,9 @@ class Dcipher:
|
|
|
120
131
|
message = status_response.get("message", "")
|
|
121
132
|
|
|
122
133
|
if status == "SUCCEEDED":
|
|
123
|
-
logger.debug("Workflow has SUCCEEDED.
|
|
124
|
-
|
|
134
|
+
logger.debug("Workflow has SUCCEEDED.")
|
|
135
|
+
if save_path is not None:
|
|
136
|
+
self._save_result(url=response_url, save_path=save_path)
|
|
125
137
|
break
|
|
126
138
|
|
|
127
139
|
if status == "FAILED":
|
|
@@ -131,6 +143,8 @@ class Dcipher:
|
|
|
131
143
|
logger.debug(f"Status is {status}. Waiting for 3 more seconds")
|
|
132
144
|
sleep(3)
|
|
133
145
|
|
|
146
|
+
return result
|
|
147
|
+
|
|
134
148
|
def _save_result(self, url: str, save_path: str):
|
|
135
149
|
# Send a GET request to the URL
|
|
136
150
|
response = requests.get(url)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
1
3
|
from httpx import NetworkError, TimeoutException
|
|
2
4
|
from requests.exceptions import ConnectionError, Timeout
|
|
3
5
|
|
|
4
6
|
from .exceptions import ConflictError, InternalServerError, RateLimitError
|
|
5
7
|
|
|
8
|
+
# json.JSONDecodeError covers response.json() failures (requests + httpx).
|
|
6
9
|
RETRIABLE_EXCEPTIONS = (ConnectionError, Timeout,
|
|
7
10
|
ConflictError, RateLimitError,
|
|
8
|
-
InternalServerError, TimeoutException, NetworkError
|
|
11
|
+
InternalServerError, TimeoutException, NetworkError,
|
|
12
|
+
json.JSONDecodeError)
|
|
File without changes
|
|
File without changes
|