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.
Files changed (72) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/ai_hub.py +21 -23
  3. lightning_sdk/api/ai_hub_api.py +29 -4
  4. lightning_sdk/api/deployment_api.py +0 -2
  5. lightning_sdk/api/job_api.py +10 -2
  6. lightning_sdk/api/teamspace_api.py +22 -16
  7. lightning_sdk/api/utils.py +25 -3
  8. lightning_sdk/cli/ai_hub.py +1 -1
  9. lightning_sdk/cli/download.py +3 -5
  10. lightning_sdk/cli/run.py +24 -0
  11. lightning_sdk/cli/upload.py +3 -10
  12. lightning_sdk/job/base.py +35 -0
  13. lightning_sdk/job/job.py +18 -1
  14. lightning_sdk/job/v1.py +10 -1
  15. lightning_sdk/job/v2.py +16 -0
  16. lightning_sdk/lightning_cloud/openapi/__init__.py +13 -2
  17. lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +5 -1
  18. lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +6 -1
  19. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +680 -62
  20. lightning_sdk/lightning_cloud/openapi/api/models_store_api.py +118 -1
  21. lightning_sdk/lightning_cloud/openapi/models/__init__.py +13 -2
  22. lightning_sdk/lightning_cloud/openapi/models/create.py +6 -32
  23. lightning_sdk/lightning_cloud/openapi/models/deploymenttemplates_id_body.py +32 -6
  24. lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +27 -1
  25. lightning_sdk/lightning_cloud/openapi/models/id_start_body.py +29 -3
  26. lightning_sdk/lightning_cloud/openapi/models/multimachinejobs_id_body.py +123 -0
  27. lightning_sdk/lightning_cloud/openapi/models/project_id_agents_body.py +53 -1
  28. lightning_sdk/lightning_cloud/openapi/models/project_id_cloudspaces_body.py +53 -1
  29. lightning_sdk/lightning_cloud/openapi/models/project_id_multimachinejobs_body.py +201 -0
  30. lightning_sdk/lightning_cloud/openapi/models/update.py +6 -32
  31. lightning_sdk/lightning_cloud/openapi/models/v1_api_pricing_spec.py +149 -0
  32. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +27 -1
  33. lightning_sdk/lightning_cloud/openapi/models/v1_create_deployment_template_request.py +32 -6
  34. lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +6 -32
  35. lightning_sdk/lightning_cloud/openapi/models/v1_data_path.py +29 -3
  36. lightning_sdk/lightning_cloud/openapi/models/v1_delete_multi_machine_job_response.py +97 -0
  37. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_metrics.py +43 -17
  38. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_performance.py +305 -0
  39. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template.py +32 -6
  40. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template_parameter.py +27 -1
  41. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template_parameter_type.py +1 -0
  42. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_template_summary.py +27 -1
  43. lightning_sdk/lightning_cloud/openapi/models/{v1_efs_data_connection.py → v1_efs_config.py} +22 -22
  44. lightning_sdk/lightning_cloud/openapi/models/v1_get_model_files_response.py +27 -1
  45. lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +53 -1
  46. lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +53 -53
  47. lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py +125 -0
  48. lightning_sdk/lightning_cloud/openapi/models/v1_list_multi_machine_jobs_response.py +123 -0
  49. lightning_sdk/lightning_cloud/openapi/models/v1_machines_selector.py +149 -0
  50. lightning_sdk/lightning_cloud/openapi/models/v1_message.py +6 -6
  51. lightning_sdk/lightning_cloud/openapi/models/v1_message_content.py +6 -6
  52. lightning_sdk/lightning_cloud/openapi/models/v1_message_content_type.py +103 -0
  53. lightning_sdk/lightning_cloud/openapi/models/v1_metrics_stream.py +53 -1
  54. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job.py +409 -0
  55. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_state.py +106 -0
  56. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_status.py +279 -0
  57. lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +2 -0
  58. lightning_sdk/lightning_cloud/openapi/models/v1_system_info.py +27 -1
  59. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +53 -1
  60. lightning_sdk/lightning_cloud/openapi/models/v1_user_requested_compute_config.py +27 -1
  61. lightning_sdk/lightning_cloud/openapi/models/v1_validate_data_connection_response.py +6 -32
  62. lightning_sdk/lightning_cloud/openapi/models/validate.py +6 -32
  63. lightning_sdk/models.py +132 -0
  64. lightning_sdk/teamspace.py +8 -2
  65. {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/METADATA +1 -1
  66. {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/RECORD +70 -59
  67. lightning_sdk/cli/models.py +0 -68
  68. lightning_sdk/lightning_cloud/openapi/models/v1_efs_folder_data_connection.py +0 -201
  69. {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/LICENSE +0 -0
  70. {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/WHEEL +0 -0
  71. {lightning_sdk-0.1.37.dist-info → lightning_sdk-0.1.39.dist-info}/entry_points.txt +0 -0
  72. {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': 'V1EfsDataConnection',
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: 'V1EfsDataConnection' =None, efs_folder: 'V1EFSFolderDataConnection' =None, gcp: 'V1GcpDataConnection' =None, gcs_folder: 'V1GCSFolderDataConnection' =None, s3_folder: 'V1S3FolderDataConnection' =None): # noqa: E501
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) -> 'V1EfsDataConnection':
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: V1EfsDataConnection
157
+ :rtype: V1EfsConfig
163
158
  """
164
159
  return self._efs
165
160
 
166
161
  @efs.setter
167
- def efs(self, efs: 'V1EfsDataConnection'):
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: V1EfsDataConnection
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
@@ -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
+ )
@@ -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
- teamspace_id=self.id,
257
+ teamspace_name=self.name,
258
+ teamspace_owner_name=self.owner.name,
253
259
  progress_bar=progress_bar,
254
260
  )
255
261
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.1.37
3
+ Version: 0.1.39
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License