openbayes-cli 0.4.5__py3-none-any.whl

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.
Files changed (55) hide show
  1. bayes/__init__.py +0 -0
  2. bayes/client/__init__.py +0 -0
  3. bayes/client/base.py +20 -0
  4. bayes/client/dataset_version_client.py +91 -0
  5. bayes/client/gear_client.py +468 -0
  6. bayes/client/job_run_client.py +504 -0
  7. bayes/client/job_upload_client.py +114 -0
  8. bayes/client/org_client.py +67 -0
  9. bayes/client/resource_client.py +108 -0
  10. bayes/client/runtime_client.py +32 -0
  11. bayes/client/ssh_client.py +66 -0
  12. bayes/client/status_client.py +14 -0
  13. bayes/client/user_client.py +58 -0
  14. bayes/commands/__init__.py +0 -0
  15. bayes/commands/gear.py +691 -0
  16. bayes/commands/org.py +100 -0
  17. bayes/commands/ssh.py +70 -0
  18. bayes/error.py +9 -0
  19. bayes/model/__init__.py +0 -0
  20. bayes/model/dataset_version.py +14 -0
  21. bayes/model/file/__init__.py +0 -0
  22. bayes/model/file/data_bindings.py +42 -0
  23. bayes/model/file/openbayes_data.py +133 -0
  24. bayes/model/file/openbayes_gear.py +72 -0
  25. bayes/model/file/openbayes_ignore.py +75 -0
  26. bayes/model/file/openbayes_yaml.py +180 -0
  27. bayes/model/file/settings.py +157 -0
  28. bayes/model/party.py +35 -0
  29. bayes/model/resource.py +147 -0
  30. bayes/model/runtime.py +34 -0
  31. bayes/root.py +170 -0
  32. bayes/templates/openbayes_zh-Hans.yaml +134 -0
  33. bayes/templates/openbayesignore.yaml +3 -0
  34. bayes/usercases/__init__.py +0 -0
  35. bayes/usercases/archive_usecase.py +79 -0
  36. bayes/usercases/auth_usecase.py +35 -0
  37. bayes/usercases/dataset_version_usecase.py +61 -0
  38. bayes/usercases/disk_usecase.py +98 -0
  39. bayes/usercases/gear_download_usecese.py +113 -0
  40. bayes/usercases/gear_logs_usecase.py +44 -0
  41. bayes/usercases/gear_open_usecase.py +16 -0
  42. bayes/usercases/gear_run_usecase.py +123 -0
  43. bayes/usercases/gear_upload_usecase.py +248 -0
  44. bayes/usercases/gear_usecase.py +301 -0
  45. bayes/usercases/openbayes_data_usecase.py +73 -0
  46. bayes/usercases/org_usecase.py +85 -0
  47. bayes/usercases/resource_usecase.py +74 -0
  48. bayes/usercases/runtime_usecase.py +58 -0
  49. bayes/usercases/ssh_usecase.py +110 -0
  50. bayes/usercases/switch_usercase.py +19 -0
  51. bayes/utils.py +163 -0
  52. openbayes_cli-0.4.5.dist-info/METADATA +62 -0
  53. openbayes_cli-0.4.5.dist-info/RECORD +55 -0
  54. openbayes_cli-0.4.5.dist-info/WHEEL +4 -0
  55. openbayes_cli-0.4.5.dist-info/entry_points.txt +3 -0
bayes/__init__.py ADDED
File without changes
File without changes
bayes/client/base.py ADDED
@@ -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)