accli 1.0.3__tar.gz → 1.1.0__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.
- {accli-1.0.3 → accli-1.1.0}/PKG-INFO +18 -1
- {accli-1.0.3 → accli-1.1.0}/README.md +16 -0
- {accli-1.0.3 → accli-1.1.0}/accli/AcceleratorJobProjectService.py +99 -102
- {accli-1.0.3 → accli-1.1.0}/accli/AcceleratorTaskDispatcher.py +79 -94
- {accli-1.0.3 → accli-1.1.0}/accli/AcceleratorTerminalCliProjectService.py +75 -80
- {accli-1.0.3 → accli-1.1.0}/accli/CsvRegionalTimeseriesValidator.py +46 -64
- {accli-1.0.3 → accli-1.1.0}/accli/__init__.py +0 -1
- {accli-1.0.3 → accli-1.1.0}/accli/__main__.py +1 -1
- accli-1.1.0/accli/_version.py +3 -0
- {accli-1.0.3 → accli-1.1.0}/accli/cli.py +71 -64
- {accli-1.0.3 → accli-1.1.0}/accli/common.py +2 -1
- {accli-1.0.3 → accli-1.1.0}/accli/token.py +9 -4
- {accli-1.0.3 → accli-1.1.0}/accli.egg-info/PKG-INFO +18 -1
- {accli-1.0.3 → accli-1.1.0}/accli.egg-info/requires.txt +1 -0
- {accli-1.0.3 → accli-1.1.0}/pyproject.toml +1 -0
- accli-1.0.3/accli/_version.py +0 -3
- {accli-1.0.3 → accli-1.1.0}/LICENSE +0 -0
- {accli-1.0.3 → accli-1.1.0}/accli.egg-info/SOURCES.txt +0 -0
- {accli-1.0.3 → accli-1.1.0}/accli.egg-info/dependency_links.txt +0 -0
- {accli-1.0.3 → accli-1.1.0}/accli.egg-info/entry_points.txt +0 -0
- {accli-1.0.3 → accli-1.1.0}/accli.egg-info/top_level.txt +0 -0
- {accli-1.0.3 → accli-1.1.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: accli
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: IIASA Accelerator Client
|
|
5
5
|
Author-email: Wrufesh S <wrufesh@gmail.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -38,6 +38,7 @@ Requires-Dist: tinydb>=4.5.2
|
|
|
38
38
|
Requires-Dist: requests>=2.25.1
|
|
39
39
|
Requires-Dist: jsonschema>=4.5.1
|
|
40
40
|
Requires-Dist: pydantic>=2.0
|
|
41
|
+
Requires-Dist: GitPython
|
|
41
42
|
Dynamic: license-file
|
|
42
43
|
|
|
43
44
|
|
|
@@ -71,6 +72,22 @@ This client uses **device authentication** via Auth0.
|
|
|
71
72
|
|
|
72
73
|
### 📦 Installation
|
|
73
74
|
|
|
75
|
+
#### Option 1: Standalone Binaries (Recommended)
|
|
76
|
+
|
|
77
|
+
No Python install required. Run the appropriate command for your system:
|
|
78
|
+
|
|
79
|
+
**Linux / macOS:**
|
|
80
|
+
```bash
|
|
81
|
+
curl -fsSL https://raw.githubusercontent.com/iiasa/accli/master/scripts/install.sh | bash
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Windows (PowerShell):**
|
|
85
|
+
```powershell
|
|
86
|
+
irm https://raw.githubusercontent.com/iiasa/accli/master/scripts/install.ps1 | iex
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### Option 2: Via PIP
|
|
90
|
+
|
|
74
91
|
```bash
|
|
75
92
|
pip install accli --user
|
|
76
93
|
```
|
|
@@ -29,6 +29,22 @@ This client uses **device authentication** via Auth0.
|
|
|
29
29
|
|
|
30
30
|
### 📦 Installation
|
|
31
31
|
|
|
32
|
+
#### Option 1: Standalone Binaries (Recommended)
|
|
33
|
+
|
|
34
|
+
No Python install required. Run the appropriate command for your system:
|
|
35
|
+
|
|
36
|
+
**Linux / macOS:**
|
|
37
|
+
```bash
|
|
38
|
+
curl -fsSL https://raw.githubusercontent.com/iiasa/accli/master/scripts/install.sh | bash
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Windows (PowerShell):**
|
|
42
|
+
```powershell
|
|
43
|
+
irm https://raw.githubusercontent.com/iiasa/accli/master/scripts/install.ps1 | iex
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Option 2: Via PIP
|
|
47
|
+
|
|
32
48
|
```bash
|
|
33
49
|
pip install accli --user
|
|
34
50
|
```
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import io
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
from typing import Union, List, Tuple
|
|
4
|
+
|
|
5
5
|
import requests
|
|
6
6
|
import json
|
|
7
7
|
import base64
|
|
8
8
|
import urllib3
|
|
9
9
|
from urllib.parse import quote
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import List, Tuple
|
|
12
11
|
|
|
13
12
|
from accli.common import todict
|
|
14
13
|
|
|
15
14
|
ACCLI_DEBUG = os.environ.get('ACCLI_DEBUG', False)
|
|
16
15
|
|
|
16
|
+
|
|
17
17
|
class AccAPIError(Exception):
|
|
18
18
|
pass
|
|
19
19
|
|
|
@@ -33,14 +33,15 @@ http_client_wo_cert_verification = urllib3.poolmanager.PoolManager(
|
|
|
33
33
|
cert_reqs="CERT_NONE", num_pools=20, retries=retries, maxsize=2000, block=True
|
|
34
34
|
)
|
|
35
35
|
|
|
36
|
+
|
|
36
37
|
class AcceleratorJobProjectService:
|
|
37
38
|
def __init__(
|
|
38
39
|
self,
|
|
39
|
-
user_token,
|
|
40
|
+
user_token,
|
|
40
41
|
server_url='http://accelerator.iiasa.ac.at',
|
|
41
42
|
verify_cert=(not ACCLI_DEBUG)
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
):
|
|
44
|
+
|
|
44
45
|
self.user_token = user_token
|
|
45
46
|
|
|
46
47
|
if verify_cert:
|
|
@@ -48,13 +49,13 @@ class AcceleratorJobProjectService:
|
|
|
48
49
|
else:
|
|
49
50
|
self.http_client = http_client_wo_cert_verification
|
|
50
51
|
|
|
51
|
-
self.cli_base_url = f"{server_url}/v1/ajob-cli"
|
|
52
|
+
self.cli_base_url = f"{server_url}/api/v1/ajob-cli"
|
|
52
53
|
self.common_request_headers = {
|
|
53
54
|
'x-authorization': user_token
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
def http_client_request(self, *args, **kwargs):
|
|
57
|
-
|
|
58
|
+
|
|
58
59
|
if urllib3.__version__.startswith('1.'):
|
|
59
60
|
if 'json' in kwargs:
|
|
60
61
|
json_dict = kwargs.pop('json')
|
|
@@ -66,106 +67,109 @@ class AcceleratorJobProjectService:
|
|
|
66
67
|
encoded_data = json.dumps(json_dict).encode('utf-8')
|
|
67
68
|
|
|
68
69
|
kwargs['body'] = encoded_data
|
|
69
|
-
|
|
70
|
+
|
|
70
71
|
res = self.http_client.request(*args, **kwargs)
|
|
71
72
|
|
|
72
73
|
if str(res.status)[0] in ['4', '5']:
|
|
73
74
|
raise AccAPIError(
|
|
74
|
-
f"Accelerator api error:: status_code={res.status} :: response_data={res.data}",
|
|
75
|
+
f"Accelerator api error:: status_code={res.status} :: response_data={res.data}",
|
|
75
76
|
)
|
|
76
77
|
return res
|
|
77
78
|
|
|
78
79
|
def get_file_stat(self, bucket_object_id):
|
|
79
80
|
res = self.http_client_request(
|
|
80
|
-
"GET",
|
|
81
|
+
"GET",
|
|
81
82
|
f"{self.cli_base_url}/file-stat/{bucket_object_id}",
|
|
82
83
|
headers=self.common_request_headers
|
|
83
84
|
)
|
|
84
85
|
return todict(res.data)
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
def enumerate_files_by_prefix(self, prefix):
|
|
88
|
-
|
|
88
|
+
raise NotImplementedError("filename parameter is not implemented yet")
|
|
89
89
|
|
|
90
|
+
project_slug = filename.split('/')[0]
|
|
90
91
|
|
|
91
92
|
b64_encoded_prefix = base64.b64encode(prefix.encode()).decode()
|
|
92
93
|
|
|
93
94
|
res = self.http_client_request(
|
|
94
|
-
"GET",
|
|
95
|
+
"GET",
|
|
95
96
|
f"{self.cli_base_url}/{project_slug}/enumerate-all-files/{b64_encoded_prefix}",
|
|
96
97
|
headers=self.common_request_headers
|
|
97
98
|
)
|
|
98
99
|
if res.data:
|
|
99
100
|
return todict(res.data)
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
def get_file_url_from_repo(self, filename):
|
|
103
103
|
project_slug = filename.split('/')[0]
|
|
104
104
|
res = self.http_client_request(
|
|
105
|
-
"GET",
|
|
105
|
+
"GET",
|
|
106
106
|
f"{self.cli_base_url}/{project_slug}/get-file-download-url/?filename={filename}",
|
|
107
107
|
headers=self.common_request_headers
|
|
108
108
|
)
|
|
109
109
|
if res.data:
|
|
110
110
|
return todict(res.data)
|
|
111
|
-
|
|
111
|
+
return None
|
|
112
|
+
|
|
112
113
|
def get_dataset_type(self, *args, **kwargs):
|
|
113
114
|
return self.get_bucket_object_validation_type(*args, **kwargs)
|
|
114
115
|
|
|
115
116
|
def get_bucket_object_validation_type(self, bucket_object_id):
|
|
116
117
|
res = self.http_client_request(
|
|
117
|
-
"GET",
|
|
118
|
+
"GET",
|
|
118
119
|
f"{self.cli_base_url}/dataset-type/{bucket_object_id}",
|
|
119
120
|
headers=self.common_request_headers
|
|
120
121
|
)
|
|
121
122
|
if res.data:
|
|
122
123
|
return todict(res.data)
|
|
123
|
-
|
|
124
|
+
return None
|
|
124
125
|
|
|
125
126
|
def get_filename_dataset_type(self, filename):
|
|
126
127
|
res = self.http_client_request(
|
|
127
|
-
"GET",
|
|
128
|
+
"GET",
|
|
128
129
|
f"{self.cli_base_url}/filename-dataset-type/?filename={filename}",
|
|
129
130
|
headers=self.common_request_headers
|
|
130
131
|
)
|
|
131
132
|
if res.data:
|
|
132
133
|
return todict(res.data)
|
|
134
|
+
return None
|
|
133
135
|
|
|
134
136
|
def get_filename_validation_details(self, filename):
|
|
135
137
|
res = self.http_client_request(
|
|
136
|
-
"GET",
|
|
138
|
+
"GET",
|
|
137
139
|
f"{self.cli_base_url}/filename-validation-detail/?filename={filename}",
|
|
138
140
|
headers=self.common_request_headers
|
|
139
141
|
)
|
|
140
142
|
if res.data:
|
|
141
143
|
return todict(res.data)
|
|
144
|
+
return None
|
|
142
145
|
|
|
143
146
|
def get_bucket_object_validation_details(self, bucket_object_id):
|
|
144
147
|
res = self.http_client_request(
|
|
145
|
-
"GET",
|
|
148
|
+
"GET",
|
|
146
149
|
f"{self.cli_base_url}/validation-detail/{bucket_object_id}",
|
|
147
150
|
headers=self.common_request_headers
|
|
148
151
|
)
|
|
149
152
|
if res.data:
|
|
150
153
|
return todict(res.data)
|
|
154
|
+
return None
|
|
151
155
|
|
|
152
|
-
|
|
153
156
|
def get_file_url(self, bucket_object_id):
|
|
154
157
|
res = self.http_client_request(
|
|
155
|
-
"GET",
|
|
158
|
+
"GET",
|
|
156
159
|
f"{self.cli_base_url}/file-url/{bucket_object_id}",
|
|
157
160
|
headers=self.common_request_headers
|
|
158
161
|
)
|
|
159
162
|
|
|
160
163
|
if res.data:
|
|
161
164
|
return todict(res.data)
|
|
162
|
-
|
|
165
|
+
return None
|
|
163
166
|
|
|
164
167
|
def get_file_stream(self, bucket_object_id):
|
|
165
168
|
url = self.get_file_url(bucket_object_id)
|
|
166
169
|
if url:
|
|
167
170
|
resp = self.http_client_request("GET", url, preload_content=False)
|
|
168
171
|
return resp
|
|
172
|
+
return None
|
|
169
173
|
|
|
170
174
|
def check_job_health(self):
|
|
171
175
|
|
|
@@ -174,15 +178,15 @@ class AcceleratorJobProjectService:
|
|
|
174
178
|
f"{self.cli_base_url}/is-healthy/",
|
|
175
179
|
headers=self.common_request_headers
|
|
176
180
|
)
|
|
177
|
-
|
|
181
|
+
|
|
178
182
|
if res.data:
|
|
179
183
|
res = todict(res.data)
|
|
180
|
-
|
|
184
|
+
|
|
181
185
|
is_healthy = res['is_healthy']
|
|
182
186
|
return is_healthy
|
|
183
|
-
|
|
187
|
+
|
|
184
188
|
def add_log_file(self, data: bytes, filename):
|
|
185
|
-
|
|
189
|
+
|
|
186
190
|
res = self.http_client_request(
|
|
187
191
|
"GET",
|
|
188
192
|
f"{self.cli_base_url}/presigned-log-upload-url/?filename={filename}",
|
|
@@ -193,7 +197,7 @@ class AcceleratorJobProjectService:
|
|
|
193
197
|
res = todict(res.data)
|
|
194
198
|
else:
|
|
195
199
|
raise ValueError(f"Unable to get presign url in response: {res.data}")
|
|
196
|
-
|
|
200
|
+
|
|
197
201
|
upload_url = res['upload_url']
|
|
198
202
|
app_bucket_id = res['app_bucket_id']
|
|
199
203
|
res_filename = res['filename']
|
|
@@ -206,7 +210,6 @@ class AcceleratorJobProjectService:
|
|
|
206
210
|
verify=False,
|
|
207
211
|
)
|
|
208
212
|
|
|
209
|
-
|
|
210
213
|
self.http_client_request(
|
|
211
214
|
"POST",
|
|
212
215
|
f"{self.cli_base_url}/register-log-file/",
|
|
@@ -216,19 +219,18 @@ class AcceleratorJobProjectService:
|
|
|
216
219
|
),
|
|
217
220
|
headers=self.common_request_headers
|
|
218
221
|
)
|
|
219
|
-
|
|
220
|
-
return is_healthy
|
|
221
222
|
|
|
223
|
+
return is_healthy
|
|
222
224
|
|
|
223
225
|
def get_multipart_put_create_signed_url(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
226
|
+
self,
|
|
227
|
+
app_bucket_id,
|
|
228
|
+
object_name,
|
|
229
|
+
upload_id,
|
|
230
|
+
part_number
|
|
229
231
|
):
|
|
230
232
|
res = self.http_client_request(
|
|
231
|
-
"GET",
|
|
233
|
+
"GET",
|
|
232
234
|
f"{self.cli_base_url}/put-create-signed-url",
|
|
233
235
|
fields=dict(
|
|
234
236
|
app_bucket_id=app_bucket_id,
|
|
@@ -242,13 +244,13 @@ class AcceleratorJobProjectService:
|
|
|
242
244
|
return todict(res.data)
|
|
243
245
|
|
|
244
246
|
def get_multipart_put_update_signed_url(
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
self,
|
|
248
|
+
filename,
|
|
249
|
+
upload_id,
|
|
250
|
+
part_number,
|
|
249
251
|
):
|
|
250
252
|
res = self.http_client_request(
|
|
251
|
-
"GET",
|
|
253
|
+
"GET",
|
|
252
254
|
f"{self.cli_base_url}/put-update-signed-url",
|
|
253
255
|
fields=dict(
|
|
254
256
|
filename=filename,
|
|
@@ -263,7 +265,7 @@ class AcceleratorJobProjectService:
|
|
|
263
265
|
def get_put_create_multipart_upload_id(self, filename):
|
|
264
266
|
encoded_filename = quote(filename)
|
|
265
267
|
res = self.http_client_request(
|
|
266
|
-
"GET",
|
|
268
|
+
"GET",
|
|
267
269
|
f"{self.cli_base_url}/multipart-upload-id/?filename={encoded_filename}",
|
|
268
270
|
headers=self.common_request_headers
|
|
269
271
|
)
|
|
@@ -272,11 +274,10 @@ class AcceleratorJobProjectService:
|
|
|
272
274
|
|
|
273
275
|
return data['upload_id'], data['app_bucket_id'], data['uniqified_filename']
|
|
274
276
|
|
|
275
|
-
|
|
276
277
|
def get_validator_create_multipart_upload_id(self, filename):
|
|
277
278
|
encoded_filename = quote(filename)
|
|
278
279
|
res = self.http_client_request(
|
|
279
|
-
"GET",
|
|
280
|
+
"GET",
|
|
280
281
|
f"{self.cli_base_url}/validator-multipart-upload-id/?filename={encoded_filename}",
|
|
281
282
|
headers=self.common_request_headers
|
|
282
283
|
)
|
|
@@ -288,7 +289,7 @@ class AcceleratorJobProjectService:
|
|
|
288
289
|
def get_put_update_multipart_upload_id(self, filename):
|
|
289
290
|
encoded_filename = quote(filename)
|
|
290
291
|
res = self.http_client_request(
|
|
291
|
-
"GET",
|
|
292
|
+
"GET",
|
|
292
293
|
f"{self.cli_base_url}/update-multipart-upload-id/?filename={encoded_filename}",
|
|
293
294
|
headers=self.common_request_headers
|
|
294
295
|
)
|
|
@@ -296,19 +297,19 @@ class AcceleratorJobProjectService:
|
|
|
296
297
|
return todict(res.data)
|
|
297
298
|
|
|
298
299
|
def complete_job_multipart_upload(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
300
|
+
self,
|
|
301
|
+
app_bucket_id,
|
|
302
|
+
filename,
|
|
303
|
+
upload_id,
|
|
304
|
+
parts: List[Tuple[str, str]],
|
|
305
|
+
is_log_file=False
|
|
305
306
|
):
|
|
306
307
|
headers = {"Content-Type": "application/json"}
|
|
307
308
|
|
|
308
309
|
headers.update(self.common_request_headers)
|
|
309
310
|
|
|
310
311
|
res = self.http_client_request(
|
|
311
|
-
"PUT",
|
|
312
|
+
"PUT",
|
|
312
313
|
f"{self.cli_base_url}/complete-create-multipart-upload",
|
|
313
314
|
json=dict(
|
|
314
315
|
app_bucket_id=app_bucket_id,
|
|
@@ -322,20 +323,19 @@ class AcceleratorJobProjectService:
|
|
|
322
323
|
|
|
323
324
|
return todict(res.data)
|
|
324
325
|
|
|
325
|
-
|
|
326
326
|
def complete_validator_multipart_upload(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
327
|
+
self,
|
|
328
|
+
app_bucket_id,
|
|
329
|
+
filename,
|
|
330
|
+
upload_id,
|
|
331
|
+
parts: List[Tuple[str, str]]
|
|
332
332
|
):
|
|
333
333
|
headers = {"Content-Type": "application/json"}
|
|
334
334
|
|
|
335
335
|
headers.update(self.common_request_headers)
|
|
336
336
|
|
|
337
337
|
res = self.http_client_request(
|
|
338
|
-
"PUT",
|
|
338
|
+
"PUT",
|
|
339
339
|
f"{self.cli_base_url}/complete-validator-multipart-upload",
|
|
340
340
|
json=dict(
|
|
341
341
|
app_bucket_id=app_bucket_id,
|
|
@@ -349,7 +349,7 @@ class AcceleratorJobProjectService:
|
|
|
349
349
|
return todict(res.data)
|
|
350
350
|
|
|
351
351
|
def complete_update_multipart_upload(
|
|
352
|
-
|
|
352
|
+
self, filename, upload_id, parts: List[Tuple[str, str]]
|
|
353
353
|
):
|
|
354
354
|
|
|
355
355
|
headers = {"Content-Type": "application/json"}
|
|
@@ -357,7 +357,7 @@ class AcceleratorJobProjectService:
|
|
|
357
357
|
headers.update(self.common_request_headers)
|
|
358
358
|
|
|
359
359
|
res = self.http_client_request(
|
|
360
|
-
"PUT",
|
|
360
|
+
"PUT",
|
|
361
361
|
f"{self.cli_base_url}/complete-update-multipart-upload",
|
|
362
362
|
json=dict(
|
|
363
363
|
filename=filename,
|
|
@@ -370,13 +370,13 @@ class AcceleratorJobProjectService:
|
|
|
370
370
|
return todict(res.data)
|
|
371
371
|
|
|
372
372
|
def abort_create_multipart_upload(self, app_bucket_id, filename, upload_id):
|
|
373
|
-
|
|
373
|
+
|
|
374
374
|
headers = {"Content-Type": "application/json"}
|
|
375
375
|
|
|
376
376
|
headers.update(self.common_request_headers)
|
|
377
377
|
|
|
378
378
|
res = self.http_client_request(
|
|
379
|
-
"PUT",
|
|
379
|
+
"PUT",
|
|
380
380
|
f"{self.cli_base_url}/abort-create-multipart-upload",
|
|
381
381
|
json=dict(
|
|
382
382
|
app_bucket_id=app_bucket_id,
|
|
@@ -387,7 +387,7 @@ class AcceleratorJobProjectService:
|
|
|
387
387
|
)
|
|
388
388
|
|
|
389
389
|
def abort_update_multipart_upload(self, filename, upload_id):
|
|
390
|
-
|
|
390
|
+
|
|
391
391
|
headers = {
|
|
392
392
|
# "Content-Type": "application/json"
|
|
393
393
|
}
|
|
@@ -395,7 +395,7 @@ class AcceleratorJobProjectService:
|
|
|
395
395
|
headers.update(self.common_request_headers)
|
|
396
396
|
|
|
397
397
|
res = self.http_client_request(
|
|
398
|
-
"PUT",
|
|
398
|
+
"PUT",
|
|
399
399
|
f"{self.cli_base_url}/abort-update-multipart-upload",
|
|
400
400
|
json=dict(
|
|
401
401
|
filename=filename,
|
|
@@ -403,7 +403,7 @@ class AcceleratorJobProjectService:
|
|
|
403
403
|
),
|
|
404
404
|
headers=headers
|
|
405
405
|
)
|
|
406
|
-
|
|
406
|
+
|
|
407
407
|
# # TODO @wrufesh ensure it requires special token
|
|
408
408
|
# def register_iamc_validation(
|
|
409
409
|
# self, validated_bucket_object_id, indexdb_bucket_object_id
|
|
@@ -424,18 +424,18 @@ class AcceleratorJobProjectService:
|
|
|
424
424
|
# )
|
|
425
425
|
|
|
426
426
|
def register_validation(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
427
|
+
self,
|
|
428
|
+
validated_bucket_object_id: int,
|
|
429
|
+
dataset_template_id: int,
|
|
430
|
+
validated_metadata: dict,
|
|
431
|
+
validation_supporting_bucket_object_ids: List[int]
|
|
432
432
|
):
|
|
433
433
|
headers = {"Content-Type": "application/json"}
|
|
434
434
|
|
|
435
435
|
headers.update(self.common_request_headers)
|
|
436
436
|
|
|
437
437
|
res = self.http_client_request(
|
|
438
|
-
"PUT",
|
|
438
|
+
"PUT",
|
|
439
439
|
f"{self.cli_base_url}/register-validation",
|
|
440
440
|
json=dict(
|
|
441
441
|
validated_bucket_object_id=validated_bucket_object_id,
|
|
@@ -447,25 +447,23 @@ class AcceleratorJobProjectService:
|
|
|
447
447
|
)
|
|
448
448
|
|
|
449
449
|
def get_dataset_template_details(
|
|
450
|
-
|
|
451
|
-
|
|
450
|
+
self,
|
|
451
|
+
dataset_template_id
|
|
452
452
|
):
|
|
453
453
|
headers = {"Content-Type": "application/json"}
|
|
454
454
|
|
|
455
455
|
headers.update(self.common_request_headers)
|
|
456
456
|
|
|
457
457
|
res = self.http_client_request(
|
|
458
|
-
"GET",
|
|
458
|
+
"GET",
|
|
459
459
|
f"{self.cli_base_url}/dataset-template-detail/{dataset_template_id}",
|
|
460
460
|
headers=headers
|
|
461
461
|
)
|
|
462
462
|
|
|
463
463
|
return todict(res.data)
|
|
464
464
|
|
|
465
|
-
|
|
466
|
-
|
|
467
465
|
def read_part_data(self, stream, size, part_data=b"", progress=None):
|
|
468
|
-
"""Read part data of given size from stream."""
|
|
466
|
+
"""Read part data of the given size from the stream."""
|
|
469
467
|
size -= len(part_data)
|
|
470
468
|
while size:
|
|
471
469
|
data = stream.read(size)
|
|
@@ -483,7 +481,7 @@ class AcceleratorJobProjectService:
|
|
|
483
481
|
headers = dict()
|
|
484
482
|
headers["Content-Type"] = "application/octet-stream"
|
|
485
483
|
|
|
486
|
-
part_size, part_count = 50 * 1024**2, -1
|
|
484
|
+
part_size, part_count = 50 * 1024 ** 2, -1
|
|
487
485
|
|
|
488
486
|
upload_id = None
|
|
489
487
|
app_bucket_id = None
|
|
@@ -507,7 +505,7 @@ class AcceleratorJobProjectService:
|
|
|
507
505
|
)
|
|
508
506
|
|
|
509
507
|
# If part_data_size is less or equal to part_size,
|
|
510
|
-
# then we have reached last part.
|
|
508
|
+
# then we have reached the last part.
|
|
511
509
|
if len(part_data) <= part_size:
|
|
512
510
|
part_count = part_number
|
|
513
511
|
stop = True
|
|
@@ -523,7 +521,7 @@ class AcceleratorJobProjectService:
|
|
|
523
521
|
app_bucket_id,
|
|
524
522
|
uniqified_filename,
|
|
525
523
|
) = self.get_put_create_multipart_upload_id(
|
|
526
|
-
filename,
|
|
524
|
+
filename,
|
|
527
525
|
# headers=headers
|
|
528
526
|
)
|
|
529
527
|
|
|
@@ -560,7 +558,7 @@ class AcceleratorJobProjectService:
|
|
|
560
558
|
headers = dict()
|
|
561
559
|
headers["Content-Type"] = "application/octet-stream"
|
|
562
560
|
|
|
563
|
-
part_size, part_count = 50 * 1024**2, -1
|
|
561
|
+
part_size, part_count = 50 * 1024 ** 2, -1
|
|
564
562
|
|
|
565
563
|
upload_id = None
|
|
566
564
|
app_bucket_id = None
|
|
@@ -584,7 +582,7 @@ class AcceleratorJobProjectService:
|
|
|
584
582
|
)
|
|
585
583
|
|
|
586
584
|
# If part_data_size is less or equal to part_size,
|
|
587
|
-
# then we have reached last part.
|
|
585
|
+
# then we have reached the last part.
|
|
588
586
|
if len(part_data) <= part_size:
|
|
589
587
|
part_count = part_number
|
|
590
588
|
stop = True
|
|
@@ -630,12 +628,11 @@ class AcceleratorJobProjectService:
|
|
|
630
628
|
|
|
631
629
|
raise err
|
|
632
630
|
|
|
633
|
-
|
|
634
631
|
def add_filestream_as_validation_supporter(self, filename, file_stream, is_log_file=False):
|
|
635
632
|
headers = dict()
|
|
636
633
|
headers["Content-Type"] = "application/octet-stream"
|
|
637
634
|
|
|
638
|
-
part_size, part_count = 50 * 1024**2, -1
|
|
635
|
+
part_size, part_count = 50 * 1024 ** 2, -1
|
|
639
636
|
|
|
640
637
|
upload_id = None
|
|
641
638
|
app_bucket_id = None
|
|
@@ -659,7 +656,7 @@ class AcceleratorJobProjectService:
|
|
|
659
656
|
)
|
|
660
657
|
|
|
661
658
|
# If part_data_size is less or equal to part_size,
|
|
662
|
-
# then we have reached last part.
|
|
659
|
+
# then we have reached the last part.
|
|
663
660
|
if len(part_data) <= part_size:
|
|
664
661
|
part_count = part_number
|
|
665
662
|
stop = True
|
|
@@ -675,7 +672,7 @@ class AcceleratorJobProjectService:
|
|
|
675
672
|
app_bucket_id,
|
|
676
673
|
uniqified_filename,
|
|
677
674
|
) = self.get_validator_create_multipart_upload_id(
|
|
678
|
-
filename,
|
|
675
|
+
filename,
|
|
679
676
|
# headers=headers
|
|
680
677
|
)
|
|
681
678
|
|
|
@@ -717,7 +714,7 @@ class AcceleratorJobProjectService:
|
|
|
717
714
|
headers.update(self.common_request_headers)
|
|
718
715
|
|
|
719
716
|
res = self.http_client_request(
|
|
720
|
-
"POST",
|
|
717
|
+
"POST",
|
|
721
718
|
f"{self.cli_base_url}/webhook-event",
|
|
722
719
|
json=dict(
|
|
723
720
|
type='STATUS_UPDATE',
|
|
@@ -728,12 +725,13 @@ class AcceleratorJobProjectService:
|
|
|
728
725
|
headers=headers
|
|
729
726
|
)
|
|
730
727
|
|
|
728
|
+
|
|
731
729
|
class Fs:
|
|
732
730
|
@staticmethod
|
|
733
731
|
def write_stream_remote(filestream, dest_filepath, user_token, server_url):
|
|
734
732
|
|
|
735
733
|
accelerator_job_service = AcceleratorJobProjectService(
|
|
736
|
-
user_token,
|
|
734
|
+
user_token,
|
|
737
735
|
server_url=server_url,
|
|
738
736
|
verify_cert=(not ACCLI_DEBUG)
|
|
739
737
|
)
|
|
@@ -755,9 +753,9 @@ class Fs:
|
|
|
755
753
|
|
|
756
754
|
if not (user_token and server_url):
|
|
757
755
|
raise ValueError("Remote data repository credentials not found.")
|
|
758
|
-
|
|
756
|
+
|
|
759
757
|
accelerator_job_service = AcceleratorJobProjectService(
|
|
760
|
-
user_token,
|
|
758
|
+
user_token,
|
|
761
759
|
server_url=server_url,
|
|
762
760
|
verify_cert=(not ACCLI_DEBUG)
|
|
763
761
|
)
|
|
@@ -765,15 +763,14 @@ class Fs:
|
|
|
765
763
|
return accelerator_job_service.get_file_url_from_repo(
|
|
766
764
|
remote_filepath
|
|
767
765
|
)
|
|
768
|
-
|
|
769
766
|
|
|
770
767
|
@staticmethod
|
|
771
|
-
def write_file(source:
|
|
768
|
+
def write_file(source: Union[str, io.BytesIO], dest_filepath):
|
|
772
769
|
user_token = os.environ.get("ACC_JOB_TOKEN", None)
|
|
773
770
|
server_url = os.environ.get("ACC_JOB_GATEWAY_SERVER", None)
|
|
774
771
|
|
|
775
772
|
if isinstance(source, io.BytesIO):
|
|
776
|
-
if
|
|
773
|
+
if user_token and server_url:
|
|
777
774
|
Fs.write_stream_remote(source, dest_filepath, user_token, server_url)
|
|
778
775
|
else:
|
|
779
776
|
Fs.write_stream_local(source, dest_filepath)
|
|
@@ -785,7 +782,7 @@ class Fs:
|
|
|
785
782
|
raise ValueError("Source path does not exist")
|
|
786
783
|
|
|
787
784
|
with open(source, 'rb') as fstream:
|
|
788
|
-
if
|
|
785
|
+
if user_token and server_url:
|
|
789
786
|
Fs.write_stream_remote(fstream, dest_filepath, user_token, server_url)
|
|
790
787
|
else:
|
|
791
788
|
Fs.write_stream_local(fstream, dest_filepath)
|
|
@@ -797,9 +794,9 @@ class Fs:
|
|
|
797
794
|
|
|
798
795
|
if not (user_token and server_url):
|
|
799
796
|
raise ValueError("Remote data repository credentials not found.")
|
|
800
|
-
|
|
797
|
+
|
|
801
798
|
accelerator_job_service = AcceleratorJobProjectService(
|
|
802
|
-
user_token,
|
|
799
|
+
user_token,
|
|
803
800
|
server_url=server_url,
|
|
804
801
|
verify_cert=(not ACCLI_DEBUG)
|
|
805
802
|
)
|