gmicloud 0.1.3__py3-none-any.whl → 0.1.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.
- gmicloud/__init__.py +12 -1
- gmicloud/_internal/_client/_artifact_client.py +126 -56
- gmicloud/_internal/_client/_http_client.py +5 -2
- gmicloud/_internal/_client/_iam_client.py +108 -20
- gmicloud/_internal/_client/_task_client.py +75 -30
- gmicloud/_internal/_enums.py +8 -0
- gmicloud/_internal/_manager/_artifact_manager.py +17 -5
- gmicloud/_internal/_manager/_iam_manager.py +36 -0
- gmicloud/_internal/_manager/_task_manager.py +19 -12
- gmicloud/_internal/_models.py +129 -11
- gmicloud/client.py +26 -5
- gmicloud/tests/test_artifacts.py +14 -15
- gmicloud/tests/test_tasks.py +1 -1
- {gmicloud-0.1.3.dist-info → gmicloud-0.1.5.dist-info}/METADATA +88 -56
- gmicloud-0.1.5.dist-info/RECORD +27 -0
- {gmicloud-0.1.3.dist-info → gmicloud-0.1.5.dist-info}/WHEEL +1 -1
- gmicloud-0.1.3.dist-info/RECORD +0 -26
- {gmicloud-0.1.3.dist-info → gmicloud-0.1.5.dist-info}/top_level.txt +0 -0
@@ -81,7 +81,11 @@ class ArtifactManager:
|
|
81
81
|
if not artifact_template_id or not artifact_template_id.strip():
|
82
82
|
raise ValueError("Artifact template ID is required and cannot be empty.")
|
83
83
|
|
84
|
-
|
84
|
+
resp = self.artifact_client.create_artifact_from_template(artifact_template_id)
|
85
|
+
if not resp or not resp.artifact_id:
|
86
|
+
raise ValueError("Failed to create artifact from template.")
|
87
|
+
|
88
|
+
return resp.artifact_id
|
85
89
|
|
86
90
|
def rebuild_artifact(self, artifact_id: str) -> RebuildArtifactResponse:
|
87
91
|
"""
|
@@ -170,7 +174,11 @@ class ArtifactManager:
|
|
170
174
|
|
171
175
|
req = GetBigFileUploadUrlRequest(artifact_id=artifact_id, file_name=model_file_name, file_type=model_file_type)
|
172
176
|
|
173
|
-
|
177
|
+
resp = self.artifact_client.get_bigfile_upload_url(req)
|
178
|
+
if not resp or not resp.upload_link:
|
179
|
+
raise ValueError("Failed to get bigfile upload URL.")
|
180
|
+
|
181
|
+
return resp.upload_link
|
174
182
|
|
175
183
|
def delete_bigfile(self, artifact_id: str, file_name: str) -> str:
|
176
184
|
"""
|
@@ -182,7 +190,11 @@ class ArtifactManager:
|
|
182
190
|
self._validate_artifact_id(artifact_id)
|
183
191
|
self._validate_file_name(file_name)
|
184
192
|
|
185
|
-
|
193
|
+
resp = self.artifact_client.delete_bigfile(artifact_id, file_name)
|
194
|
+
if not resp or not resp.status:
|
195
|
+
raise ValueError("Failed to delete bigfile.")
|
196
|
+
|
197
|
+
return resp.status
|
186
198
|
|
187
199
|
def upload_large_file(self, upload_link: str, file_path: str) -> None:
|
188
200
|
"""
|
@@ -229,14 +241,14 @@ class ArtifactManager:
|
|
229
241
|
|
230
242
|
return artifact_id
|
231
243
|
|
232
|
-
def
|
244
|
+
def get_public_templates(self) -> List[ArtifactTemplate]:
|
233
245
|
"""
|
234
246
|
Fetch all artifact templates.
|
235
247
|
|
236
248
|
:return: A list of ArtifactTemplate objects.
|
237
249
|
:rtype: List[ArtifactTemplate]
|
238
250
|
"""
|
239
|
-
return self.artifact_client.
|
251
|
+
return self.artifact_client.get_public_templates()
|
240
252
|
|
241
253
|
@staticmethod
|
242
254
|
def _validate_file_name(file_name: str) -> None:
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from .._client._iam_client import IAMClient
|
3
|
+
from .._models import *
|
4
|
+
|
5
|
+
|
6
|
+
class IAMManager:
|
7
|
+
"""
|
8
|
+
IamManager handles operations related to IAM, including user authentication and authorization.
|
9
|
+
"""
|
10
|
+
|
11
|
+
def __init__(self, iam_client: IAMClient):
|
12
|
+
"""
|
13
|
+
Initialize the IAMManager instance and the associated IAMClient.
|
14
|
+
"""
|
15
|
+
self.iam_client = iam_client
|
16
|
+
|
17
|
+
def create_org_api_key(self, name: str, expires_at: Optional[int] = None) -> str:
|
18
|
+
"""
|
19
|
+
Creates a new API key for the current user.
|
20
|
+
"""
|
21
|
+
|
22
|
+
if not name:
|
23
|
+
raise ValueError("API key name cannot be empty")
|
24
|
+
if not expires_at:
|
25
|
+
# Set the expiration date to 30 days from now
|
26
|
+
expires_at = int(datetime.now().timestamp()) + 30 * 24 * 60 * 60
|
27
|
+
print(expires_at)
|
28
|
+
|
29
|
+
return self.iam_client.create_org_api_key(
|
30
|
+
CreateAPIKeyRequest(name=name, type="ie_model", expiresAt=expires_at))
|
31
|
+
|
32
|
+
def get_org_api_keys(self) -> List[APIKey]:
|
33
|
+
"""
|
34
|
+
Fetches all API keys for the current user.
|
35
|
+
"""
|
36
|
+
return self.iam_client.get_org_api_keys().keys
|
@@ -37,7 +37,11 @@ class TaskManager:
|
|
37
37
|
|
38
38
|
:return: A list of `Task` objects.
|
39
39
|
"""
|
40
|
-
|
40
|
+
resp = self.task_client.get_all_tasks(self.iam_client.get_user_id())
|
41
|
+
if not resp or not resp.tasks:
|
42
|
+
return []
|
43
|
+
|
44
|
+
return resp.tasks
|
41
45
|
|
42
46
|
def create_task(self, task: Task) -> Task:
|
43
47
|
"""
|
@@ -51,8 +55,11 @@ class TaskManager:
|
|
51
55
|
self._validate_task(task)
|
52
56
|
if not task.owner:
|
53
57
|
task.owner = TaskOwner(user_id=self.iam_client.get_user_id())
|
58
|
+
resp = self.task_client.create_task(task)
|
59
|
+
if not resp or not resp.task:
|
60
|
+
raise ValueError("Failed to create task.")
|
54
61
|
|
55
|
-
return
|
62
|
+
return resp.task
|
56
63
|
|
57
64
|
def create_task_from_file(self, artifact_id: str, config_file_path: str, trigger_timestamp: int = None) -> Task:
|
58
65
|
"""
|
@@ -76,7 +83,7 @@ class TaskManager:
|
|
76
83
|
|
77
84
|
return self.create_task(task)
|
78
85
|
|
79
|
-
def update_task_schedule(self, task: Task):
|
86
|
+
def update_task_schedule(self, task: Task) -> bool:
|
80
87
|
"""
|
81
88
|
Update the schedule of an existing task.
|
82
89
|
|
@@ -87,10 +94,10 @@ class TaskManager:
|
|
87
94
|
self._validate_task(task)
|
88
95
|
self._validate_not_empty(task.task_id, "Task ID")
|
89
96
|
|
90
|
-
self.task_client.update_task_schedule(task)
|
97
|
+
return self.task_client.update_task_schedule(task)
|
91
98
|
|
92
99
|
def update_task_schedule_from_file(self, artifact_id: str, task_id: str, config_file_path: str,
|
93
|
-
trigger_timestamp: int = None):
|
100
|
+
trigger_timestamp: int = None) -> bool:
|
94
101
|
"""
|
95
102
|
Update the schedule of an existing task using data from a file. The file should contain a valid task definition.
|
96
103
|
|
@@ -112,9 +119,9 @@ class TaskManager:
|
|
112
119
|
if trigger_timestamp:
|
113
120
|
task.config.task_scheduling.scheduling_oneoff.trigger_timestamp = trigger_timestamp
|
114
121
|
|
115
|
-
self.update_task_schedule(task)
|
122
|
+
return self.update_task_schedule(task)
|
116
123
|
|
117
|
-
def start_task(self, task_id: str):
|
124
|
+
def start_task(self, task_id: str) -> bool:
|
118
125
|
"""
|
119
126
|
Start a task by its ID.
|
120
127
|
|
@@ -124,9 +131,9 @@ class TaskManager:
|
|
124
131
|
"""
|
125
132
|
self._validate_not_empty(task_id, "Task ID")
|
126
133
|
|
127
|
-
self.task_client.start_task(task_id)
|
134
|
+
return self.task_client.start_task(task_id)
|
128
135
|
|
129
|
-
def stop_task(self, task_id: str):
|
136
|
+
def stop_task(self, task_id: str) -> bool:
|
130
137
|
"""
|
131
138
|
Stop a task by its ID.
|
132
139
|
|
@@ -136,7 +143,7 @@ class TaskManager:
|
|
136
143
|
"""
|
137
144
|
self._validate_not_empty(task_id, "Task ID")
|
138
145
|
|
139
|
-
self.task_client.stop_task(task_id)
|
146
|
+
return self.task_client.stop_task(task_id)
|
140
147
|
|
141
148
|
def get_usage_data(self, start_timestamp: str, end_timestamp: str) -> GetUsageDataResponse:
|
142
149
|
"""
|
@@ -151,7 +158,7 @@ class TaskManager:
|
|
151
158
|
|
152
159
|
return self.task_client.get_usage_data(start_timestamp, end_timestamp)
|
153
160
|
|
154
|
-
def archive_task(self, task_id: str):
|
161
|
+
def archive_task(self, task_id: str) -> bool:
|
155
162
|
"""
|
156
163
|
Archive a task by its ID.
|
157
164
|
|
@@ -161,7 +168,7 @@ class TaskManager:
|
|
161
168
|
"""
|
162
169
|
self._validate_not_empty(task_id, "Task ID")
|
163
170
|
|
164
|
-
self.task_client.archive_task(task_id)
|
171
|
+
return self.task_client.archive_task(task_id)
|
165
172
|
|
166
173
|
@staticmethod
|
167
174
|
def _validate_not_empty(value: str, name: str):
|
gmicloud/_internal/_models.py
CHANGED
@@ -2,7 +2,7 @@ from typing import Optional, List
|
|
2
2
|
from datetime import datetime
|
3
3
|
|
4
4
|
from pydantic import BaseModel
|
5
|
-
from gmicloud._internal._enums import BuildStatus, TaskEndpointStatus
|
5
|
+
from gmicloud._internal._enums import BuildStatus, TaskStatus, TaskEndpointStatus
|
6
6
|
|
7
7
|
|
8
8
|
class BigFileMetadata(BaseModel):
|
@@ -24,6 +24,7 @@ class ArtifactMetadata(BaseModel):
|
|
24
24
|
artifact_description: Optional[str] = "" # Description of the artifact.
|
25
25
|
artifact_tags: Optional[List[str]] = "" # Comma-separated tags for categorizing the artifact.
|
26
26
|
artifact_volume_path: Optional[str] = "" # Path to the volume where the artifact is stored.
|
27
|
+
artifact_template_id: Optional[str] = "" # The template ID used to create this artifact.
|
27
28
|
|
28
29
|
|
29
30
|
class ArtifactData(BaseModel):
|
@@ -130,7 +131,7 @@ class DeleteBigfileResponse(BaseModel):
|
|
130
131
|
status: Optional[str] = "" # Status of the deletion process.
|
131
132
|
|
132
133
|
|
133
|
-
class
|
134
|
+
class GetPublicTemplatesResponse(BaseModel):
|
134
135
|
"""
|
135
136
|
Response containing a list of artifact templates.
|
136
137
|
"""
|
@@ -141,24 +142,46 @@ class ArtifactTemplate(BaseModel):
|
|
141
142
|
"""
|
142
143
|
Template for creating an artifact.
|
143
144
|
"""
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
145
|
+
template_id: str # Unique identifier for the artifact template.
|
146
|
+
template_data: Optional["TemplateData"] = None # Data for the artifact template.
|
147
|
+
template_metadata: Optional["TemplateMetadata"] = None # Metadata for the artifact template.
|
148
|
+
|
149
|
+
|
150
|
+
class TemplateMetadata(BaseModel):
|
151
|
+
"""
|
152
|
+
Metadata for an artifact template.
|
153
|
+
"""
|
154
|
+
create_at: Optional[str] = None # Timestamp when the template was created.
|
155
|
+
create_by: Optional[str] = "" # ID of the user who created the template.
|
156
|
+
create_by_org_id: Optional[str] = "" # ID of the organization to which the user belongs.
|
157
|
+
is_public: Optional[bool] = False # Indicates if the template is public.
|
158
|
+
update_at: Optional[str] = None # Timestamp when the template was last updated.
|
159
|
+
update_by: Optional[str] = "" # ID of the user who last updated the template.
|
160
|
+
|
161
|
+
class TemplateData(BaseModel):
|
162
|
+
"""
|
163
|
+
Data for an artifact template.
|
164
|
+
"""
|
165
|
+
description: Optional[str] = "" # Description of the artifact template.
|
166
|
+
icon_link: Optional[str] = "" # Link to the icon for the artifact template.
|
167
|
+
image_link: Optional[str] = "" # Link to the image for the artifact template.
|
168
|
+
name: Optional[str] = "" # Name of the artifact template.
|
169
|
+
ray: Optional["RayContent"] = None # Template for Ray-based artifacts.
|
149
170
|
resources: Optional["ResourcesTemplate"] = None # Resource allocation template.
|
171
|
+
tags: Optional[List[str]] = None # Tags associated with the artifact template.
|
172
|
+
volume_path: Optional[str] = "" # Path to the volume where the artifact is stored.
|
150
173
|
|
151
174
|
|
152
|
-
class
|
175
|
+
class RayContent(BaseModel):
|
153
176
|
deployment_name: Optional[str] = "" # Name of the deployment.
|
154
177
|
file_path: Optional[str] = "" # Path to the task file in storage.
|
155
|
-
version: Optional[str] = "" # Version of Ray used.
|
156
178
|
|
157
179
|
|
158
180
|
class ResourcesTemplate(BaseModel):
|
159
181
|
cpu: Optional[int] = 0 # Number of CPU cores allocated.
|
160
182
|
memory: Optional[int] = 0 # Amount of RAM (in GB) allocated.
|
161
183
|
gpu: Optional[int] = 0 # Number of GPUs allocated.
|
184
|
+
gpu_name: Optional[str] = "" # Type the GPU allocated.
|
162
185
|
|
163
186
|
|
164
187
|
class CreateArtifactFromTemplateRequest(BaseModel):
|
@@ -290,7 +313,7 @@ class Task(BaseModel):
|
|
290
313
|
config: Optional[TaskConfig] = None # Configuration data for the task.
|
291
314
|
endpoint_info: Optional[EndpointInfo] = None # Additional information about the task endpoint.
|
292
315
|
cluster_endpoints: Optional[List[EndpointInfo]] = None # Endpoints for the task cluster.
|
293
|
-
task_status: Optional[
|
316
|
+
task_status: Optional[TaskStatus] = "" # Status of the task.
|
294
317
|
readiness_status: Optional[str] = "" # Readiness status of the task.
|
295
318
|
user_preference: Optional[UserPreference] = None # User preference for the task.
|
296
319
|
|
@@ -307,10 +330,35 @@ class CreateTaskResponse(BaseModel):
|
|
307
330
|
upload_link: str # URL to upload the task data.
|
308
331
|
|
309
332
|
|
310
|
-
class
|
333
|
+
class AuthTokenRequest(BaseModel):
|
334
|
+
"""
|
335
|
+
Request object for user login.
|
336
|
+
"""
|
337
|
+
email: str # User email.
|
338
|
+
password: str # User password.
|
339
|
+
|
340
|
+
|
341
|
+
class AuthTokenResponse(BaseModel):
|
311
342
|
"""
|
312
343
|
Response object for user login.
|
313
344
|
"""
|
345
|
+
authToken: str # Access token for the user session.
|
346
|
+
is2FARequired: bool # Indicates if 2FA is required for the user.
|
347
|
+
|
348
|
+
|
349
|
+
class CreateSessionRequest(BaseModel):
|
350
|
+
"""
|
351
|
+
Request object for creating a user session.
|
352
|
+
"""
|
353
|
+
type: str # Type of the session (e.g., native).
|
354
|
+
authToken: str # Access token for the user session.
|
355
|
+
otpCode: Optional[str] # 2FA code for the user session.
|
356
|
+
|
357
|
+
|
358
|
+
class CreateSessionResponse(BaseModel):
|
359
|
+
"""
|
360
|
+
Response object for creating a user session.
|
361
|
+
"""
|
314
362
|
accessToken: str # Access token for the user session.
|
315
363
|
refreshToken: str # Refresh token for the user session.
|
316
364
|
|
@@ -348,3 +396,73 @@ class LoginRequest(BaseModel):
|
|
348
396
|
"""
|
349
397
|
email: str # User email.
|
350
398
|
password: str # User password.
|
399
|
+
|
400
|
+
|
401
|
+
class User(BaseModel):
|
402
|
+
"""
|
403
|
+
User information.
|
404
|
+
"""
|
405
|
+
id: Optional[str] = "" # User ID.
|
406
|
+
email: Optional[str] = "" # User email.
|
407
|
+
firstName: Optional[str] = "" # User first name.
|
408
|
+
lastName: Optional[str] = "" # User last name.
|
409
|
+
|
410
|
+
|
411
|
+
class Organization(BaseModel):
|
412
|
+
"""
|
413
|
+
Organization information.
|
414
|
+
"""
|
415
|
+
id: Optional[str] = "" # Organization ID.
|
416
|
+
role: Optional[str] = "" # Organization role.
|
417
|
+
|
418
|
+
|
419
|
+
class ProfileResponse(BaseModel):
|
420
|
+
"""
|
421
|
+
Response object for user profile.
|
422
|
+
"""
|
423
|
+
user: User # User information.
|
424
|
+
organization: Organization # Organization information.
|
425
|
+
|
426
|
+
|
427
|
+
class CreateAPIKeyRequest(BaseModel):
|
428
|
+
"""
|
429
|
+
Request object for creating an API key.
|
430
|
+
"""
|
431
|
+
name: str # Name of the API key.
|
432
|
+
type: Optional[str] = "" # Type of the API key.
|
433
|
+
expiresAt: Optional[int] = 0 # Expiration timestamp for the API key.
|
434
|
+
|
435
|
+
|
436
|
+
class CreateAPIKeyResponse(BaseModel):
|
437
|
+
"""
|
438
|
+
Response object for creating an API key.
|
439
|
+
"""
|
440
|
+
key: str # The created API key.
|
441
|
+
|
442
|
+
|
443
|
+
class APIKey(BaseModel):
|
444
|
+
"""
|
445
|
+
API key information.
|
446
|
+
"""
|
447
|
+
id: Optional[str] = "" # API key ID.
|
448
|
+
name: Optional[str] = "" # API key name.
|
449
|
+
type: Optional[str] = "" # API key type.
|
450
|
+
partialKey: Optional[str] = "" # Partial key for the API key.
|
451
|
+
expiresAt: Optional[int] = 0 # Expiration timestamp for the API key.
|
452
|
+
createdAt: Optional[int] = 0 # Creation timestamp for the API key.
|
453
|
+
owner: Optional[User] = None # Owner of the API key.
|
454
|
+
|
455
|
+
|
456
|
+
class GetAPIKeysResponse(BaseModel):
|
457
|
+
"""
|
458
|
+
Response object for getting a list of API keys.
|
459
|
+
"""
|
460
|
+
keys: list[APIKey] # List of API keys.
|
461
|
+
|
462
|
+
|
463
|
+
class GetSelfAPIKeyResponse(BaseModel):
|
464
|
+
"""
|
465
|
+
Response object for getting the API key of the current user.
|
466
|
+
"""
|
467
|
+
key: APIKey # The API key of the current user.
|
468
|
+
organization: Optional[Organization] = None # Organization information.
|
gmicloud/client.py
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
|
+
import logging
|
3
4
|
|
4
5
|
from typing import Optional
|
5
6
|
|
6
7
|
from ._internal._client._iam_client import IAMClient
|
7
8
|
from ._internal._manager._artifact_manager import ArtifactManager
|
8
9
|
from ._internal._manager._task_manager import TaskManager
|
10
|
+
from ._internal._manager._iam_manager import IAMManager
|
9
11
|
from ._internal._enums import BuildStatus
|
10
12
|
from ._internal._models import Task, TaskConfig, RayTaskConfig, TaskScheduling, ReplicaResource
|
11
13
|
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
12
16
|
|
13
17
|
class Client:
|
14
18
|
def __init__(self, client_id: Optional[str] = "", email: Optional[str] = "", password: Optional[str] = ""):
|
@@ -32,6 +36,7 @@ class Client:
|
|
32
36
|
# Managers are lazily initialized through private attributes
|
33
37
|
self._artifact_manager = None
|
34
38
|
self._task_manager = None
|
39
|
+
self._iam_manager = None
|
35
40
|
|
36
41
|
def create_task_from_artifact_template(self, artifact_template_id: str, task_scheduling: TaskScheduling) -> Task:
|
37
42
|
"""
|
@@ -50,24 +55,28 @@ class Client:
|
|
50
55
|
artifact_manager = self.artifact_manager
|
51
56
|
task_manager = self.task_manager
|
52
57
|
|
53
|
-
templates = artifact_manager.
|
58
|
+
templates = artifact_manager.get_public_templates()
|
54
59
|
template = None
|
55
60
|
for v in templates:
|
56
|
-
if v.
|
61
|
+
if v.template_id == artifact_template_id:
|
57
62
|
template = v
|
58
63
|
if not template:
|
59
64
|
raise ValueError(f"Template with ID {artifact_template_id} not found.")
|
60
|
-
if not template.
|
65
|
+
if not template.template_data:
|
66
|
+
raise ValueError("Template does not contain template data.")
|
67
|
+
if not template.template_data.ray:
|
61
68
|
raise ValueError("Template does not contain Ray configuration.")
|
62
|
-
if not template.resources:
|
69
|
+
if not template.template_data.resources:
|
63
70
|
raise ValueError("Template does not contain resource configuration.")
|
64
71
|
|
65
72
|
artifact_id = artifact_manager.create_artifact_from_template(artifact_template_id)
|
73
|
+
|
74
|
+
logger.info(f"Successfully created artifact from template, artifact_id: {artifact_id}")
|
66
75
|
# Wait for the artifact to be ready
|
67
76
|
while True:
|
68
77
|
try:
|
69
78
|
artifact = artifact_manager.get_artifact(artifact_id)
|
70
|
-
|
79
|
+
logger.info(f"Successfully got artifact info, artifact status: {artifact.build_status}")
|
71
80
|
# Wait until the artifact is ready
|
72
81
|
if artifact.build_status == BuildStatus.SUCCESS:
|
73
82
|
break
|
@@ -94,8 +103,10 @@ class Client:
|
|
94
103
|
),
|
95
104
|
))
|
96
105
|
|
106
|
+
logger.info(f"Successfully created task, task_id: {task.task_id}")
|
97
107
|
# Start the task
|
98
108
|
task_manager.start_task(task.task_id)
|
109
|
+
logger.info(f"Successfully started task, task_id: {task.task_id}")
|
99
110
|
except Exception as e:
|
100
111
|
raise e
|
101
112
|
|
@@ -120,3 +131,13 @@ class Client:
|
|
120
131
|
if self._task_manager is None:
|
121
132
|
self._task_manager = TaskManager(self.iam_client)
|
122
133
|
return self._task_manager
|
134
|
+
|
135
|
+
@property
|
136
|
+
def iam_manager(self):
|
137
|
+
"""
|
138
|
+
Lazy initialization for IAMManager.
|
139
|
+
Ensures the Client instance controls its lifecycle.
|
140
|
+
"""
|
141
|
+
if self._iam_manager is None:
|
142
|
+
self._iam_manager = IAMManager(self.iam_client)
|
143
|
+
return self._iam_manager
|
gmicloud/tests/test_artifacts.py
CHANGED
@@ -251,24 +251,23 @@ class TestArtifactManager(unittest.TestCase):
|
|
251
251
|
self.artifact_manager.delete_bigfile("nonexistent_id", "file.txt")
|
252
252
|
self.assertTrue("Artifact not found" in str(context.exception))
|
253
253
|
|
254
|
-
@patch('gmicloud._internal._client._artifact_client.ArtifactClient.
|
255
|
-
def test_get_artifact_templates_returns_templates(self,
|
256
|
-
|
257
|
-
|
258
|
-
templates = self.artifact_manager.get_artifact_templates()
|
254
|
+
@patch('gmicloud._internal._client._artifact_client.ArtifactClient.get_public_templates')
|
255
|
+
def test_get_artifact_templates_returns_templates(self, mock_get_public_templates):
|
256
|
+
mock_get_public_templates.return_value = [ArtifactTemplate(template_id="1", template_data=TemplateData(name="Template1"))]
|
257
|
+
templates = self.artifact_manager.get_public_templates()
|
259
258
|
self.assertEqual(len(templates), 1)
|
260
|
-
self.assertEqual(templates[0].
|
261
|
-
self.assertEqual(templates[0].
|
259
|
+
self.assertEqual(templates[0].template_id, "1")
|
260
|
+
self.assertEqual(templates[0].template_data.name, "Template1")
|
262
261
|
|
263
|
-
@patch('gmicloud._internal._client._artifact_client.ArtifactClient.
|
264
|
-
def test_get_artifact_templates_returns_empty_list_when_no_templates(self,
|
265
|
-
|
266
|
-
templates = self.artifact_manager.
|
262
|
+
@patch('gmicloud._internal._client._artifact_client.ArtifactClient.get_public_templates')
|
263
|
+
def test_get_artifact_templates_returns_empty_list_when_no_templates(self, mock_get_public_templates):
|
264
|
+
mock_get_public_templates.return_value = []
|
265
|
+
templates = self.artifact_manager.get_public_templates()
|
267
266
|
self.assertEqual(len(templates), 0)
|
268
267
|
|
269
|
-
@patch('gmicloud._internal._client._artifact_client.ArtifactClient.
|
270
|
-
def test_get_artifact_templates_raises_error_on_failure(self,
|
271
|
-
|
268
|
+
@patch('gmicloud._internal._client._artifact_client.ArtifactClient.get_public_templates')
|
269
|
+
def test_get_artifact_templates_raises_error_on_failure(self, mock_get_public_templates):
|
270
|
+
mock_get_public_templates.side_effect = Exception("Failed to fetch templates")
|
272
271
|
with self.assertRaises(Exception) as context:
|
273
|
-
self.artifact_manager.
|
272
|
+
self.artifact_manager.get_public_templates()
|
274
273
|
self.assertTrue("Failed to fetch templates" in str(context.exception))
|
gmicloud/tests/test_tasks.py
CHANGED