accli 0.5.6__tar.gz → 0.6__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.5.6 → accli-0.6}/PKG-INFO +10 -2
- {accli-0.5.6 → accli-0.6}/README.md +9 -1
- {accli-0.5.6 → accli-0.6}/accli/AcceleratorJobProjectService.py +34 -0
- {accli-0.5.6 → accli-0.6}/accli/AcceleratorTaskDispatcher.py +19 -10
- {accli-0.5.6 → accli-0.6}/accli/AcceleratorTerminalCliProjectService.py +13 -0
- {accli-0.5.6 → accli-0.6}/accli/_version.py +1 -1
- {accli-0.5.6 → accli-0.6}/accli/cli.py +14 -9
- {accli-0.5.6 → accli-0.6}/accli.egg-info/PKG-INFO +10 -2
- {accli-0.5.6 → accli-0.6}/LICENSE +0 -0
- {accli-0.5.6 → accli-0.6}/accli/CsvRegionalTimeseriesValidator.py +0 -0
- {accli-0.5.6 → accli-0.6}/accli/__init__.py +0 -0
- {accli-0.5.6 → accli-0.6}/accli/__main__.py +0 -0
- {accli-0.5.6 → accli-0.6}/accli/common.py +0 -0
- {accli-0.5.6 → accli-0.6}/accli/token.py +0 -0
- {accli-0.5.6 → accli-0.6}/accli.egg-info/SOURCES.txt +0 -0
- {accli-0.5.6 → accli-0.6}/accli.egg-info/dependency_links.txt +0 -0
- {accli-0.5.6 → accli-0.6}/accli.egg-info/entry_points.txt +0 -0
- {accli-0.5.6 → accli-0.6}/accli.egg-info/requires.txt +0 -0
- {accli-0.5.6 → accli-0.6}/accli.egg-info/top_level.txt +0 -0
- {accli-0.5.6 → accli-0.6}/pyproject.toml +0 -0
- {accli-0.5.6 → accli-0.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: accli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6
|
|
4
4
|
Summary: IIASA Accelerator Client
|
|
5
5
|
Author-email: Wrufesh S <wrufesh@gmail.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -33,8 +33,16 @@ Requires-Python: >=3.7.17
|
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
|
|
36
|
-
# Accelerator terminal
|
|
36
|
+
# Accelerator terminal client and Python API
|
|
37
37
|
|
|
38
|
+
Provides a command-line client for interacting with the Accelerator as well as a Python API in the form of the `accli` package. These communicate with the rest API of the Accelerator [Control Services Backend](https://github.com/iiasa/control_services_backend).
|
|
39
|
+
|
|
40
|
+
Uses device authentication:
|
|
41
|
+
- Part 0Auth: [Device Authentication Flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow).
|
|
42
|
+
- Auth valid for 7 days.
|
|
43
|
+
- Grants are limited.
|
|
44
|
+
- Access via RBAC:
|
|
45
|
+
* Stateless tokens.
|
|
38
46
|
|
|
39
47
|
## User Guide
|
|
40
48
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
# Accelerator terminal
|
|
1
|
+
# Accelerator terminal client and Python API
|
|
2
2
|
|
|
3
|
+
Provides a command-line client for interacting with the Accelerator as well as a Python API in the form of the `accli` package. These communicate with the rest API of the Accelerator [Control Services Backend](https://github.com/iiasa/control_services_backend).
|
|
4
|
+
|
|
5
|
+
Uses device authentication:
|
|
6
|
+
- Part 0Auth: [Device Authentication Flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow).
|
|
7
|
+
- Auth valid for 7 days.
|
|
8
|
+
- Grants are limited.
|
|
9
|
+
- Access via RBAC:
|
|
10
|
+
* Stateless tokens.
|
|
3
11
|
|
|
4
12
|
## User Guide
|
|
5
13
|
|
|
@@ -82,6 +82,22 @@ class AcceleratorJobProjectService:
|
|
|
82
82
|
)
|
|
83
83
|
return todict(res.data)
|
|
84
84
|
|
|
85
|
+
|
|
86
|
+
def enumerate_files_by_prefix(self, prefix):
|
|
87
|
+
project_slug = filename.split('/')[0]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
b64_encoded_prefix = base64.b64encode(prefix.encode()).decode()
|
|
91
|
+
|
|
92
|
+
res = self.http_client_request(
|
|
93
|
+
"GET",
|
|
94
|
+
f"{self.cli_base_url}/{project_slug}/enumerate-all-files/{b64_encoded_prefix}",
|
|
95
|
+
headers=self.common_request_headers
|
|
96
|
+
)
|
|
97
|
+
if res.data:
|
|
98
|
+
return todict(res.data)
|
|
99
|
+
|
|
100
|
+
|
|
85
101
|
def get_file_url_from_repo(self, filename):
|
|
86
102
|
project_slug = filename.split('/')[0]
|
|
87
103
|
res = self.http_client_request(
|
|
@@ -633,3 +649,21 @@ class Fs:
|
|
|
633
649
|
Fs.write_stream_remote(fstream, dest_filepath, user_token, server_url)
|
|
634
650
|
else:
|
|
635
651
|
Fs.write_stream_local(fstream, dest_filepath)
|
|
652
|
+
|
|
653
|
+
@staticmethod
|
|
654
|
+
def enumerate_files_by_prefix(prefix):
|
|
655
|
+
user_token = os.environ.get("ACC_JOB_TOKEN", None)
|
|
656
|
+
server_url = os.environ.get("ACC_JOB_GATEWAY_SERVER", None)
|
|
657
|
+
|
|
658
|
+
if not (user_token and server_url):
|
|
659
|
+
raise ValueError("Remote data repository credentials not found.")
|
|
660
|
+
|
|
661
|
+
accelerator_job_service = AcceleratorJobProjectService(
|
|
662
|
+
user_token,
|
|
663
|
+
server_url=server_url,
|
|
664
|
+
verify_cert=True
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
return accelerator_job_service.enumerate_files_by_prefix(
|
|
668
|
+
prefix
|
|
669
|
+
)
|
|
@@ -8,7 +8,11 @@ import requests
|
|
|
8
8
|
from typing import Optional, List, Dict
|
|
9
9
|
from pydantic.v1 import BaseModel, root_validator
|
|
10
10
|
from accli.AcceleratorTerminalCliProjectService import AcceleratorTerminalCliProjectService
|
|
11
|
-
from accli.token import
|
|
11
|
+
from accli.token import (
|
|
12
|
+
get_github_app_token,
|
|
13
|
+
get_token, get_server_url,
|
|
14
|
+
get_project_slug
|
|
15
|
+
)
|
|
12
16
|
|
|
13
17
|
FOLDER_JOB_REPO_URL = 'https://github.com/IIASA-Accelerator/wkube-job.git'
|
|
14
18
|
|
|
@@ -74,6 +78,9 @@ def push_folder_job(dir):
|
|
|
74
78
|
|
|
75
79
|
copy_tree(dir, repo_dir)
|
|
76
80
|
|
|
81
|
+
if os.path.isfile(f'{repo_dir}/wkube.py'):
|
|
82
|
+
os.remove(f'{repo_dir}/wkube.py')
|
|
83
|
+
|
|
77
84
|
temp_zip_path = f"{repo_dir}/temp.zip"
|
|
78
85
|
|
|
79
86
|
compress_folder(repo_dir, temp_zip_path)
|
|
@@ -106,7 +113,9 @@ def push_folder_job(dir):
|
|
|
106
113
|
|
|
107
114
|
|
|
108
115
|
class JobDispatchModel(BaseModel):
|
|
109
|
-
is_holder_job: bool = True
|
|
116
|
+
is_holder_job: bool = True
|
|
117
|
+
|
|
118
|
+
name: str
|
|
110
119
|
|
|
111
120
|
execute_cluster: str
|
|
112
121
|
job_location: str
|
|
@@ -150,7 +159,7 @@ class WKubeTaskMeta(BaseModel):
|
|
|
150
159
|
class WKubeTaskKwargs(BaseModel):
|
|
151
160
|
docker_image: Optional[str]
|
|
152
161
|
|
|
153
|
-
job_folder:
|
|
162
|
+
job_folder: str = './'
|
|
154
163
|
|
|
155
164
|
repo_url: Optional[str] # required when docker image is not present
|
|
156
165
|
repo_branch: Optional[str] # required when docker image is not present
|
|
@@ -176,21 +185,21 @@ class WKubeTaskKwargs(BaseModel):
|
|
|
176
185
|
def validate_root(cls, values):
|
|
177
186
|
if not values.get('docker_image'):
|
|
178
187
|
|
|
179
|
-
job_folder = values.get('job_folder')
|
|
188
|
+
job_folder = values.get('job_folder', './')
|
|
180
189
|
|
|
181
|
-
if not
|
|
182
|
-
|
|
190
|
+
if not (values.get('repo_url') and values.get('repo_branch')):
|
|
191
|
+
remote_url, branch_name = push_folder_job(job_folder)
|
|
192
|
+
values['repo_url'] = remote_url
|
|
193
|
+
values['repo_branch'] = branch_name
|
|
194
|
+
else:
|
|
183
195
|
if not values.get('repo_url'):
|
|
184
196
|
# TODO if has no repo url just set it
|
|
185
197
|
raise ValueError("repo_url is required")
|
|
186
198
|
|
|
187
199
|
if not values.get('repo_branch'):
|
|
188
200
|
raise ValueError('repo_branch is required')
|
|
189
|
-
else:
|
|
190
|
-
remote_url, branch_name = push_folder_job(job_folder)
|
|
191
|
-
values['repo_url'] = remote_url
|
|
192
|
-
values['repo_branch'] = branch_name
|
|
193
201
|
|
|
202
|
+
|
|
194
203
|
if not values.get('docker_filename'):
|
|
195
204
|
if not values.get("base_stack"):
|
|
196
205
|
raise ValueError("base_stack is required when dockerfile is not defined")
|
|
@@ -50,6 +50,19 @@ class AcceleratorTerminalCliProjectService:
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
def http_client_request(self, *args, **kwargs):
|
|
53
|
+
|
|
54
|
+
if urllib3.__version__.startswith('1.'):
|
|
55
|
+
if 'json' in kwargs:
|
|
56
|
+
json_dict = kwargs.pop('json')
|
|
57
|
+
|
|
58
|
+
assert isinstance(json_dict, dict), (
|
|
59
|
+
f"urllib request: json keyword argument should be dict."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
encoded_data = json.dumps(json_dict).encode('utf-8')
|
|
63
|
+
|
|
64
|
+
kwargs['body'] = encoded_data
|
|
65
|
+
|
|
53
66
|
res = self.http_client.request(*args, **kwargs)
|
|
54
67
|
|
|
55
68
|
if str(res.status)[0] in ['4', '5']:
|
|
@@ -47,8 +47,8 @@ def about():
|
|
|
47
47
|
|
|
48
48
|
@app.command()
|
|
49
49
|
def login(
|
|
50
|
-
server: Annotated[str, typer.Option(help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
51
|
-
webcli: Annotated[str, typer.Option(help="Accelerator web client for authorization.")] = "https://accelerator.iiasa.ac.at"
|
|
50
|
+
server: Annotated[str, typer.Option(..., '-c',help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
51
|
+
webcli: Annotated[str, typer.Option(..., '-s', help="Accelerator web client for authorization.")] = "https://accelerator.iiasa.ac.at"
|
|
52
52
|
):
|
|
53
53
|
print(
|
|
54
54
|
f"[bold cyan]Welcome to Accelerator Terminal Client.[/bold cyan]\n"
|
|
@@ -100,7 +100,7 @@ def upload(
|
|
|
100
100
|
project_slug: Annotated[str, typer.Argument(help="Unique Accelerator project slug.")],
|
|
101
101
|
path: Annotated[str, typer.Argument(help="Folder path to upload to Accelerator project space.")],
|
|
102
102
|
folder_name: Annotated[str, typer.Argument(help="Name of the folder to be made in Accelerator project space.")],
|
|
103
|
-
max_workers: Annotated[int, typer.Option(help="Maximum worker pool for multipart upload.")] = os.cpu_count()
|
|
103
|
+
max_workers: Annotated[int, typer.Option(..., '-w',help="Maximum worker pool for multipart upload.")] = os.cpu_count()
|
|
104
104
|
):
|
|
105
105
|
|
|
106
106
|
|
|
@@ -154,7 +154,7 @@ def validate(
|
|
|
154
154
|
project_slug: Annotated[str, typer.Argument(help="Unique Accelerator project slug.")],
|
|
155
155
|
template_slug: Annotated[str, typer.Argument(help="Unique project template slug")],
|
|
156
156
|
filepath: Annotated[str, typer.Argument(help="Path of the file to validate")],
|
|
157
|
-
server: Annotated[str, typer.Option(help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
157
|
+
server: Annotated[str, typer.Option(..., '-s',help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
158
158
|
):
|
|
159
159
|
|
|
160
160
|
|
|
@@ -176,14 +176,12 @@ def validate(
|
|
|
176
176
|
@app.command()
|
|
177
177
|
def dispatch(
|
|
178
178
|
project_slug: Annotated[str, typer.Argument(help="Unique Accelerator project slug.")],
|
|
179
|
-
# experiment_name: Annotated[str, typer.Argument(help="Experiment or simulation name. Please put name in quote it includes space(s).")],
|
|
180
|
-
workflow_file: Annotated[str, typer.Argument(help="Python workflow filepath.")],
|
|
181
179
|
root_task_variable: Annotated[str, typer.Argument(help="Root task variable in workflow_file.")],
|
|
182
|
-
server: Annotated[str, typer.Option(help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
180
|
+
server: Annotated[str, typer.Option(..., '-s', help="Accelerator server url.")] = "https://accelerator-api.iiasa.ac.at",
|
|
181
|
+
workflow_filename: Annotated[str, typer.Option(..., '-f', help="Python workflow filepath.")] = "wkube.py"
|
|
183
182
|
):
|
|
184
183
|
set_project_slug(project_slug)
|
|
185
184
|
access_token = get_token()
|
|
186
|
-
|
|
187
185
|
server_url = get_server_url()
|
|
188
186
|
|
|
189
187
|
term_cli_project_service = AcceleratorTerminalCliProjectService(
|
|
@@ -192,7 +190,14 @@ def dispatch(
|
|
|
192
190
|
verify_cert=False
|
|
193
191
|
)
|
|
194
192
|
|
|
195
|
-
|
|
193
|
+
base_dir = os.getcwd()
|
|
194
|
+
|
|
195
|
+
if base_dir.endswith('/'):
|
|
196
|
+
workflow_filepath = f"{base_dir}{workflow_filename}"
|
|
197
|
+
else:
|
|
198
|
+
workflow_filepath = f"{base_dir}/{workflow_filename}"
|
|
199
|
+
|
|
200
|
+
spec = importlib.util.spec_from_file_location("workflow", workflow_filepath)
|
|
196
201
|
|
|
197
202
|
module = importlib.util.module_from_spec(spec)
|
|
198
203
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: accli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6
|
|
4
4
|
Summary: IIASA Accelerator Client
|
|
5
5
|
Author-email: Wrufesh S <wrufesh@gmail.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -33,8 +33,16 @@ Requires-Python: >=3.7.17
|
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
|
|
36
|
-
# Accelerator terminal
|
|
36
|
+
# Accelerator terminal client and Python API
|
|
37
37
|
|
|
38
|
+
Provides a command-line client for interacting with the Accelerator as well as a Python API in the form of the `accli` package. These communicate with the rest API of the Accelerator [Control Services Backend](https://github.com/iiasa/control_services_backend).
|
|
39
|
+
|
|
40
|
+
Uses device authentication:
|
|
41
|
+
- Part 0Auth: [Device Authentication Flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow).
|
|
42
|
+
- Auth valid for 7 days.
|
|
43
|
+
- Grants are limited.
|
|
44
|
+
- Access via RBAC:
|
|
45
|
+
* Stateless tokens.
|
|
38
46
|
|
|
39
47
|
## User Guide
|
|
40
48
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|