lightning-sdk 0.2.13__py3-none-any.whl → 0.2.15__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.
- lightning_sdk/__init__.py +1 -1
- lightning_sdk/api/base_studio_api.py +73 -0
- lightning_sdk/api/license_api.py +48 -0
- lightning_sdk/api/llm_api.py +61 -8
- lightning_sdk/api/studio_api.py +47 -1
- lightning_sdk/base_studio.py +70 -0
- lightning_sdk/cli/delete.py +6 -8
- lightning_sdk/cli/download.py +25 -0
- lightning_sdk/cli/serve.py +82 -30
- lightning_sdk/cli/teamspace_menu.py +9 -1
- lightning_sdk/cli/upload.py +0 -1
- lightning_sdk/lightning_cloud/openapi/__init__.py +11 -0
- lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
- lightning_sdk/lightning_cloud/openapi/api/billing_service_api.py +9 -1
- lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +121 -0
- lightning_sdk/lightning_cloud/openapi/api/file_system_service_api.py +178 -0
- lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +243 -2
- lightning_sdk/lightning_cloud/openapi/api/product_license_service_api.py +525 -0
- lightning_sdk/lightning_cloud/openapi/configuration.py +1 -1
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +10 -0
- lightning_sdk/lightning_cloud/openapi/models/assistant_id_conversations_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/endpoints_id_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/model_id_versions_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/pipelines_id_body.py +6 -6
- lightning_sdk/lightning_cloud/openapi/models/project_id_storage_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/storage_complete_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/update.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/uploads_upload_id_body1.py +55 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_aws_direct_v1.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_provider.py +3 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_config.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_type.py +104 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloudflare_v1.py +66 -66
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_upload.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_complete_upload.py +55 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_conversation.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_create_cloud_space_environment_template_request.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_api.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_state.py +4 -4
- lightning_sdk/lightning_cloud/openapi/models/v1_endpoint.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_external_search_user.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_ge_list_deployment_routing_telemetry_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_job_stats_response.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_get_project_balance_response.py +1 -27
- lightning_sdk/lightning_cloud/openapi/models/v1_get_user_response.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_job_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_product_licenses_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_managed_model.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +17 -17
- lightning_sdk/lightning_cloud/openapi/models/v1_modify_filesystem_volume_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_pipeline.py +6 -6
- lightning_sdk/lightning_cloud/openapi/models/v1_pipeline_state.py +111 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_presigned_url.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_product_license.py +409 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_product_license_check_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +17 -17
- lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_r2_data_connection.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_secret_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_trigger_filesystem_upgrade_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_update_user_request.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_upload_project_artifact_response.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_usage_report.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +295 -113
- lightning_sdk/lightning_cloud/rest_client.py +4 -0
- lightning_sdk/llm/llm.py +120 -30
- lightning_sdk/services/__init__.py +1 -1
- lightning_sdk/services/license.py +236 -0
- lightning_sdk/studio.py +30 -0
- {lightning_sdk-0.2.13.dist-info → lightning_sdk-0.2.15.dist-info}/METADATA +1 -1
- {lightning_sdk-0.2.13.dist-info → lightning_sdk-0.2.15.dist-info}/RECORD +83 -68
- /lightning_sdk/services/{finetune/__init__.py → finetune_llm.py} +0 -0
- {lightning_sdk-0.2.13.dist-info → lightning_sdk-0.2.15.dist-info}/LICENSE +0 -0
- {lightning_sdk-0.2.13.dist-info → lightning_sdk-0.2.15.dist-info}/WHEEL +0 -0
- {lightning_sdk-0.2.13.dist-info → lightning_sdk-0.2.15.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-0.2.13.dist-info → lightning_sdk-0.2.15.dist-info}/top_level.txt +0 -0
lightning_sdk/__init__.py
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from typing import Any, List, Optional
|
|
2
|
+
|
|
3
|
+
from lightning_sdk.lightning_cloud.openapi.models.update import Update as BaseStudioUpdateBody
|
|
4
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_cloud_space_environment_template import (
|
|
5
|
+
V1CloudSpaceEnvironmentTemplate,
|
|
6
|
+
)
|
|
7
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_cloud_space_environment_type import V1CloudSpaceEnvironmentType
|
|
8
|
+
from lightning_sdk.lightning_cloud.rest_client import LightningClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseStudioApi:
|
|
12
|
+
def __init__(self) -> None:
|
|
13
|
+
self._client = LightningClient(retry=False, max_tries=0)
|
|
14
|
+
|
|
15
|
+
def get_base_studio(self, base_studio_id: str, org_id: str) -> V1CloudSpaceEnvironmentTemplate:
|
|
16
|
+
"""Retrieve the base studio by its ID."""
|
|
17
|
+
try:
|
|
18
|
+
return self._client.cloud_space_environment_template_service_get_cloud_space_environment_template(
|
|
19
|
+
base_studio_id, org_id
|
|
20
|
+
)
|
|
21
|
+
except ValueError as e:
|
|
22
|
+
raise ValueError(f"Base studio {base_studio_id} does not exist") from e
|
|
23
|
+
|
|
24
|
+
def update_base_studio(
|
|
25
|
+
self,
|
|
26
|
+
base_studio_id: str,
|
|
27
|
+
org_id: str,
|
|
28
|
+
name: Optional[str] = None,
|
|
29
|
+
allowed_machines: Optional[List[str]] = None,
|
|
30
|
+
default_machine: Optional[str] = None,
|
|
31
|
+
disabled: Optional[bool] = None,
|
|
32
|
+
environment_type: Optional[V1CloudSpaceEnvironmentType] = None,
|
|
33
|
+
machine_image_version: Optional[str] = None,
|
|
34
|
+
setup_script_text: Optional[str] = None,
|
|
35
|
+
) -> V1CloudSpaceEnvironmentTemplate:
|
|
36
|
+
base_studio = self.get_base_studio(base_studio_id, org_id)
|
|
37
|
+
|
|
38
|
+
# Get the current configuration for the base studio
|
|
39
|
+
update_body = BaseStudioUpdateBody(
|
|
40
|
+
org_id=base_studio.org_id,
|
|
41
|
+
name=base_studio.name,
|
|
42
|
+
allowed_machines=base_studio.config.allowed_machines,
|
|
43
|
+
default_machine=base_studio.config.default_machine,
|
|
44
|
+
environment_type=base_studio.config.environment_type,
|
|
45
|
+
machine_image_version=base_studio.config.machine_image_version,
|
|
46
|
+
setup_script_text=base_studio.config.setup_script_text,
|
|
47
|
+
disabled=base_studio.disabled,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Apply changes only if the new value is not None
|
|
51
|
+
apply_change(update_body, "name", name)
|
|
52
|
+
apply_change(update_body, "allowed_machines", allowed_machines)
|
|
53
|
+
apply_change(update_body, "default_machine", default_machine)
|
|
54
|
+
apply_change(update_body, "environment_type", environment_type)
|
|
55
|
+
apply_change(update_body, "machine_image_version", machine_image_version)
|
|
56
|
+
apply_change(update_body, "setup_script_text", setup_script_text)
|
|
57
|
+
apply_change(update_body, "disabled", disabled)
|
|
58
|
+
|
|
59
|
+
return self._client.cloud_space_environment_template_service_update_cloud_space_environment_template(
|
|
60
|
+
id=base_studio_id,
|
|
61
|
+
body=update_body,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def apply_change(spec: Any, key: str, value: Any) -> bool:
|
|
66
|
+
if value is None:
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
if getattr(spec, key) != value:
|
|
70
|
+
setattr(spec, key, value)
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
return False
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from lightning_sdk.lightning_cloud.rest_client import LightningClient
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LicenseApi:
|
|
7
|
+
def __init__(self) -> None:
|
|
8
|
+
self._client = LightningClient(retry=False, max_tries=0)
|
|
9
|
+
|
|
10
|
+
def valid_license(
|
|
11
|
+
self,
|
|
12
|
+
license_key: str,
|
|
13
|
+
product_name: str,
|
|
14
|
+
product_version: Optional[str] = None,
|
|
15
|
+
product_type: str = "package",
|
|
16
|
+
) -> bool:
|
|
17
|
+
"""Check if the license key is valid.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
license_key: The license key to check.
|
|
21
|
+
product_name: The name of the product.
|
|
22
|
+
product_version: The version of the product.
|
|
23
|
+
product_type: The type of the product. Default is "package".
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
True if the license key is valid, False otherwise.
|
|
27
|
+
"""
|
|
28
|
+
response, code, _ = self._client.product_license_service_validate_product_license_with_http_info(
|
|
29
|
+
license_key=license_key,
|
|
30
|
+
product_name=product_name,
|
|
31
|
+
product_version=product_version,
|
|
32
|
+
product_type=product_type,
|
|
33
|
+
)
|
|
34
|
+
if code != 200:
|
|
35
|
+
raise ConnectionError(f"Failed to validate license key: {code} - {response}")
|
|
36
|
+
return response.valid
|
|
37
|
+
|
|
38
|
+
def list_user_licenses(self, user_id: str) -> list:
|
|
39
|
+
"""List all licenses for a user.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
user_id: The ID of the user.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
A list of licenses for the user.
|
|
46
|
+
"""
|
|
47
|
+
response = self._client.product_license_service_list_user_licenses(user_id=user_id)
|
|
48
|
+
return response.licenses
|
lightning_sdk/api/llm_api.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import json
|
|
2
|
+
from typing import Generator, List, Optional, Union
|
|
3
|
+
|
|
4
|
+
from pip._vendor.urllib3 import HTTPResponse
|
|
2
5
|
|
|
3
6
|
from lightning_sdk.lightning_cloud.openapi.models.v1_conversation_response_chunk import V1ConversationResponseChunk
|
|
7
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_response_choice import V1ResponseChoice
|
|
8
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_response_choice_delta import V1ResponseChoiceDelta
|
|
4
9
|
from lightning_sdk.lightning_cloud.rest_client import LightningClient
|
|
5
10
|
|
|
6
11
|
|
|
@@ -20,14 +25,47 @@ class LLMApi:
|
|
|
20
25
|
result = self._client.assistants_service_list_assistants(user_id=user_id)
|
|
21
26
|
return result.assistants
|
|
22
27
|
|
|
28
|
+
def _stream_chat_response(self, result: HTTPResponse) -> Generator[V1ConversationResponseChunk, None, None]:
|
|
29
|
+
for line in result.stream():
|
|
30
|
+
decoded_lines = line.decode("utf-8").strip()
|
|
31
|
+
for decoded_line in decoded_lines.splitlines():
|
|
32
|
+
try:
|
|
33
|
+
payload = json.loads(decoded_line)
|
|
34
|
+
result_data = payload.get("result", {})
|
|
35
|
+
|
|
36
|
+
choices = []
|
|
37
|
+
for choice in result_data.get("choices", []):
|
|
38
|
+
delta = choice.get("delta", {})
|
|
39
|
+
choices.append(
|
|
40
|
+
V1ResponseChoice(
|
|
41
|
+
delta=V1ResponseChoiceDelta(**delta),
|
|
42
|
+
finish_reason=choice.get("finishReason"),
|
|
43
|
+
index=choice.get("index"),
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
yield V1ConversationResponseChunk(
|
|
48
|
+
choices=choices,
|
|
49
|
+
conversation_id=result_data.get("conversationId"),
|
|
50
|
+
executable=result_data.get("executable"),
|
|
51
|
+
id=result_data.get("id"),
|
|
52
|
+
throughput=result_data.get("throughput"),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
except json.JSONDecodeError:
|
|
56
|
+
print("Error decoding JSON:", decoded_line)
|
|
57
|
+
|
|
23
58
|
def start_conversation(
|
|
24
59
|
self,
|
|
25
60
|
prompt: str,
|
|
26
61
|
system_prompt: Optional[str],
|
|
27
|
-
max_completion_tokens:
|
|
62
|
+
max_completion_tokens: int,
|
|
28
63
|
assistant_id: str,
|
|
29
|
-
conversation_id: Optional[str],
|
|
30
|
-
|
|
64
|
+
conversation_id: Optional[str] = None,
|
|
65
|
+
billing_project_id: Optional[str] = None,
|
|
66
|
+
name: Optional[str] = None,
|
|
67
|
+
stream: bool = False,
|
|
68
|
+
) -> Union[V1ConversationResponseChunk, Generator[V1ConversationResponseChunk, None, None]]:
|
|
31
69
|
body = {
|
|
32
70
|
"message": {
|
|
33
71
|
"author": {"role": "user"},
|
|
@@ -39,8 +77,23 @@ class LLMApi:
|
|
|
39
77
|
],
|
|
40
78
|
},
|
|
41
79
|
"max_completion_tokens": max_completion_tokens,
|
|
80
|
+
"conversation_id": conversation_id,
|
|
81
|
+
"billing_project_id": billing_project_id,
|
|
82
|
+
"name": name,
|
|
83
|
+
"stream": stream,
|
|
42
84
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return
|
|
85
|
+
result = self._client.assistants_service_start_conversation(body, assistant_id, _preload_content=not stream)
|
|
86
|
+
if not stream:
|
|
87
|
+
return result.result
|
|
88
|
+
return self._stream_chat_response(result)
|
|
89
|
+
|
|
90
|
+
def list_conversations(self, assistant_id: str) -> List[str]:
|
|
91
|
+
result = self._client.assistants_service_list_conversations(assistant_id)
|
|
92
|
+
return result.conversations
|
|
93
|
+
|
|
94
|
+
def get_conversation(self, assistant_id: str, conversation_id: str) -> V1ConversationResponseChunk:
|
|
95
|
+
result = self._client.assistants_service_get_conversation(assistant_id, conversation_id)
|
|
96
|
+
return result.messages
|
|
97
|
+
|
|
98
|
+
def reset_conversation(self, assistant_id: str, conversation_id: str) -> None:
|
|
99
|
+
self._client.assistants_service_delete_conversation(assistant_id, conversation_id)
|
lightning_sdk/api/studio_api.py
CHANGED
|
@@ -5,7 +5,7 @@ import time
|
|
|
5
5
|
import warnings
|
|
6
6
|
import zipfile
|
|
7
7
|
from threading import Event, Thread
|
|
8
|
-
from typing import Any, Dict, Mapping, Optional, Tuple, Union
|
|
8
|
+
from typing import Any, Dict, Generator, Mapping, Optional, Tuple, Union
|
|
9
9
|
|
|
10
10
|
import backoff
|
|
11
11
|
import requests
|
|
@@ -285,6 +285,52 @@ class StudioApi:
|
|
|
285
285
|
for response in responses:
|
|
286
286
|
yield response.result
|
|
287
287
|
|
|
288
|
+
def run_studio_commands_and_yield(
|
|
289
|
+
self, studio_id: str, teamspace_id: str, *commands: str, timeout: float, check_interval: float
|
|
290
|
+
) -> Generator[Tuple[str, int], None, None]:
|
|
291
|
+
"""Run given commands in a given Studio and yield the output and exit code for the given timeout.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
timeout: wait for this many seconds for the command to finish.
|
|
295
|
+
"""
|
|
296
|
+
response_submit = self._client.cloud_space_service_execute_command_in_cloud_space(
|
|
297
|
+
IdExecuteBody1("; ".join(commands), detached=True),
|
|
298
|
+
project_id=teamspace_id,
|
|
299
|
+
id=studio_id,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
if not response_submit:
|
|
303
|
+
raise RuntimeError("Unable to submit command")
|
|
304
|
+
|
|
305
|
+
if response_submit.session_name == "":
|
|
306
|
+
raise RuntimeError("The session name should be defined.")
|
|
307
|
+
|
|
308
|
+
start_time = time.time()
|
|
309
|
+
exit_code = None
|
|
310
|
+
while True:
|
|
311
|
+
for resp in self._get_detached_command_status(
|
|
312
|
+
studio_id=studio_id,
|
|
313
|
+
teamspace_id=teamspace_id,
|
|
314
|
+
session_id=response_submit.session_name,
|
|
315
|
+
):
|
|
316
|
+
if time.time() - start_time >= timeout:
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
if resp.exit_code == -1:
|
|
320
|
+
break
|
|
321
|
+
|
|
322
|
+
if exit_code is None:
|
|
323
|
+
exit_code = resp.exit_code
|
|
324
|
+
|
|
325
|
+
elif exit_code != resp.exit_code:
|
|
326
|
+
raise RuntimeError("Cannot determine exit code")
|
|
327
|
+
|
|
328
|
+
if resp.exit_code is not None and resp.exit_code != 0:
|
|
329
|
+
raise RuntimeError(f"Command failed with exit code {resp.exit_code}. Output: {resp.output}")
|
|
330
|
+
|
|
331
|
+
yield resp.output, exit_code
|
|
332
|
+
time.sleep(check_interval)
|
|
333
|
+
|
|
288
334
|
def run_studio_commands(self, studio_id: str, teamspace_id: str, *commands: str) -> Tuple[str, int]:
|
|
289
335
|
"""Run given commands in a given Studio."""
|
|
290
336
|
response_submit = self._client.cloud_space_service_execute_command_in_cloud_space(
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import List, Optional, Union
|
|
2
|
+
|
|
3
|
+
from lightning_sdk.api.base_studio_api import BaseStudioApi
|
|
4
|
+
from lightning_sdk.api.user_api import UserApi
|
|
5
|
+
from lightning_sdk.lightning_cloud import login
|
|
6
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_cloud_space_environment_template import (
|
|
7
|
+
V1CloudSpaceEnvironmentTemplate,
|
|
8
|
+
)
|
|
9
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_cloud_space_environment_type import V1CloudSpaceEnvironmentType
|
|
10
|
+
from lightning_sdk.organization import Organization
|
|
11
|
+
from lightning_sdk.user import User
|
|
12
|
+
from lightning_sdk.utils.resolve import _resolve_org, _resolve_user
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseStudio:
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
name: Optional[str] = None,
|
|
19
|
+
org: Optional[Union[str, Organization]] = None,
|
|
20
|
+
user: Optional[Union[str, User]] = None,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Initializes the BaseStudio instance with organization and user information.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
org (Optional[Union[str, Organization]]): The organization for the base studio. If not provided,
|
|
26
|
+
it will be resolved through the authentication process.
|
|
27
|
+
user (Optional[Union[str, User]]): The user for the base studio. If not provided, it will be resolved
|
|
28
|
+
through the authentication process.
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
ConnectionError: If there is an issue with the authentication process.
|
|
32
|
+
"""
|
|
33
|
+
self._auth = login.Auth()
|
|
34
|
+
self._user = None
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
self._auth.authenticate()
|
|
38
|
+
if user is None:
|
|
39
|
+
self._user = User(name=UserApi()._get_user_by_id(self._auth.user_id).username)
|
|
40
|
+
except ConnectionError as e:
|
|
41
|
+
raise e
|
|
42
|
+
|
|
43
|
+
self._user = _resolve_user(self._user or user)
|
|
44
|
+
self._org = _resolve_org(org)
|
|
45
|
+
|
|
46
|
+
self._base_studio_api = BaseStudioApi()
|
|
47
|
+
|
|
48
|
+
self._base_studio = self._base_studio_api.get_base_studio(name, self._org.id)
|
|
49
|
+
|
|
50
|
+
def update(
|
|
51
|
+
self,
|
|
52
|
+
name: Optional[str] = None,
|
|
53
|
+
allowed_machines: Optional[List[str]] = None,
|
|
54
|
+
default_machine: Optional[str] = None,
|
|
55
|
+
disabled: Optional[bool] = None,
|
|
56
|
+
environment_type: Optional[V1CloudSpaceEnvironmentType] = None,
|
|
57
|
+
machine_image_version: Optional[str] = None,
|
|
58
|
+
setup_script_text: Optional[str] = None,
|
|
59
|
+
) -> V1CloudSpaceEnvironmentTemplate:
|
|
60
|
+
self._base_studio = self._base_studio_api.update_base_studio(
|
|
61
|
+
self._base_studio.id,
|
|
62
|
+
self._org.id,
|
|
63
|
+
name=name,
|
|
64
|
+
allowed_machines=allowed_machines,
|
|
65
|
+
default_machine=default_machine,
|
|
66
|
+
environment_type=environment_type,
|
|
67
|
+
machine_image_version=machine_image_version,
|
|
68
|
+
setup_script_text=setup_script_text,
|
|
69
|
+
disabled=disabled,
|
|
70
|
+
)
|
lightning_sdk/cli/delete.py
CHANGED
|
@@ -17,7 +17,7 @@ def delete() -> None:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@delete.command(name="container")
|
|
20
|
-
@click.argument("
|
|
20
|
+
@click.argument("name")
|
|
21
21
|
@click.option(
|
|
22
22
|
"--teamspace",
|
|
23
23
|
default=None,
|
|
@@ -27,18 +27,16 @@ def delete() -> None:
|
|
|
27
27
|
"If not provided, can be selected in an interactive menu."
|
|
28
28
|
),
|
|
29
29
|
)
|
|
30
|
-
def
|
|
31
|
-
"""Delete the docker container
|
|
30
|
+
def container(name: str, teamspace: Optional[str] = None) -> None:
|
|
31
|
+
"""Delete the docker container NAME."""
|
|
32
32
|
api = LitContainer()
|
|
33
33
|
menu = _TeamspacesMenu()
|
|
34
34
|
resolved_teamspace = menu._resolve_teamspace(teamspace=teamspace)
|
|
35
35
|
try:
|
|
36
|
-
api.delete_container(
|
|
37
|
-
Console().print(f"Container {
|
|
36
|
+
api.delete_container(name, resolved_teamspace.name, resolved_teamspace.owner.name)
|
|
37
|
+
Console().print(f"Container {name} deleted successfully.")
|
|
38
38
|
except Exception as e:
|
|
39
|
-
raise StudioCliError(
|
|
40
|
-
f"Could not delete container {container} from project {resolved_teamspace.name}: {e}"
|
|
41
|
-
) from None
|
|
39
|
+
raise StudioCliError(f"Could not delete container {name} from project {resolved_teamspace.name}: {e}") from None
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
@delete.command(name="job")
|
lightning_sdk/cli/download.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import os
|
|
2
3
|
import re
|
|
3
4
|
from pathlib import Path
|
|
@@ -6,6 +7,7 @@ from typing import Optional
|
|
|
6
7
|
import click
|
|
7
8
|
from rich.console import Console
|
|
8
9
|
|
|
10
|
+
from lightning_sdk.api.license_api import LicenseApi
|
|
9
11
|
from lightning_sdk.api.lit_container_api import LitContainerApi
|
|
10
12
|
from lightning_sdk.cli.exceptions import StudioCliError
|
|
11
13
|
from lightning_sdk.cli.studios_menu import _StudiosMenu
|
|
@@ -208,3 +210,26 @@ def _resolve_studio(studio: Optional[str]) -> Studio:
|
|
|
208
210
|
|
|
209
211
|
with skip_studio_init():
|
|
210
212
|
return Studio(**selected_studio)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@download.command(name="licenses")
|
|
216
|
+
def licenses() -> None:
|
|
217
|
+
"""Download licenses for all products/packages.
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
lightning download licenses
|
|
221
|
+
|
|
222
|
+
"""
|
|
223
|
+
user = _get_authed_user()
|
|
224
|
+
api = LicenseApi()
|
|
225
|
+
licenses = api.list_user_licenses(user.id)
|
|
226
|
+
|
|
227
|
+
user_home = Path.home()
|
|
228
|
+
lit_dir = user_home / ".lightning"
|
|
229
|
+
lit_dir.mkdir(parents=True, exist_ok=True)
|
|
230
|
+
licenses_file = lit_dir / "licenses.json"
|
|
231
|
+
|
|
232
|
+
licenses_short = {ll.product_name: ll.license_key for ll in licenses if ll.is_valid}
|
|
233
|
+
with licenses_file.open("w") as fp:
|
|
234
|
+
json.dump(licenses_short, fp, indent=4)
|
|
235
|
+
Console().print(f"Licenses downloaded to {licenses_file}", style="green")
|