lightning-sdk 0.1.37__py3-none-any.whl → 0.1.39__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/ai_hub.py +21 -23
- lightning_sdk/api/ai_hub_api.py +29 -4
- lightning_sdk/api/deployment_api.py +0 -2
- lightning_sdk/api/job_api.py +10 -2
- lightning_sdk/api/teamspace_api.py +22 -16
- lightning_sdk/api/utils.py +25 -3
- lightning_sdk/cli/ai_hub.py +1 -1
- lightning_sdk/cli/download.py +3 -5
- lightning_sdk/cli/run.py +24 -0
- lightning_sdk/cli/upload.py +3 -10
- lightning_sdk/job/base.py +35 -0
- lightning_sdk/job/job.py +18 -1
- lightning_sdk/job/v1.py +10 -1
- lightning_sdk/job/v2.py +16 -0
- lightning_sdk/lightning_cloud/openapi/__init__.py +13 -2
- lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +5 -1
- lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +6 -1
- lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +680 -62
- lightning_sdk/lightning_cloud/openapi/api/models_store_api.py +118 -1
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +13 -2
- lightning_sdk/lightning_cloud/openapi/models/create.py +6 -32
- lightning_sdk/lightning_cloud/openapi/models/deploymenttemplates_id_body.py +32 -6
- lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/id_start_body.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/multimachinejobs_id_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/project_id_agents_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/project_id_cloudspaces_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/project_id_multimachinejobs_body.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/update.py +6 -32
- lightning_sdk/lightning_cloud/openapi/models/v1_api_pricing_spec.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_create_deployment_template_request.py +32 -6
- lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +6 -32
- lightning_sdk/lightning_cloud/openapi/models/v1_data_path.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_multi_machine_job_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_metrics.py +43 -17
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_performance.py +305 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template.py +32 -6
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template_parameter.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template_parameter_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template_summary.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/{v1_efs_data_connection.py → v1_efs_config.py} +22 -22
- lightning_sdk/lightning_cloud/openapi/models/v1_get_model_files_response.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +53 -53
- lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py +125 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_multi_machine_jobs_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_machines_selector.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_message.py +6 -6
- lightning_sdk/lightning_cloud/openapi/models/v1_message_content.py +6 -6
- lightning_sdk/lightning_cloud/openapi/models/v1_message_content_type.py +103 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_metrics_stream.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job.py +409 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_state.py +106 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_status.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +2 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_system_info.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_user_requested_compute_config.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_validate_data_connection_response.py +6 -32
- lightning_sdk/lightning_cloud/openapi/models/validate.py +6 -32
- lightning_sdk/models.py +132 -0
- lightning_sdk/teamspace.py +8 -2
- {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/METADATA +1 -1
- {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/RECORD +70 -59
- lightning_sdk/cli/models.py +0 -68
- lightning_sdk/lightning_cloud/openapi/models/v1_efs_folder_data_connection.py +0 -201
- {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/LICENSE +0 -0
- {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/WHEEL +0 -0
- {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/top_level.txt +0 -0
|
@@ -44,8 +44,7 @@ class Validate(object):
|
|
|
44
44
|
'aws': 'V1AwsDataConnection',
|
|
45
45
|
'check_is_public': 'bool',
|
|
46
46
|
'cluster_ids': 'list[str]',
|
|
47
|
-
'efs': '
|
|
48
|
-
'efs_folder': 'V1EFSFolderDataConnection',
|
|
47
|
+
'efs': 'V1EfsConfig',
|
|
49
48
|
'gcp': 'V1GcpDataConnection',
|
|
50
49
|
'gcs_folder': 'V1GCSFolderDataConnection',
|
|
51
50
|
's3_folder': 'V1S3FolderDataConnection'
|
|
@@ -56,19 +55,17 @@ class Validate(object):
|
|
|
56
55
|
'check_is_public': 'checkIsPublic',
|
|
57
56
|
'cluster_ids': 'clusterIds',
|
|
58
57
|
'efs': 'efs',
|
|
59
|
-
'efs_folder': 'efsFolder',
|
|
60
58
|
'gcp': 'gcp',
|
|
61
59
|
'gcs_folder': 'gcsFolder',
|
|
62
60
|
's3_folder': 's3Folder'
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
def __init__(self, aws: 'V1AwsDataConnection' =None, check_is_public: 'bool' =None, cluster_ids: 'list[str]' =None, efs: '
|
|
63
|
+
def __init__(self, aws: 'V1AwsDataConnection' =None, check_is_public: 'bool' =None, cluster_ids: 'list[str]' =None, efs: 'V1EfsConfig' =None, gcp: 'V1GcpDataConnection' =None, gcs_folder: 'V1GCSFolderDataConnection' =None, s3_folder: 'V1S3FolderDataConnection' =None): # noqa: E501
|
|
66
64
|
"""Validate - a model defined in Swagger""" # noqa: E501
|
|
67
65
|
self._aws = None
|
|
68
66
|
self._check_is_public = None
|
|
69
67
|
self._cluster_ids = None
|
|
70
68
|
self._efs = None
|
|
71
|
-
self._efs_folder = None
|
|
72
69
|
self._gcp = None
|
|
73
70
|
self._gcs_folder = None
|
|
74
71
|
self._s3_folder = None
|
|
@@ -81,8 +78,6 @@ class Validate(object):
|
|
|
81
78
|
self.cluster_ids = cluster_ids
|
|
82
79
|
if efs is not None:
|
|
83
80
|
self.efs = efs
|
|
84
|
-
if efs_folder is not None:
|
|
85
|
-
self.efs_folder = efs_folder
|
|
86
81
|
if gcp is not None:
|
|
87
82
|
self.gcp = gcp
|
|
88
83
|
if gcs_folder is not None:
|
|
@@ -154,47 +149,26 @@ class Validate(object):
|
|
|
154
149
|
self._cluster_ids = cluster_ids
|
|
155
150
|
|
|
156
151
|
@property
|
|
157
|
-
def efs(self) -> '
|
|
152
|
+
def efs(self) -> 'V1EfsConfig':
|
|
158
153
|
"""Gets the efs of this Validate. # noqa: E501
|
|
159
154
|
|
|
160
155
|
|
|
161
156
|
:return: The efs of this Validate. # noqa: E501
|
|
162
|
-
:rtype:
|
|
157
|
+
:rtype: V1EfsConfig
|
|
163
158
|
"""
|
|
164
159
|
return self._efs
|
|
165
160
|
|
|
166
161
|
@efs.setter
|
|
167
|
-
def efs(self, efs: '
|
|
162
|
+
def efs(self, efs: 'V1EfsConfig'):
|
|
168
163
|
"""Sets the efs of this Validate.
|
|
169
164
|
|
|
170
165
|
|
|
171
166
|
:param efs: The efs of this Validate. # noqa: E501
|
|
172
|
-
:type:
|
|
167
|
+
:type: V1EfsConfig
|
|
173
168
|
"""
|
|
174
169
|
|
|
175
170
|
self._efs = efs
|
|
176
171
|
|
|
177
|
-
@property
|
|
178
|
-
def efs_folder(self) -> 'V1EFSFolderDataConnection':
|
|
179
|
-
"""Gets the efs_folder of this Validate. # noqa: E501
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
:return: The efs_folder of this Validate. # noqa: E501
|
|
183
|
-
:rtype: V1EFSFolderDataConnection
|
|
184
|
-
"""
|
|
185
|
-
return self._efs_folder
|
|
186
|
-
|
|
187
|
-
@efs_folder.setter
|
|
188
|
-
def efs_folder(self, efs_folder: 'V1EFSFolderDataConnection'):
|
|
189
|
-
"""Sets the efs_folder of this Validate.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
:param efs_folder: The efs_folder of this Validate. # noqa: E501
|
|
193
|
-
:type: V1EFSFolderDataConnection
|
|
194
|
-
"""
|
|
195
|
-
|
|
196
|
-
self._efs_folder = efs_folder
|
|
197
|
-
|
|
198
172
|
@property
|
|
199
173
|
def gcp(self) -> 'V1GcpDataConnection':
|
|
200
174
|
"""Gets the gcp of this Validate. # noqa: E501
|
lightning_sdk/models.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
4
|
+
|
|
5
|
+
from lightning_sdk.api import OrgApi, TeamspaceApi, UserApi
|
|
6
|
+
from lightning_sdk.lightning_cloud.openapi.models import V1Membership, V1OwnerType
|
|
7
|
+
from lightning_sdk.lightning_cloud.openapi.rest import ApiException
|
|
8
|
+
from lightning_sdk.teamspace import Teamspace
|
|
9
|
+
from lightning_sdk.user import User
|
|
10
|
+
from lightning_sdk.utils.resolve import _get_authed_user
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _get_teamspace_and_path(
|
|
14
|
+
ts: V1Membership, org_api: OrgApi, user_api: UserApi, authed_user: User
|
|
15
|
+
) -> Tuple[str, Dict[str, Any]]:
|
|
16
|
+
if ts.owner_type == V1OwnerType.ORGANIZATION:
|
|
17
|
+
org = org_api._get_org_by_id(ts.owner_id)
|
|
18
|
+
return f"{org.name}/{ts.name}", {"name": ts.name, "org": org.name}
|
|
19
|
+
|
|
20
|
+
if ts.owner_type == V1OwnerType.USER and ts.owner_id != authed_user.id:
|
|
21
|
+
user = user_api._get_user_by_id(ts.owner_id) # todo: check also the name
|
|
22
|
+
return f"{user.username}/{ts.name}", {"name": ts.name, "user": User(name=user.username)}
|
|
23
|
+
|
|
24
|
+
if ts.owner_type == V1OwnerType.USER:
|
|
25
|
+
return f"{authed_user.name}/{ts.name}", {"name": ts.name, "user": authed_user}
|
|
26
|
+
|
|
27
|
+
raise RuntimeError(f"Unknown organization type {ts.owner_type}")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _list_teamspaces() -> List[str]:
|
|
31
|
+
org_api = OrgApi()
|
|
32
|
+
user_api = UserApi()
|
|
33
|
+
authed_user = _get_authed_user()
|
|
34
|
+
|
|
35
|
+
return [
|
|
36
|
+
_get_teamspace_and_path(ts, org_api, user_api, authed_user)[0]
|
|
37
|
+
for ts in user_api._get_all_teamspace_memberships("")
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _get_teamspace(name: str, organization: str) -> Teamspace:
|
|
42
|
+
"""Get a Teamspace object from the SDK."""
|
|
43
|
+
org_api = OrgApi()
|
|
44
|
+
user_api = UserApi()
|
|
45
|
+
authed_user = _get_authed_user()
|
|
46
|
+
|
|
47
|
+
requested_teamspace = f"{organization}/{name}".lower()
|
|
48
|
+
|
|
49
|
+
for ts in user_api._get_all_teamspace_memberships(""):
|
|
50
|
+
if ts.name != name:
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
teamspace_path, teamspace = _get_teamspace_and_path(ts, org_api, user_api, authed_user)
|
|
54
|
+
if requested_teamspace == teamspace_path:
|
|
55
|
+
return Teamspace(**teamspace)
|
|
56
|
+
|
|
57
|
+
options = f"{os.linesep}\t".join(_list_teamspaces())
|
|
58
|
+
raise RuntimeError(f"Teamspace `{requested_teamspace}` not found. Available teamspaces: {os.linesep}\t{options}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _parse_model_name_and_version(name: str) -> Tuple[str, str, str, str]:
|
|
62
|
+
"""Parse the name argument into its components."""
|
|
63
|
+
try:
|
|
64
|
+
org_name, teamspace_name, model_name = name.split("/")
|
|
65
|
+
parts = model_name.split(":")
|
|
66
|
+
if len(parts) == 1:
|
|
67
|
+
return org_name, teamspace_name, parts[0], "latest"
|
|
68
|
+
if len(parts) == 2:
|
|
69
|
+
return org_name, teamspace_name, parts[0], parts[1]
|
|
70
|
+
# The rest of the validation for name and version happens in the backend
|
|
71
|
+
raise ValueError(
|
|
72
|
+
"Model version is expected to be in the format `entity/modelname:version` separated by a"
|
|
73
|
+
f" single colon, but got: {name}"
|
|
74
|
+
)
|
|
75
|
+
except ValueError as err:
|
|
76
|
+
raise ValueError(
|
|
77
|
+
f"Model name must be in the format 'organization/teamspace/model' but you provided '{name}'."
|
|
78
|
+
) from err
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def download_model(
|
|
82
|
+
name: str,
|
|
83
|
+
download_dir: Union[Path, str] = ".",
|
|
84
|
+
progress_bar: bool = True,
|
|
85
|
+
) -> List[str]:
|
|
86
|
+
"""Download a Model.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
name: The name of the Model you want to download.
|
|
90
|
+
This should have the format <ORGANIZATION-NAME>/<TEAMSPACE-NAME>/<MODEL-NAME>.
|
|
91
|
+
download_dir: The directory where the Model should be downloaded.
|
|
92
|
+
progress_bar: Whether to show a progress bar when downloading.
|
|
93
|
+
"""
|
|
94
|
+
teamspace_owner_name, teamspace_name, model_name, version = _parse_model_name_and_version(name)
|
|
95
|
+
|
|
96
|
+
download_dir = Path(download_dir)
|
|
97
|
+
|
|
98
|
+
api = TeamspaceApi()
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
return api.download_model_files(
|
|
102
|
+
name=model_name,
|
|
103
|
+
version=version,
|
|
104
|
+
download_dir=download_dir,
|
|
105
|
+
teamspace_name=teamspace_name,
|
|
106
|
+
teamspace_owner_name=teamspace_owner_name,
|
|
107
|
+
progress_bar=progress_bar,
|
|
108
|
+
)
|
|
109
|
+
except ApiException as e:
|
|
110
|
+
# if we get an error, check if the teamspace actually exists (and print the list)
|
|
111
|
+
# TODO: ideally this would match a specific error about teamspace not being found
|
|
112
|
+
_ = _get_teamspace(name=teamspace_name, organization=teamspace_owner_name)
|
|
113
|
+
raise e
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def upload_model(name: str, path: Union[Path, str] = ".", cloud_account: Optional[str] = None) -> None:
|
|
117
|
+
"""Upload a Model.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
name: The name of the Model you want to upload.
|
|
121
|
+
This should have the format <ORGANIZATION-NAME>/<TEAMSPACE-NAME>/<MODEL-NAME>.
|
|
122
|
+
path: The path to the file or directory you want to upload. Defaults to the current directory.
|
|
123
|
+
cloud_account: The name of the cloud account to store the Model in.
|
|
124
|
+
"""
|
|
125
|
+
org_name, teamspace_name, model_name, _ = _parse_model_name_and_version(name)
|
|
126
|
+
teamspace = _get_teamspace(name=teamspace_name, organization=org_name)
|
|
127
|
+
teamspace.upload_model(
|
|
128
|
+
path=path,
|
|
129
|
+
name=model_name,
|
|
130
|
+
progress_bar=True,
|
|
131
|
+
cluster_id=cloud_account,
|
|
132
|
+
)
|
lightning_sdk/teamspace.py
CHANGED
|
@@ -153,7 +153,7 @@ class Teamspace:
|
|
|
153
153
|
|
|
154
154
|
def upload_model(
|
|
155
155
|
self,
|
|
156
|
-
path: str,
|
|
156
|
+
path: Union[str, Path],
|
|
157
157
|
name: str,
|
|
158
158
|
progress_bar: bool = True,
|
|
159
159
|
cluster_id: Optional[str] = None,
|
|
@@ -245,11 +245,17 @@ class Teamspace:
|
|
|
245
245
|
download_dir = Path(download_dir)
|
|
246
246
|
|
|
247
247
|
name, version = _parse_model_and_version(name)
|
|
248
|
+
model_version = self._teamspace_api.get_model_version(name=name, version=version, teamspace_id=self.id)
|
|
249
|
+
if not model_version.upload_complete:
|
|
250
|
+
raise RuntimeError(
|
|
251
|
+
f"Model {name}:{version} is not fully uploaded yet. Please wait until the upload is complete."
|
|
252
|
+
)
|
|
248
253
|
downloaded_files = self._teamspace_api.download_model_files(
|
|
249
254
|
name=name,
|
|
250
255
|
version=version,
|
|
251
256
|
download_dir=download_dir,
|
|
252
|
-
|
|
257
|
+
teamspace_name=self.name,
|
|
258
|
+
teamspace_owner_name=self.owner.name,
|
|
253
259
|
progress_bar=progress_bar,
|
|
254
260
|
)
|
|
255
261
|
|