openbayes-cli 0.4.5__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.
- openbayes_cli-0.4.5/PKG-INFO +62 -0
- openbayes_cli-0.4.5/README.md +23 -0
- openbayes_cli-0.4.5/bayes/__init__.py +0 -0
- openbayes_cli-0.4.5/bayes/client/__init__.py +0 -0
- openbayes_cli-0.4.5/bayes/client/base.py +20 -0
- openbayes_cli-0.4.5/bayes/client/dataset_version_client.py +91 -0
- openbayes_cli-0.4.5/bayes/client/gear_client.py +468 -0
- openbayes_cli-0.4.5/bayes/client/job_run_client.py +504 -0
- openbayes_cli-0.4.5/bayes/client/job_upload_client.py +114 -0
- openbayes_cli-0.4.5/bayes/client/org_client.py +67 -0
- openbayes_cli-0.4.5/bayes/client/resource_client.py +108 -0
- openbayes_cli-0.4.5/bayes/client/runtime_client.py +32 -0
- openbayes_cli-0.4.5/bayes/client/ssh_client.py +66 -0
- openbayes_cli-0.4.5/bayes/client/status_client.py +14 -0
- openbayes_cli-0.4.5/bayes/client/user_client.py +58 -0
- openbayes_cli-0.4.5/bayes/commands/__init__.py +0 -0
- openbayes_cli-0.4.5/bayes/commands/gear.py +691 -0
- openbayes_cli-0.4.5/bayes/commands/org.py +100 -0
- openbayes_cli-0.4.5/bayes/commands/ssh.py +70 -0
- openbayes_cli-0.4.5/bayes/error.py +9 -0
- openbayes_cli-0.4.5/bayes/model/__init__.py +0 -0
- openbayes_cli-0.4.5/bayes/model/dataset_version.py +14 -0
- openbayes_cli-0.4.5/bayes/model/file/__init__.py +0 -0
- openbayes_cli-0.4.5/bayes/model/file/data_bindings.py +42 -0
- openbayes_cli-0.4.5/bayes/model/file/openbayes_data.py +133 -0
- openbayes_cli-0.4.5/bayes/model/file/openbayes_gear.py +72 -0
- openbayes_cli-0.4.5/bayes/model/file/openbayes_ignore.py +75 -0
- openbayes_cli-0.4.5/bayes/model/file/openbayes_yaml.py +180 -0
- openbayes_cli-0.4.5/bayes/model/file/settings.py +157 -0
- openbayes_cli-0.4.5/bayes/model/party.py +35 -0
- openbayes_cli-0.4.5/bayes/model/resource.py +147 -0
- openbayes_cli-0.4.5/bayes/model/runtime.py +34 -0
- openbayes_cli-0.4.5/bayes/root.py +170 -0
- openbayes_cli-0.4.5/bayes/templates/openbayes_zh-Hans.yaml +134 -0
- openbayes_cli-0.4.5/bayes/templates/openbayesignore.yaml +3 -0
- openbayes_cli-0.4.5/bayes/usercases/__init__.py +0 -0
- openbayes_cli-0.4.5/bayes/usercases/archive_usecase.py +79 -0
- openbayes_cli-0.4.5/bayes/usercases/auth_usecase.py +35 -0
- openbayes_cli-0.4.5/bayes/usercases/dataset_version_usecase.py +61 -0
- openbayes_cli-0.4.5/bayes/usercases/disk_usecase.py +98 -0
- openbayes_cli-0.4.5/bayes/usercases/gear_download_usecese.py +113 -0
- openbayes_cli-0.4.5/bayes/usercases/gear_logs_usecase.py +44 -0
- openbayes_cli-0.4.5/bayes/usercases/gear_open_usecase.py +16 -0
- openbayes_cli-0.4.5/bayes/usercases/gear_run_usecase.py +123 -0
- openbayes_cli-0.4.5/bayes/usercases/gear_upload_usecase.py +248 -0
- openbayes_cli-0.4.5/bayes/usercases/gear_usecase.py +301 -0
- openbayes_cli-0.4.5/bayes/usercases/openbayes_data_usecase.py +73 -0
- openbayes_cli-0.4.5/bayes/usercases/org_usecase.py +85 -0
- openbayes_cli-0.4.5/bayes/usercases/resource_usecase.py +74 -0
- openbayes_cli-0.4.5/bayes/usercases/runtime_usecase.py +58 -0
- openbayes_cli-0.4.5/bayes/usercases/ssh_usecase.py +110 -0
- openbayes_cli-0.4.5/bayes/usercases/switch_usercase.py +19 -0
- openbayes_cli-0.4.5/bayes/utils.py +163 -0
- openbayes_cli-0.4.5/pyproject.toml +61 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: openbayes-cli
|
|
3
|
+
Version: 0.4.5
|
|
4
|
+
Summary: A Python CLI for OpenBayes
|
|
5
|
+
Home-page: https://openbayes.com
|
|
6
|
+
License: OpenBayes Public Source License
|
|
7
|
+
Keywords: openbayes,cli,machine learning
|
|
8
|
+
Author: OpenBayes
|
|
9
|
+
Author-email: dev@openbayes.com
|
|
10
|
+
Requires-Python: >=3.8,<4.0
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: Other/Proprietary License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Dist: aiohttp (>=3.10.2,<4.0.0)
|
|
21
|
+
Requires-Dist: archiver (>=0.2.2,<0.3.0)
|
|
22
|
+
Requires-Dist: gql (>=3.5.0,<4.0.0)
|
|
23
|
+
Requires-Dist: pathspec (>=0.12.1,<0.13.0)
|
|
24
|
+
Requires-Dist: pytz (>=2024.1,<2025.0)
|
|
25
|
+
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
26
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
27
|
+
Requires-Dist: requests-mock (>=1.12.1,<2.0.0)
|
|
28
|
+
Requires-Dist: tabulate (==0.9.0)
|
|
29
|
+
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
30
|
+
Requires-Dist: tqdm (>=4.66.5,<5.0.0)
|
|
31
|
+
Requires-Dist: tuspy (>=1.0.3,<2.0.0)
|
|
32
|
+
Requires-Dist: typer[all] (>=0.12.3,<0.13.0)
|
|
33
|
+
Requires-Dist: validators (>=0.29.0,<0.30.0)
|
|
34
|
+
Requires-Dist: wcwidth (>=0.2.13,<0.3.0)
|
|
35
|
+
Requires-Dist: websocket-client (>=1.8.0,<2.0.0)
|
|
36
|
+
Project-URL: Repository, https://github.com/signcl/openbayes-python-cli
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# openbayes python cli
|
|
40
|
+
|
|
41
|
+
## 环境依赖
|
|
42
|
+
|
|
43
|
+
1. python >= 3.8
|
|
44
|
+
2. [poetry](https://python-poetry.org/)
|
|
45
|
+
|
|
46
|
+
安装好 poetry 后,可以使用以下命令安装依赖:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
poetry install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 使用
|
|
53
|
+
|
|
54
|
+
通过命令:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
python main.py --help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
使用命令行。
|
|
61
|
+
|
|
62
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# openbayes python cli
|
|
2
|
+
|
|
3
|
+
## 环境依赖
|
|
4
|
+
|
|
5
|
+
1. python >= 3.8
|
|
6
|
+
2. [poetry](https://python-poetry.org/)
|
|
7
|
+
|
|
8
|
+
安装好 poetry 后,可以使用以下命令安装依赖:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
poetry install
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 使用
|
|
15
|
+
|
|
16
|
+
通过命令:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
python main.py --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
使用命令行。
|
|
23
|
+
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from gql import gql, Client
|
|
2
|
+
from gql.transport.aiohttp import AIOHTTPTransport
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BayesGQLClient:
|
|
6
|
+
def __init__(self, endpoint, token) -> None:
|
|
7
|
+
headers = {
|
|
8
|
+
"Origin": endpoint
|
|
9
|
+
}
|
|
10
|
+
if token is not None:
|
|
11
|
+
headers['Authorization'] = f'Bearer {token}'
|
|
12
|
+
|
|
13
|
+
transport = AIOHTTPTransport(
|
|
14
|
+
url=endpoint,
|
|
15
|
+
headers=headers)
|
|
16
|
+
self.client = Client(transport=transport)
|
|
17
|
+
|
|
18
|
+
def exec(self, query, variable_values={}):
|
|
19
|
+
return self.client.execute(gql(query), variable_values=variable_values)
|
|
20
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from gql.transport.exceptions import TransportQueryError
|
|
4
|
+
|
|
5
|
+
from bayes.client.base import BayesGQLClient
|
|
6
|
+
from bayes.model.dataset_version import PublicDatasetVersions, DatasetVersion
|
|
7
|
+
from bayes.model.party import Party, JobData, DatasetVersionData
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_public_dataset_version_for_gear_binding(client: BayesGQLClient):
|
|
11
|
+
query = """
|
|
12
|
+
query PublicDatasetVersions($status: [DatasetStatusInput], $tagIds: [Int!]) {
|
|
13
|
+
publicDatasetVersions(status: $status, tagIds: $tagIds) {
|
|
14
|
+
data {
|
|
15
|
+
semanticBindingName
|
|
16
|
+
createdAt
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
"""
|
|
21
|
+
variables = {"status": "VALID", "tagIds": [0]}
|
|
22
|
+
try:
|
|
23
|
+
response = client.exec(query, variables)
|
|
24
|
+
except TransportQueryError as e:
|
|
25
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
26
|
+
print(error_message, file=sys.stderr)
|
|
27
|
+
sys.exit(1)
|
|
28
|
+
|
|
29
|
+
result = response.get("publicDatasetVersions", {}).get("data", [])
|
|
30
|
+
if not result:
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
return PublicDatasetVersions(data=[DatasetVersion(**dataset) for dataset in result])
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_party_private_dataset_version_for_gear_binding(client: BayesGQLClient, party_name):
|
|
37
|
+
query = """
|
|
38
|
+
query Data($partyId: ID!, $status: [DatasetStatusInput]) {
|
|
39
|
+
party(id: $partyId) {
|
|
40
|
+
datasetVersions(status: $status) {
|
|
41
|
+
data {
|
|
42
|
+
semanticBindingName
|
|
43
|
+
createdAt
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
"""
|
|
49
|
+
variables = {"partyId": party_name, "status": ["ALL"]}
|
|
50
|
+
try:
|
|
51
|
+
response = client.exec(query, variables)
|
|
52
|
+
except TransportQueryError as e:
|
|
53
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
54
|
+
print(error_message, file=sys.stderr)
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
result = response.get("party", {})
|
|
58
|
+
if not result or not result.get("datasetVersions"):
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
return DatasetVersionData(**result["datasetVersions"])
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_party_job_output_for_gear_binding(client: BayesGQLClient, party_name):
|
|
65
|
+
query = """
|
|
66
|
+
query Jobs($partyId: ID!, $status: [JobStatusInput]) {
|
|
67
|
+
party(id: $partyId) {
|
|
68
|
+
jobs(status: $status) {
|
|
69
|
+
data {
|
|
70
|
+
output {
|
|
71
|
+
path
|
|
72
|
+
}
|
|
73
|
+
createdAt
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
"""
|
|
79
|
+
variables = {"partyId": party_name, "status": ["CANCELLING","RUNNING","CANCELLED", "SUCCEEDED", "FAILED"]}
|
|
80
|
+
try:
|
|
81
|
+
response = client.exec(query, variables)
|
|
82
|
+
except TransportQueryError as e:
|
|
83
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
84
|
+
print(error_message, file=sys.stderr)
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
|
|
87
|
+
result = response.get("party", {})
|
|
88
|
+
if not result or not result.get("jobs"):
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
return JobData(**result["jobs"])
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Optional, TYPE_CHECKING, Union
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from gql.transport.exceptions import TransportQueryError
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
from bayes.client.base import BayesGQLClient
|
|
10
|
+
from bayes.error import Error
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pydantic.typing import ForwardRef
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DownloadInfoPayload(BaseModel):
|
|
17
|
+
url: Optional[str]
|
|
18
|
+
type: Optional[str]
|
|
19
|
+
name: Optional[str]
|
|
20
|
+
|
|
21
|
+
def is_file(self) -> bool:
|
|
22
|
+
return self.type == "file"
|
|
23
|
+
|
|
24
|
+
def get_file_name(self) -> str:
|
|
25
|
+
if self.is_file():
|
|
26
|
+
return self.name
|
|
27
|
+
|
|
28
|
+
if self.name.endswith(".zip"):
|
|
29
|
+
return self.name
|
|
30
|
+
return self.name + ".zip"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Resource(BaseModel):
|
|
34
|
+
name: str
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Runtime(BaseModel):
|
|
38
|
+
framework: str
|
|
39
|
+
version: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Link(BaseModel):
|
|
43
|
+
name: str
|
|
44
|
+
value: Optional[str]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DataBinding(BaseModel):
|
|
48
|
+
__typename: str
|
|
49
|
+
mountPath: Optional[str] = None
|
|
50
|
+
semanticBindingName: Optional[str] = None
|
|
51
|
+
isDeleted: Optional[bool] = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DatasetBinding(DataBinding):
|
|
55
|
+
bindingAuth: Optional[str] = None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class JobOutputBinding(DataBinding):
|
|
59
|
+
id: str
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class SourceCode(BaseModel):
|
|
63
|
+
id: str
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Job(BaseModel):
|
|
67
|
+
id: Optional[str] = None
|
|
68
|
+
mode: Optional[str] = None
|
|
69
|
+
resource: Optional[Resource] = None
|
|
70
|
+
runtime: Optional[Runtime] = None
|
|
71
|
+
subStatus: Optional[str] = None
|
|
72
|
+
status: Optional[str] = None
|
|
73
|
+
size: Optional[int] = None
|
|
74
|
+
version: Optional[int] = None
|
|
75
|
+
createdAt: Optional[datetime] = None
|
|
76
|
+
links: Optional[List[Link]] = Field(default_factory=list)
|
|
77
|
+
project: Optional['ProjectModel'] = None # Forward reference
|
|
78
|
+
dataBindings: Optional[List[Union[DataBinding, DatasetBinding, JobOutputBinding]]] = Field(default_factory=list)
|
|
79
|
+
sourceCode: Optional[SourceCode] = None
|
|
80
|
+
command: Optional[str] = None
|
|
81
|
+
children: Optional[List['Job']] = Field(default_factory=list)
|
|
82
|
+
batchParentId: Optional[str] = None
|
|
83
|
+
|
|
84
|
+
def __init__(self, **data):
|
|
85
|
+
data['dataBindings'] = self._parse_data_bindings(data.get('dataBindings', []))
|
|
86
|
+
super().__init__(**data)
|
|
87
|
+
|
|
88
|
+
def children_count(self) -> int:
|
|
89
|
+
return len(self.children)
|
|
90
|
+
|
|
91
|
+
def get_link_value(self, link_name: str) -> Optional[str]:
|
|
92
|
+
for link in self.links:
|
|
93
|
+
if link.name == link_name:
|
|
94
|
+
return link.value
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
def get_runtime(self) -> str:
|
|
98
|
+
return f"{self.runtime.framework}-{self.runtime.version}"
|
|
99
|
+
|
|
100
|
+
def is_running(self) -> bool:
|
|
101
|
+
return self.status == "RUNNING"
|
|
102
|
+
|
|
103
|
+
def is_finished(self) -> bool:
|
|
104
|
+
return self.status in {"SUCCEEDED", "CANCELLED", "FAILED"}
|
|
105
|
+
|
|
106
|
+
def get_job_dataBindings(self) -> List[str]:
|
|
107
|
+
datasets = []
|
|
108
|
+
for binding in self.dataBindings or []:
|
|
109
|
+
# api server 数据绑定的格式 "^/output|/input[01234]|(/openbayes/input/input[01234])|(/openbayes/home)$"
|
|
110
|
+
# 如果是 datset 就拼接成 Qion1/serving数据集/1:/input1:ro 要带上 bindingAuth:分割后有三部分部分
|
|
111
|
+
# 如果是 output 就拼接成 Qion1/jobs/8.19-vli-1/2/2/output:/input1 :分割后只有两部分
|
|
112
|
+
if isinstance(binding, DatasetBinding):
|
|
113
|
+
data = f"{binding.semanticBindingName}:{binding.mountPath}:{binding.bindingAuth}"
|
|
114
|
+
datasets.append(data)
|
|
115
|
+
else:
|
|
116
|
+
data = f"{binding.semanticBindingName}:{binding.mountPath}"
|
|
117
|
+
datasets.append(data)
|
|
118
|
+
return datasets
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def _parse_data_bindings(bindings):
|
|
122
|
+
if bindings is None:
|
|
123
|
+
return []
|
|
124
|
+
|
|
125
|
+
parsed_bindings = []
|
|
126
|
+
for item in bindings:
|
|
127
|
+
typename = item.get('__typename')
|
|
128
|
+
if typename == 'DatasetBinding':
|
|
129
|
+
parsed_bindings.append(DatasetBinding(**item))
|
|
130
|
+
elif typename == 'JobOutputBinding':
|
|
131
|
+
parsed_bindings.append(JobOutputBinding(**item))
|
|
132
|
+
else:
|
|
133
|
+
parsed_bindings.append(DataBinding(**item))
|
|
134
|
+
return parsed_bindings
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class JobsData(BaseModel):
|
|
138
|
+
data: List[Job] = []
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class LatestJob(BaseModel):
|
|
142
|
+
status: Optional[str] = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class ProjectModel(BaseModel):
|
|
146
|
+
id: Optional[str] = None
|
|
147
|
+
name: Optional[str] = None
|
|
148
|
+
links: Optional[List[Link]] = Field(default_factory=list)
|
|
149
|
+
size: Optional[float] = None
|
|
150
|
+
updatedAt: Optional[datetime] = None
|
|
151
|
+
latestVersion: Optional[int] = None
|
|
152
|
+
latestJob: Optional[LatestJob] = None
|
|
153
|
+
jobs: Optional[JobsData] = None
|
|
154
|
+
|
|
155
|
+
def get_link_value(self, link_name: str) -> Optional[str]:
|
|
156
|
+
for link in self.links:
|
|
157
|
+
if link.name == link_name:
|
|
158
|
+
return link.value
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def get_party_project_by_id_or_name(client: BayesGQLClient, party_id, id_or_name, tagsNames, page,
|
|
163
|
+
perPage) -> ProjectModel:
|
|
164
|
+
query = """
|
|
165
|
+
query Projects($partyId: ID!, $q: String!, $page: Int!, $tagNames: [String!], $perPage: Int!) {
|
|
166
|
+
party(id: $partyId) {
|
|
167
|
+
projects(q: $q, page: $page, tagNames: $tagNames, perPage: $perPage) {
|
|
168
|
+
data {
|
|
169
|
+
id
|
|
170
|
+
name
|
|
171
|
+
links {
|
|
172
|
+
name
|
|
173
|
+
value
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
"""
|
|
180
|
+
variables = {"partyId": party_id, "q": id_or_name, "page": page, "tagNames": list(tagsNames), "perPage": perPage}
|
|
181
|
+
try:
|
|
182
|
+
response = client.exec(query, variables)
|
|
183
|
+
except TransportQueryError as e:
|
|
184
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
185
|
+
print(error_message, file=sys.stderr) # 打印错误消息到标准错误流
|
|
186
|
+
sys.exit(1)
|
|
187
|
+
|
|
188
|
+
result = response.get("party", {}).get("projects", {}).get("data", [])
|
|
189
|
+
if result is None or not result:
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
if isinstance(result, list) and isinstance(result[0], dict):
|
|
193
|
+
return ProjectModel(**result[0])
|
|
194
|
+
else:
|
|
195
|
+
raise Error("Returned project data is not in the expected format.")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def create_project(client: BayesGQLClient, party_name, name, desc, tags):
|
|
199
|
+
query = """
|
|
200
|
+
mutation CreateProject($userId: String!, $name: String!, $description: String, $tagNames: [TagInput]) {
|
|
201
|
+
createProject(userId: $userId, name: $name, description: $description, tagNames: $tagNames) {
|
|
202
|
+
id
|
|
203
|
+
name
|
|
204
|
+
links {
|
|
205
|
+
name
|
|
206
|
+
value
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
"""
|
|
211
|
+
variables = {"userId": party_name, "name": name, "description": desc, "tagNames": list(tags)}
|
|
212
|
+
try:
|
|
213
|
+
response = client.exec(query, variables)
|
|
214
|
+
except TransportQueryError as e:
|
|
215
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
216
|
+
print(error_message, file=sys.stderr) # 打印错误消息到标准错误流
|
|
217
|
+
sys.exit(1)
|
|
218
|
+
|
|
219
|
+
result = response.get("createProject")
|
|
220
|
+
if result is None:
|
|
221
|
+
raise Error("create project result is none")
|
|
222
|
+
|
|
223
|
+
return ProjectModel(**result)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_party_projects(client: BayesGQLClient, party_name, tags, page):
|
|
227
|
+
query = """
|
|
228
|
+
query Projects($partyId: ID!, $page: Int!, $tagNames: [String!]) {
|
|
229
|
+
party(id: $partyId) {
|
|
230
|
+
projects(page: $page, tagNames: $tagNames) {
|
|
231
|
+
data {
|
|
232
|
+
id
|
|
233
|
+
name
|
|
234
|
+
links {
|
|
235
|
+
name
|
|
236
|
+
value
|
|
237
|
+
}
|
|
238
|
+
size
|
|
239
|
+
updatedAt
|
|
240
|
+
latestVersion
|
|
241
|
+
latestJob {
|
|
242
|
+
status
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
"""
|
|
249
|
+
variables = {"partyId": party_name, "page": page, "tagNames": list(tags)}
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
response = client.exec(query, variables)
|
|
253
|
+
except TransportQueryError as e:
|
|
254
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
255
|
+
print(error_message, file=sys.stderr) # 打印错误消息到标准错误流
|
|
256
|
+
sys.exit(1)
|
|
257
|
+
|
|
258
|
+
project_data_list = response.get("party", {}).get("projects", {}).get("data", [])
|
|
259
|
+
if not project_data_list:
|
|
260
|
+
return None
|
|
261
|
+
|
|
262
|
+
return [ProjectModel(**project_data) for project_data in project_data_list]
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def get_project_jobs_by_id(client: BayesGQLClient, party_name, project_id, page):
|
|
266
|
+
query = """
|
|
267
|
+
query Project($projectId: String!, $userId: String!, $page: Int!) {
|
|
268
|
+
project(projectId: $projectId) {
|
|
269
|
+
jobs(userId: $userId, page: $page, projectId: $projectId) {
|
|
270
|
+
data {
|
|
271
|
+
id
|
|
272
|
+
mode
|
|
273
|
+
resource {
|
|
274
|
+
name
|
|
275
|
+
}
|
|
276
|
+
runtime {
|
|
277
|
+
framework
|
|
278
|
+
version
|
|
279
|
+
}
|
|
280
|
+
status
|
|
281
|
+
size
|
|
282
|
+
version
|
|
283
|
+
createdAt
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
id
|
|
287
|
+
name
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
"""
|
|
292
|
+
variables = {"userId": party_name, "projectId": project_id, "page": page}
|
|
293
|
+
try:
|
|
294
|
+
response = client.exec(query, variables)
|
|
295
|
+
except TransportQueryError as e:
|
|
296
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
297
|
+
print(error_message, file=sys.stderr) # 打印错误消息到标准错误流
|
|
298
|
+
sys.exit(1)
|
|
299
|
+
|
|
300
|
+
project_jobs_list = response.get("project", {})
|
|
301
|
+
if not project_jobs_list:
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
return ProjectModel(**project_jobs_list)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def get_logs(client: BayesGQLClient, jobId, party_name):
|
|
308
|
+
query = """
|
|
309
|
+
query jobLogs($userId: String!,$jobId: String!){
|
|
310
|
+
jobLogs(userId: $userId, jobId: $jobId)
|
|
311
|
+
}
|
|
312
|
+
"""
|
|
313
|
+
variables = {"userId": party_name, "jobId": jobId}
|
|
314
|
+
try:
|
|
315
|
+
response = client.exec(query, variables)
|
|
316
|
+
result = response.get("jobLogs", {})
|
|
317
|
+
return result
|
|
318
|
+
except TransportQueryError as e:
|
|
319
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
320
|
+
print(error_message, file=sys.stderr)
|
|
321
|
+
sys.exit(1)
|
|
322
|
+
except Exception as e:
|
|
323
|
+
print(str(e), file=sys.stderr)
|
|
324
|
+
sys.exit(1)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def get_job_by_id(client: BayesGQLClient, id, party_name):
|
|
328
|
+
query = """
|
|
329
|
+
query Job($userId: String!, $jobId: String!) {
|
|
330
|
+
job(userId: $userId, jobId: $jobId) {
|
|
331
|
+
id
|
|
332
|
+
mode
|
|
333
|
+
resource {
|
|
334
|
+
name
|
|
335
|
+
}
|
|
336
|
+
runtime {
|
|
337
|
+
framework
|
|
338
|
+
version
|
|
339
|
+
}
|
|
340
|
+
subStatus
|
|
341
|
+
status
|
|
342
|
+
size
|
|
343
|
+
version
|
|
344
|
+
createdAt
|
|
345
|
+
links {
|
|
346
|
+
name
|
|
347
|
+
value
|
|
348
|
+
}
|
|
349
|
+
dataBindings {
|
|
350
|
+
mountPath
|
|
351
|
+
semanticBindingName
|
|
352
|
+
isDeleted
|
|
353
|
+
... on DatasetBinding {
|
|
354
|
+
bindingAuth
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
project {
|
|
358
|
+
name
|
|
359
|
+
id
|
|
360
|
+
}
|
|
361
|
+
... on Task {
|
|
362
|
+
sourceCode {
|
|
363
|
+
id
|
|
364
|
+
}
|
|
365
|
+
command
|
|
366
|
+
}
|
|
367
|
+
... on BatchTask {
|
|
368
|
+
sourceCode {
|
|
369
|
+
id
|
|
370
|
+
}
|
|
371
|
+
command
|
|
372
|
+
size
|
|
373
|
+
children {
|
|
374
|
+
id
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
batchParentId
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
"""
|
|
381
|
+
variables = {"userId": party_name, "jobId": id}
|
|
382
|
+
try:
|
|
383
|
+
response = client.exec(query, variables)
|
|
384
|
+
except Exception as e:
|
|
385
|
+
if hasattr(e, 'errors') and e.errors:
|
|
386
|
+
error_message = e.errors[0]['message']
|
|
387
|
+
else:
|
|
388
|
+
error_message = str(e)
|
|
389
|
+
print(error_message, file=sys.stderr) # 打印错误消息到标准错误流
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
result = response.get("job", {})
|
|
393
|
+
if result is None or not result:
|
|
394
|
+
return None
|
|
395
|
+
|
|
396
|
+
return Job(**result)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def get_output_download_link(client: BayesGQLClient, id, party_name, download_from):
|
|
400
|
+
query = """
|
|
401
|
+
mutation createJobOutputDownloadUrl($userId: String!, $jobId: String!, $key: String!) {
|
|
402
|
+
createJobOutputDownloadUrl(userId: $userId, jobId: $jobId, key: $key) {
|
|
403
|
+
url
|
|
404
|
+
type
|
|
405
|
+
name
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
"""
|
|
410
|
+
variables = {"userId": party_name, "jobId": id, "key": download_from}
|
|
411
|
+
try:
|
|
412
|
+
response = client.exec(query, variables)
|
|
413
|
+
except TransportQueryError as e:
|
|
414
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
415
|
+
print(error_message, file=sys.stderr)
|
|
416
|
+
sys.exit(1)
|
|
417
|
+
|
|
418
|
+
result = response.get("createJobOutputDownloadUrl", {})
|
|
419
|
+
if result is None or not result:
|
|
420
|
+
return None
|
|
421
|
+
|
|
422
|
+
return DownloadInfoPayload(**result)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def download(url, filename, is_finished):
|
|
426
|
+
try:
|
|
427
|
+
response = requests.get(url, stream=True)
|
|
428
|
+
with open(filename, 'wb') as file:
|
|
429
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
430
|
+
if chunk:
|
|
431
|
+
file.write(chunk)
|
|
432
|
+
except Exception as err:
|
|
433
|
+
print(f"Error: {err}")
|
|
434
|
+
is_finished.put((False, err))
|
|
435
|
+
return err
|
|
436
|
+
|
|
437
|
+
is_finished.put((True, None))
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def stopJob(client: BayesGQLClient, id, party_name):
|
|
442
|
+
query = """
|
|
443
|
+
mutation StopJob($userId: String!, $jobId: String!) {
|
|
444
|
+
stopJob(userId: $userId, jobId: $jobId) {
|
|
445
|
+
id
|
|
446
|
+
links {
|
|
447
|
+
name
|
|
448
|
+
value
|
|
449
|
+
}
|
|
450
|
+
project {
|
|
451
|
+
name
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
"""
|
|
456
|
+
variables = {"userId": party_name, "jobId": id}
|
|
457
|
+
try:
|
|
458
|
+
response = client.exec(query, variables)
|
|
459
|
+
except TransportQueryError as e:
|
|
460
|
+
error_message = e.errors[0]['message'] if e.errors else str(e)
|
|
461
|
+
print(error_message, file=sys.stderr)
|
|
462
|
+
sys.exit(1)
|
|
463
|
+
|
|
464
|
+
result = response.get("stopJob", {})
|
|
465
|
+
if result is None or not result:
|
|
466
|
+
return None
|
|
467
|
+
|
|
468
|
+
return Job(**result)
|