accli 0.4.1__tar.gz → 0.5.1__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-0.4.1/accli.egg-info → accli-0.5.1}/PKG-INFO +1 -1
- {accli-0.4.1 → accli-0.5.1}/README.md +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli/AcceleratorJobProjectService.py +84 -22
- {accli-0.4.1 → accli-0.5.1}/accli/AcceleratorTaskDispatcher.py +66 -40
- {accli-0.4.1 → accli-0.5.1}/accli/AcceleratorTerminalCliProjectService.py +35 -4
- {accli-0.4.1 → accli-0.5.1}/accli/_version.py +1 -1
- {accli-0.4.1 → accli-0.5.1}/accli/cli.py +2 -2
- {accli-0.4.1 → accli-0.5.1}/accli/token.py +19 -0
- {accli-0.4.1 → accli-0.5.1/accli.egg-info}/PKG-INFO +1 -1
- {accli-0.4.1 → accli-0.5.1}/accli.egg-info/SOURCES.txt +0 -3
- {accli-0.4.1 → accli-0.5.1}/accli.egg-info/requires.txt +1 -1
- {accli-0.4.1 → accli-0.5.1}/pyproject.toml +1 -1
- accli-0.4.1/.gitignore +0 -6
- accli-0.4.1/Dockerfile.dev +0 -2
- accli-0.4.1/requirements.txt +0 -8
- {accli-0.4.1 → accli-0.5.1}/LICENSE +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli/CsvRegionalTimeseriesValidator.py +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli/__init__.py +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli/__main__.py +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli.egg-info/dependency_links.txt +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli.egg-info/entry_points.txt +0 -0
- {accli-0.4.1 → accli-0.5.1}/accli.egg-info/top_level.txt +0 -0
- {accli-0.4.1 → accli-0.5.1}/setup.cfg +0 -0
|
File without changes
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import io
|
|
3
|
+
import sys
|
|
3
4
|
import typing
|
|
4
5
|
import requests
|
|
5
6
|
import json
|
|
@@ -16,6 +17,19 @@ class AccAPIError(Exception):
|
|
|
16
17
|
# self.response_data = kwargs.pop('response_data')
|
|
17
18
|
# super().__init__(*args, **kwargs)
|
|
18
19
|
|
|
20
|
+
class UnhealthyControlServerError(Exception):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
retries = urllib3.util.Retry(total=10, backoff_factor=1)
|
|
24
|
+
|
|
25
|
+
http_client = urllib3.poolmanager.PoolManager(
|
|
26
|
+
num_pools=20, retries=retries
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
http_client_wo_cert_verification = urllib3.poolmanager.PoolManager(
|
|
30
|
+
cert_reqs="CERT_NONE", num_pools=20, retries=retries
|
|
31
|
+
)
|
|
32
|
+
|
|
19
33
|
class AcceleratorJobProjectService:
|
|
20
34
|
def __init__(
|
|
21
35
|
self,
|
|
@@ -26,12 +40,10 @@ class AcceleratorJobProjectService:
|
|
|
26
40
|
|
|
27
41
|
self.user_token = user_token
|
|
28
42
|
|
|
29
|
-
retries = urllib3.util.Retry(total=10, backoff_factor=1)
|
|
30
|
-
|
|
31
43
|
if verify_cert:
|
|
32
|
-
self.http_client =
|
|
44
|
+
self.http_client = http_client
|
|
33
45
|
else:
|
|
34
|
-
self.http_client =
|
|
46
|
+
self.http_client = http_client_wo_cert_verification
|
|
35
47
|
|
|
36
48
|
self.cli_base_url = f"{server_url}/v1/ajob-cli"
|
|
37
49
|
self.common_request_headers = {
|
|
@@ -39,15 +51,13 @@ class AcceleratorJobProjectService:
|
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
def http_client_request(self, *args, **kwargs):
|
|
54
|
+
|
|
42
55
|
res = self.http_client.request(*args, **kwargs)
|
|
43
56
|
|
|
44
57
|
if str(res.status)[0] in ['4', '5']:
|
|
45
58
|
raise AccAPIError(
|
|
46
59
|
f"Accelerator api error:: status_code={res.status} :: response_data={res.data}",
|
|
47
|
-
# status_code=res.status,
|
|
48
|
-
# response_data=res.data
|
|
49
60
|
)
|
|
50
|
-
|
|
51
61
|
return res
|
|
52
62
|
|
|
53
63
|
def get_file_stat(self, bucket_object_id):
|
|
@@ -58,6 +68,16 @@ class AcceleratorJobProjectService:
|
|
|
58
68
|
)
|
|
59
69
|
return res.json()
|
|
60
70
|
|
|
71
|
+
def get_file_url_from_repo(self, filename):
|
|
72
|
+
project_slug = filename.split('/')[0]
|
|
73
|
+
res = self.http_client_request(
|
|
74
|
+
"GET",
|
|
75
|
+
f"{self.cli_base_url}/{project_slug}/get-file-download-url/?filename={filename}",
|
|
76
|
+
headers=self.common_request_headers
|
|
77
|
+
)
|
|
78
|
+
if res.data:
|
|
79
|
+
return res.json()
|
|
80
|
+
|
|
61
81
|
def get_dataset_type(self, *args, **kwargs):
|
|
62
82
|
return self.get_bucket_object_validation_type(*args, **kwargs)
|
|
63
83
|
|
|
@@ -96,17 +116,34 @@ class AcceleratorJobProjectService:
|
|
|
96
116
|
if url:
|
|
97
117
|
resp = self.http_client_request("GET", url, preload_content=False)
|
|
98
118
|
return resp
|
|
119
|
+
|
|
120
|
+
def check_job_health(self):
|
|
121
|
+
try:
|
|
122
|
+
res = self.http_client_request(
|
|
123
|
+
"GET",
|
|
124
|
+
f"{self.cli_base_url}/is-healthy/",
|
|
125
|
+
headers=self.common_request_headers
|
|
126
|
+
).json()
|
|
127
|
+
except Exception as err:
|
|
128
|
+
raise UnhealthyControlServerError(str(err))
|
|
129
|
+
|
|
130
|
+
is_healthy = res['is_healthy']
|
|
131
|
+
return is_healthy
|
|
99
132
|
|
|
100
133
|
def add_log_file(self, data: bytes, filename):
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
134
|
+
try:
|
|
135
|
+
res = self.http_client_request(
|
|
136
|
+
"GET",
|
|
137
|
+
f"{self.cli_base_url}/presigned-log-upload-url/?filename={filename}",
|
|
138
|
+
headers=self.common_request_headers
|
|
139
|
+
).json()
|
|
140
|
+
except Exception as err:
|
|
141
|
+
raise UnhealthyControlServerError(str(err))
|
|
106
142
|
|
|
107
143
|
upload_url = res['upload_url']
|
|
108
144
|
app_bucket_id = res['app_bucket_id']
|
|
109
145
|
res_filename = res['filename']
|
|
146
|
+
is_healthy = res['is_healthy']
|
|
110
147
|
|
|
111
148
|
requests.put(
|
|
112
149
|
upload_url,
|
|
@@ -115,15 +152,21 @@ class AcceleratorJobProjectService:
|
|
|
115
152
|
verify=False,
|
|
116
153
|
)
|
|
117
154
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
155
|
+
try:
|
|
156
|
+
self.http_client_request(
|
|
157
|
+
"POST",
|
|
158
|
+
f"{self.cli_base_url}/register-log-file/",
|
|
159
|
+
json=dict(
|
|
160
|
+
filename=res_filename,
|
|
161
|
+
app_bucket_id=app_bucket_id
|
|
162
|
+
),
|
|
163
|
+
headers=self.common_request_headers
|
|
164
|
+
)
|
|
165
|
+
except Exception as err:
|
|
166
|
+
raise UnhealthyControlServerError(str(err))
|
|
167
|
+
|
|
168
|
+
if not is_healthy:
|
|
169
|
+
raise UnhealthyControlServerError('Unhealthy control server.')
|
|
127
170
|
|
|
128
171
|
|
|
129
172
|
|
|
@@ -531,9 +574,28 @@ class Fs:
|
|
|
531
574
|
with open(dest_filepath, 'wb') as file:
|
|
532
575
|
file.write(filestream.getvalue())
|
|
533
576
|
|
|
577
|
+
@staticmethod
|
|
578
|
+
def get_file_url(remote_filepath):
|
|
579
|
+
user_token = os.environ.get("ACC_JOB_TOKEN", None)
|
|
580
|
+
server_url = os.environ.get("ACC_JOB_GATEWAY_SERVER", None)
|
|
581
|
+
|
|
582
|
+
if not (user_token and server_url):
|
|
583
|
+
raise ValueError("Remote data repository credentials not found.")
|
|
584
|
+
|
|
585
|
+
accelerator_job_service = AcceleratorJobProjectService(
|
|
586
|
+
user_token,
|
|
587
|
+
server_url=server_url,
|
|
588
|
+
verify_cert=True
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
return accelerator_job_service.get_file_url_from_repo(
|
|
592
|
+
remote_filepath
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
|
|
534
596
|
@staticmethod
|
|
535
597
|
def write_file(source: typing.Union[str, io.BytesIO], dest_filepath):
|
|
536
|
-
user_token = os.environ.get("
|
|
598
|
+
user_token = os.environ.get("ACC_JOB_TOKEN", None)
|
|
537
599
|
server_url = os.environ.get("ACC_JOB_GATEWAY_SERVER", None)
|
|
538
600
|
|
|
539
601
|
if isinstance(source, io.BytesIO):
|
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
import git
|
|
2
2
|
import os
|
|
3
|
+
import zipfile
|
|
3
4
|
import hashlib
|
|
4
5
|
import shutil
|
|
5
6
|
import tempfile
|
|
7
|
+
import requests
|
|
6
8
|
from typing import Optional, List, Dict
|
|
7
|
-
from pydantic import BaseModel, root_validator
|
|
8
|
-
|
|
9
|
-
from accli.token import get_github_app_token
|
|
9
|
+
from pydantic.v1 import BaseModel, root_validator
|
|
10
|
+
from accli.AcceleratorTerminalCliProjectService import AcceleratorTerminalCliProjectService
|
|
11
|
+
from accli.token import get_github_app_token, get_token, get_server_url, get_project_slug
|
|
10
12
|
|
|
11
13
|
FOLDER_JOB_REPO_URL = 'https://github.com/IIASA-Accelerator/wkube-job.git'
|
|
12
14
|
|
|
13
|
-
def hash_folder(folder_path):
|
|
14
|
-
md5_hash = hashlib.md5()
|
|
15
|
-
sha256_hash = hashlib.sha256()
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
def compress_folder(folder_path, output_path):
|
|
17
|
+
# Fixed timestamp for normalization
|
|
18
|
+
fixed_time = (1980, 1, 1, 0, 0, 0)
|
|
19
|
+
|
|
20
|
+
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
|
21
|
+
for root, dirs, files in os.walk(folder_path):
|
|
22
|
+
dirs.sort()
|
|
23
|
+
files.sort()
|
|
24
|
+
for file in files:
|
|
25
|
+
file_path = os.path.join(root, file)
|
|
26
|
+
arcname = os.path.relpath(file_path, start=folder_path)
|
|
27
|
+
# Add file to zip with fixed timestamp
|
|
28
|
+
info = zipfile.ZipInfo(arcname)
|
|
29
|
+
info.date_time = fixed_time
|
|
30
|
+
info.external_attr = 0o600 << 16 # Set file permissions
|
|
21
31
|
with open(file_path, 'rb') as f:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
md5_hash.update(chunk)
|
|
25
|
-
sha256_hash.update(chunk)
|
|
26
|
-
except IOError:
|
|
27
|
-
# Handle read error (if any)
|
|
28
|
-
print(f"Error reading file: {file_path}")
|
|
32
|
+
|
|
33
|
+
zipf.writestr(info, f.read(), zipfile.ZIP_DEFLATED)
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
def get_file_sha1(file_path):
|
|
36
|
+
sha1_hash = hashlib.sha1()
|
|
37
|
+
with open(file_path, "rb") as f:
|
|
38
|
+
chunk = f.read(8192)
|
|
39
|
+
while chunk:
|
|
40
|
+
sha1_hash.update(chunk)
|
|
41
|
+
chunk = f.read(8192)
|
|
42
|
+
return sha1_hash.hexdigest()
|
|
33
43
|
|
|
34
|
-
return md5_digest
|
|
35
44
|
|
|
36
45
|
def copy_tree(src, dst):
|
|
37
46
|
"""Recursively copy from src to dst, excluding .git folders."""
|
|
@@ -49,35 +58,50 @@ def copy_tree(src, dst):
|
|
|
49
58
|
|
|
50
59
|
def push_folder_job(dir):
|
|
51
60
|
|
|
61
|
+
access_token = get_token()
|
|
62
|
+
|
|
63
|
+
server_url = get_server_url()
|
|
64
|
+
|
|
65
|
+
project_slug = get_project_slug()
|
|
66
|
+
|
|
67
|
+
term_cli_project_service = AcceleratorTerminalCliProjectService(
|
|
68
|
+
user_token=access_token,
|
|
69
|
+
server_url=server_url,
|
|
70
|
+
verify_cert=False
|
|
71
|
+
)
|
|
72
|
+
|
|
52
73
|
repo_dir = tempfile.mkdtemp()
|
|
53
74
|
|
|
54
75
|
copy_tree(dir, repo_dir)
|
|
55
|
-
|
|
56
|
-
branch_name = hash_folder(repo_dir)
|
|
57
|
-
|
|
58
|
-
repo = git.Repo.init(repo_dir)
|
|
59
76
|
|
|
60
|
-
|
|
77
|
+
temp_zip_path = f"{repo_dir}/temp.zip"
|
|
61
78
|
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
compress_folder(repo_dir, temp_zip_path)
|
|
80
|
+
|
|
81
|
+
sha256_hash = get_file_sha1(temp_zip_path)
|
|
64
82
|
|
|
65
|
-
|
|
83
|
+
final_zip_path = f"{repo_dir}/{sha256_hash}.zip"
|
|
66
84
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
except git.exc.GitCommandError:
|
|
70
|
-
repo.git.checkout('-b', branch_name)
|
|
85
|
+
|
|
86
|
+
os.rename(temp_zip_path, final_zip_path)
|
|
71
87
|
|
|
72
|
-
|
|
88
|
+
presigned_push_url = term_cli_project_service.get_jobstore_push_url(
|
|
89
|
+
project_slug, f"{sha256_hash}.zip"
|
|
90
|
+
)
|
|
73
91
|
|
|
74
|
-
repo.index.commit(branch_name)
|
|
75
92
|
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
if presigned_push_url:
|
|
94
|
+
with open(final_zip_path, 'rb') as f:
|
|
95
|
+
requests.put(
|
|
96
|
+
presigned_push_url,
|
|
97
|
+
data=f,
|
|
98
|
+
verify=False,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
78
102
|
shutil.rmtree(repo_dir)
|
|
79
103
|
|
|
80
|
-
return
|
|
104
|
+
return f"s3accjobstore://{sha256_hash}.zip", sha256_hash
|
|
81
105
|
|
|
82
106
|
|
|
83
107
|
class JobDispatchModel(BaseModel):
|
|
@@ -139,6 +163,8 @@ class WKubeTaskKwargs(BaseModel):
|
|
|
139
163
|
|
|
140
164
|
conf: Dict[str,str] = {}
|
|
141
165
|
|
|
166
|
+
build_timeout: Optional[int]
|
|
167
|
+
|
|
142
168
|
def dict(self, *args, **kwargs):
|
|
143
169
|
result = super().dict(*args, **kwargs)
|
|
144
170
|
if 'job_folder' in result:
|
|
@@ -202,7 +228,7 @@ class WKubeTask(GenericTask):
|
|
|
202
228
|
|
|
203
229
|
WKubeTaskPydantic(*t_args, **t_kwargs)
|
|
204
230
|
wkube_task_kwargs = WKubeTaskKwargs(*t_args, **t_kwargs)
|
|
205
|
-
wkube_task_meta.update(WKubeTaskMeta(*t_args, **t_kwargs).dict())
|
|
231
|
+
wkube_task_meta.update(WKubeTaskMeta(*t_args, **t_kwargs).dict(exclude_unset=True))
|
|
206
232
|
|
|
207
233
|
|
|
208
234
|
self.dispatch_model_task = JobDispatchModel(
|
|
@@ -210,7 +236,7 @@ class WKubeTask(GenericTask):
|
|
|
210
236
|
execute_cluster='WKUBE',
|
|
211
237
|
job_location='acc_native_jobs.dispatch_wkube_task',
|
|
212
238
|
job_args=[],
|
|
213
|
-
job_kwargs= wkube_task_kwargs.dict() if wkube_task_kwargs else dict(),
|
|
239
|
+
job_kwargs= wkube_task_kwargs.dict(exclude_unset=True) if wkube_task_kwargs else dict(),
|
|
214
240
|
**wkube_task_meta
|
|
215
241
|
)
|
|
216
242
|
|
|
@@ -18,6 +18,16 @@ class AccAPIError(Exception):
|
|
|
18
18
|
self.response = response
|
|
19
19
|
self.status_code = status_code
|
|
20
20
|
|
|
21
|
+
retries = urllib3.util.Retry(total=10, backoff_factor=1)
|
|
22
|
+
|
|
23
|
+
http_client = urllib3.poolmanager.PoolManager(
|
|
24
|
+
num_pools=20, retries=retries
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
http_client_wo_cert_verification = urllib3.poolmanager.PoolManager(
|
|
28
|
+
cert_reqs="CERT_NONE", num_pools=20, retries=retries
|
|
29
|
+
)
|
|
30
|
+
|
|
21
31
|
class AcceleratorTerminalCliProjectService:
|
|
22
32
|
def __init__(
|
|
23
33
|
self,
|
|
@@ -28,12 +38,10 @@ class AcceleratorTerminalCliProjectService:
|
|
|
28
38
|
|
|
29
39
|
self.user_token = user_token
|
|
30
40
|
|
|
31
|
-
retries = urllib3.util.Retry(total=10, backoff_factor=1)
|
|
32
|
-
|
|
33
41
|
if verify_cert:
|
|
34
|
-
self.http_client =
|
|
42
|
+
self.http_client = http_client
|
|
35
43
|
else:
|
|
36
|
-
self.http_client =
|
|
44
|
+
self.http_client = http_client_wo_cert_verification
|
|
37
45
|
|
|
38
46
|
self.server_url = server_url
|
|
39
47
|
self.cli_base_url = f"{self.server_url}/v1/aterm-cli"
|
|
@@ -70,6 +78,16 @@ class AcceleratorTerminalCliProjectService:
|
|
|
70
78
|
|
|
71
79
|
return res.json()
|
|
72
80
|
|
|
81
|
+
def get_file_url_from_repo(self, filename):
|
|
82
|
+
project_slug = filename.split('/')[0]
|
|
83
|
+
res = self.http_client_request(
|
|
84
|
+
"GET",
|
|
85
|
+
f"{self.cli_base_url}/{project_slug}/get-file-download-url/?filename={filename}",
|
|
86
|
+
headers=self.common_request_headers
|
|
87
|
+
)
|
|
88
|
+
if res.data:
|
|
89
|
+
return res.json()
|
|
90
|
+
|
|
73
91
|
def get_github_app_token(self, project_slug):
|
|
74
92
|
|
|
75
93
|
res = self.http_client_request(
|
|
@@ -80,6 +98,19 @@ class AcceleratorTerminalCliProjectService:
|
|
|
80
98
|
|
|
81
99
|
return res.json()
|
|
82
100
|
|
|
101
|
+
def get_jobstore_push_url(self, project_slug, filename):
|
|
102
|
+
|
|
103
|
+
res = self.http_client_request(
|
|
104
|
+
"GET",
|
|
105
|
+
f"{self.cli_base_url}/{project_slug}/jobstore-push-url/?filename={filename}",
|
|
106
|
+
headers=self.common_request_headers
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if res.status == 409 or res.status == '409':
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
return res.json()
|
|
113
|
+
|
|
83
114
|
def dispatch(self, project_slug, job_description):
|
|
84
115
|
|
|
85
116
|
try:
|
|
@@ -9,7 +9,7 @@ import importlib.util
|
|
|
9
9
|
from rich import print
|
|
10
10
|
from typing_extensions import Annotated
|
|
11
11
|
|
|
12
|
-
from accli.token import save_token_details, get_token, get_server_url, set_github_app_token
|
|
12
|
+
from accli.token import save_token_details, get_token, get_server_url, set_github_app_token, set_project_slug
|
|
13
13
|
|
|
14
14
|
from accli.CsvRegionalTimeseriesValidator import CsvRegionalTimeseriesValidator
|
|
15
15
|
from ._version import VERSION
|
|
@@ -181,7 +181,7 @@ def dispatch(
|
|
|
181
181
|
root_task_variable: Annotated[str, typer.Argument(help="Root task variable in workflow_file.")],
|
|
182
182
|
server: Annotated[str, typer.Option(help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
183
183
|
):
|
|
184
|
-
|
|
184
|
+
set_project_slug(project_slug)
|
|
185
185
|
access_token = get_token()
|
|
186
186
|
|
|
187
187
|
server_url = get_server_url()
|
|
@@ -61,6 +61,25 @@ def set_github_app_token(github_app_token):
|
|
|
61
61
|
db = TinyDB(db_path)
|
|
62
62
|
db.update({'github_app_token': github_app_token}, doc_ids=[1])
|
|
63
63
|
|
|
64
|
+
def set_project_slug(project_slug):
|
|
65
|
+
db_path = get_db_path()
|
|
66
|
+
db = TinyDB(db_path)
|
|
67
|
+
db.update({'project_slug': project_slug}, doc_ids=[1])
|
|
68
|
+
|
|
69
|
+
def get_project_slug():
|
|
70
|
+
db_path = get_db_path()
|
|
71
|
+
|
|
72
|
+
db = TinyDB(db_path)
|
|
73
|
+
|
|
74
|
+
for item in db:
|
|
75
|
+
project_slug = item.get('project_slug')
|
|
76
|
+
if project_slug:
|
|
77
|
+
break
|
|
78
|
+
|
|
79
|
+
if not project_slug:
|
|
80
|
+
print("project slug was not set.")
|
|
81
|
+
return project_slug
|
|
82
|
+
|
|
64
83
|
|
|
65
84
|
def get_server_url():
|
|
66
85
|
db_path = get_db_path()
|
|
@@ -12,7 +12,7 @@ description = "IIASA Accelerator Client"
|
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
license = {file = "LICENSE"}
|
|
14
14
|
requires-python = ">=3.7.17"
|
|
15
|
-
dependencies = ['urllib3', 'typer[all]', 'tinydb', 'requests', 'jsonschema', 'pydantic
|
|
15
|
+
dependencies = ['urllib3', 'typer[all]', 'tinydb', 'requests', 'jsonschema', 'pydantic', 'gitpython']
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Programming Language :: Python :: 3",
|
|
18
18
|
"License :: OSI Approved :: MIT License",
|
accli-0.4.1/.gitignore
DELETED
accli-0.4.1/Dockerfile.dev
DELETED
accli-0.4.1/requirements.txt
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|