lightning-sdk 0.1.41__py3-none-any.whl → 0.1.42__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 (74) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/ai_hub.py +8 -3
  3. lightning_sdk/api/ai_hub_api.py +3 -3
  4. lightning_sdk/api/deployment_api.py +6 -6
  5. lightning_sdk/api/job_api.py +32 -6
  6. lightning_sdk/api/mmt_api.py +59 -19
  7. lightning_sdk/api/studio_api.py +37 -19
  8. lightning_sdk/api/teamspace_api.py +34 -29
  9. lightning_sdk/api/utils.py +46 -34
  10. lightning_sdk/cli/ai_hub.py +3 -3
  11. lightning_sdk/cli/entrypoint.py +3 -1
  12. lightning_sdk/cli/mmt.py +11 -10
  13. lightning_sdk/cli/run.py +9 -8
  14. lightning_sdk/cli/serve.py +130 -0
  15. lightning_sdk/deployment/deployment.py +18 -12
  16. lightning_sdk/job/base.py +118 -24
  17. lightning_sdk/job/job.py +87 -9
  18. lightning_sdk/job/v1.py +75 -18
  19. lightning_sdk/job/v2.py +51 -15
  20. lightning_sdk/job/work.py +36 -7
  21. lightning_sdk/lightning_cloud/openapi/__init__.py +12 -0
  22. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +215 -5
  23. lightning_sdk/lightning_cloud/openapi/api/lit_logger_service_api.py +218 -0
  24. lightning_sdk/lightning_cloud/openapi/api/models_store_api.py +226 -0
  25. lightning_sdk/lightning_cloud/openapi/api/snowflake_service_api.py +21 -1
  26. lightning_sdk/lightning_cloud/openapi/models/__init__.py +12 -0
  27. lightning_sdk/lightning_cloud/openapi/models/deploymenttemplates_id_body.py +27 -1
  28. lightning_sdk/lightning_cloud/openapi/models/id_visibility_body.py +123 -0
  29. lightning_sdk/lightning_cloud/openapi/models/model_id_versions_body.py +29 -3
  30. lightning_sdk/lightning_cloud/openapi/models/project_id_multimachinejobs_body.py +27 -1
  31. lightning_sdk/lightning_cloud/openapi/models/project_id_snowflake_body.py +15 -67
  32. lightning_sdk/lightning_cloud/openapi/models/query_query_id_body.py +17 -69
  33. lightning_sdk/lightning_cloud/openapi/models/snowflake_export_body.py +29 -81
  34. lightning_sdk/lightning_cloud/openapi/models/snowflake_query_body.py +17 -69
  35. lightning_sdk/lightning_cloud/openapi/models/v1_get_model_file_url_response.py +27 -1
  36. lightning_sdk/lightning_cloud/openapi/models/v1_get_model_files_response.py +17 -17
  37. lightning_sdk/lightning_cloud/openapi/models/v1_get_model_files_url_response.py +149 -0
  38. lightning_sdk/lightning_cloud/openapi/models/v1_get_project_balance_response.py +27 -1
  39. lightning_sdk/lightning_cloud/openapi/models/v1_list_multi_machine_job_events_response.py +123 -0
  40. lightning_sdk/lightning_cloud/openapi/models/v1_metrics_stream.py +27 -1
  41. lightning_sdk/lightning_cloud/openapi/models/v1_model_file.py +175 -0
  42. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job.py +27 -1
  43. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_event.py +331 -0
  44. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_event_type.py +104 -0
  45. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_fault_tolerance.py +149 -0
  46. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_fault_tolerance_strategy.py +105 -0
  47. lightning_sdk/lightning_cloud/openapi/models/v1_multi_machine_job_status.py +27 -1
  48. lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
  49. lightning_sdk/lightning_cloud/openapi/models/v1_snowflake_data_connection.py +29 -81
  50. lightning_sdk/lightning_cloud/openapi/models/v1_system_metrics.py +29 -3
  51. lightning_sdk/lightning_cloud/openapi/models/v1_trainium_system_metrics.py +175 -0
  52. lightning_sdk/lightning_cloud/openapi/models/v1_update_metrics_stream_visibility_response.py +97 -0
  53. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +27 -53
  54. lightning_sdk/lightning_cloud/openapi/models/v1_validate_deployment_image_request.py +149 -0
  55. lightning_sdk/lightning_cloud/openapi/models/v1_validate_deployment_image_response.py +97 -0
  56. lightning_sdk/lightning_cloud/rest_client.py +2 -0
  57. lightning_sdk/mmt/__init__.py +3 -0
  58. lightning_sdk/{_mmt → mmt}/base.py +20 -14
  59. lightning_sdk/{_mmt → mmt}/mmt.py +46 -17
  60. lightning_sdk/mmt/v1.py +129 -0
  61. lightning_sdk/{_mmt → mmt}/v2.py +16 -21
  62. lightning_sdk/plugin.py +43 -16
  63. lightning_sdk/services/file_endpoint.py +11 -5
  64. lightning_sdk/studio.py +16 -9
  65. lightning_sdk/teamspace.py +21 -8
  66. lightning_sdk/utils/resolve.py +18 -0
  67. {lightning_sdk-0.1.41.dist-info → lightning_sdk-0.1.42.dist-info}/METADATA +3 -1
  68. {lightning_sdk-0.1.41.dist-info → lightning_sdk-0.1.42.dist-info}/RECORD +72 -59
  69. lightning_sdk/_mmt/__init__.py +0 -3
  70. lightning_sdk/_mmt/v1.py +0 -69
  71. {lightning_sdk-0.1.41.dist-info → lightning_sdk-0.1.42.dist-info}/LICENSE +0 -0
  72. {lightning_sdk-0.1.41.dist-info → lightning_sdk-0.1.42.dist-info}/WHEEL +0 -0
  73. {lightning_sdk-0.1.41.dist-info → lightning_sdk-0.1.42.dist-info}/entry_points.txt +0 -0
  74. {lightning_sdk-0.1.41.dist-info → lightning_sdk-0.1.42.dist-info}/top_level.txt +0 -0
lightning_sdk/plugin.py CHANGED
@@ -127,7 +127,15 @@ class JobsPlugin(_Plugin):
127
127
  cloud_compute: Optional[Machine] = None,
128
128
  interruptible: bool = False,
129
129
  ) -> Job:
130
- """Launches an asynchronous job."""
130
+ """Launches an asynchronous job.
131
+
132
+ Args:
133
+ command: The command to be executed.
134
+ name: The name of the job.
135
+ machine: The machine to run the job on.
136
+ interruptible: Whether to run the job on an interruptible machine.
137
+ These are cheaper but can be preempted at any time.
138
+ """
131
139
  if not name:
132
140
  name = _run_name("job")
133
141
 
@@ -139,7 +147,7 @@ class JobsPlugin(_Plugin):
139
147
  command=command,
140
148
  studio=self._studio,
141
149
  teamspace=self._studio.teamspace,
142
- cluster=self._studio._cluster,
150
+ cloud_account=self._studio.cloud_account,
143
151
  interruptible=interruptible,
144
152
  )
145
153
 
@@ -161,29 +169,39 @@ class MultiMachineTrainingPlugin(_Plugin):
161
169
  machine: Machine = Machine.CPU,
162
170
  cloud_compute: Optional[Machine] = None,
163
171
  num_instances: int = 2,
164
- strategy: str = "parallel",
165
172
  interruptible: bool = False,
166
173
  ) -> Job:
167
- """Launches an asynchronous multi-machine-training."""
174
+ """Launches an asynchronous multi-machine-training.
175
+
176
+ Args:
177
+ command: The command to be executed.
178
+ name: The name of the job.
179
+ machine: The machine to run the job on.
180
+ num_instances: The number of instances to run the job on.
181
+ interruptible: Whether to run the job on an interruptible machine.
182
+ These are cheaper but can be preempted at any time.
183
+ """
184
+ from lightning_sdk.mmt import MMT
185
+
168
186
  if not name:
169
187
  name = _run_name("dist-run")
170
188
 
171
189
  machine = _resolve_deprecated_cloud_compute(machine, cloud_compute)
172
190
 
173
- # TODO: assert num_instances >=2
174
- resp = self._studio._studio_api.create_multi_machine_job(
175
- entrypoint=command,
191
+ MMT._force_v1 = True
192
+
193
+ mmt = MMT.run(
176
194
  name=name,
177
- num_instances=num_instances,
195
+ num_machines=num_instances,
178
196
  machine=machine,
179
- strategy=strategy,
180
- studio_id=self._studio._studio.id,
181
- teamspace_id=self._studio._teamspace.id,
182
- cluster_id=self._studio._studio.cluster_id,
197
+ command=command,
198
+ studio=self._studio,
199
+ teamspace=self._studio.teamspace,
183
200
  interruptible=interruptible,
184
201
  )
185
202
 
186
- return Job(resp.name, self._studio.teamspace)
203
+ MMT._force_v1 = False
204
+ return mmt
187
205
 
188
206
 
189
207
  class MultiMachineDataPrepPlugin(_Plugin):
@@ -201,7 +219,16 @@ class MultiMachineDataPrepPlugin(_Plugin):
201
219
  num_instances: int = 2,
202
220
  interruptible: bool = False,
203
221
  ) -> Job:
204
- """Launches an asynchronous multi-machine-processing-job."""
222
+ """Launches an asynchronous multi-machine-data-processing job.
223
+
224
+ Args:
225
+ command: The command to be executed.
226
+ name: The name of the job.
227
+ machine: The machine to run the job on.
228
+ num_instances: The number of instances to run the job on.
229
+ interruptible: Whether to run the job on an interruptible machine.
230
+ These are cheaper but can be preempted at any time.
231
+ """
205
232
  if not name:
206
233
  name = _run_name("data-prep")
207
234
 
@@ -214,7 +241,7 @@ class MultiMachineDataPrepPlugin(_Plugin):
214
241
  machine=machine,
215
242
  studio_id=self._studio._studio.id,
216
243
  teamspace_id=self._studio._teamspace.id,
217
- cluster_id=self._studio._studio.cluster_id,
244
+ cloud_account=self._studio.cloud_account,
218
245
  interruptible=interruptible,
219
246
  )
220
247
 
@@ -261,7 +288,7 @@ class InferenceServerPlugin(_Plugin):
261
288
  endpoint=endpoint,
262
289
  studio_id=self._studio._studio.id,
263
290
  teamspace_id=self._studio._teamspace.id,
264
- cluster_id=self._studio._studio.cluster_id,
291
+ cloud_account=self._studio.cloud_account,
265
292
  interruptible=interruptible,
266
293
  )
267
294
 
@@ -11,6 +11,7 @@ from lightning_sdk.lightning_cloud.login import Auth
11
11
  from lightning_sdk.lightning_cloud.openapi import CommandArgumentCommandArgumentType
12
12
  from lightning_sdk.lightning_cloud.rest_client import LightningClient
13
13
  from lightning_sdk.services.utilities import _get_cluster, _get_project, _get_service_url
14
+ from lightning_sdk.utils.resolve import _resolve_deprecated_cluster
14
15
 
15
16
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
16
17
 
@@ -25,16 +26,19 @@ class Client:
25
26
  self,
26
27
  name: str,
27
28
  teamspace: Optional[str],
28
- cluster_id: Optional[str] = None,
29
+ cloud_account: Optional[str] = None,
30
+ cluster_id: Optional[str] = None, # deprecated in favor of cloud_account
29
31
  ) -> None:
30
32
  """Constructor of the Client.
31
33
 
32
34
  Args:
33
35
  name: The name of the Studio File Endpoint Service.
34
36
  teamspace: The name of the teamspace you want to attach the upload data and artifacts to be.
35
- cluster_id: The name of the cluster on which to upload the data.
37
+ cloud_account: The name of the cloud account on which to upload the data.
36
38
 
37
39
  """
40
+ cloud_account = _resolve_deprecated_cluster(cloud_account, cluster_id)
41
+
38
42
  self._auth = Auth()
39
43
 
40
44
  try:
@@ -46,7 +50,9 @@ class Client:
46
50
  self._teamspace = teamspace
47
51
  self._client = LightningClient()
48
52
  self._project = _get_project(client=self._client, project_name=teamspace)
49
- self._cluster = _get_cluster(client=self._client, project_id=self._project.project_id, cluster_id=cluster_id)
53
+ self._cloud_account = _get_cluster(
54
+ client=self._client, project_id=self._project.project_id, cluster_id=cloud_account
55
+ )
50
56
  self._file_endpoint = self._client.endpoint_service_get_file_endpoint_by_name(
51
57
  project_id=self._project.project_id, name=self._name
52
58
  )
@@ -101,7 +107,7 @@ class Client:
101
107
  _FileUploader(
102
108
  client=self._client,
103
109
  teamspace_id=self._project.project_id,
104
- cluster_id=self._cluster.cluster_id,
110
+ cloud_account=self._cloud_account.cluster_id,
105
111
  file_path=argument.value,
106
112
  progress_bar=True,
107
113
  remote_path=_sanitize_uploads_remote_path(argument.value),
@@ -109,7 +115,7 @@ class Client:
109
115
 
110
116
  json = {
111
117
  "teamspace_id": self._project.project_id,
112
- "cluster_id": self._cluster.cluster_id,
118
+ "cluster_id": self._cloud_account.cluster_id,
113
119
  "input": {},
114
120
  }
115
121
  for argument in self._arguments:
lightning_sdk/studio.py CHANGED
@@ -11,7 +11,7 @@ from lightning_sdk.owner import Owner
11
11
  from lightning_sdk.status import Status
12
12
  from lightning_sdk.teamspace import Teamspace
13
13
  from lightning_sdk.user import User
14
- from lightning_sdk.utils.resolve import _resolve_teamspace, _setup_logger
14
+ from lightning_sdk.utils.resolve import _resolve_deprecated_cluster, _resolve_teamspace, _setup_logger
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from lightning_sdk.plugin import Plugin
@@ -30,10 +30,9 @@ class Studio:
30
30
  teamspace: the name of the teamspace the studio is contained by
31
31
  org: the name of the organization owning the :param`teamspace` in case it is owned by an org
32
32
  user: the name of the user owning the :param`teamspace` in case it is owned directly by a user instead of an org
33
- cluster: the name of the cluster, the studio should be created on.
33
+ cloud_account: the name of the cloud account, the studio should be created on.
34
34
  Doesn't matter when the studio already exists.
35
35
  create_ok: whether the studio will be created if it does not yet exist. Defaults to True
36
-
37
36
  Note:
38
37
  Since a teamspace can either be owned by an org or by a user directly,
39
38
  only one of the arguments can be provided.
@@ -49,13 +48,14 @@ class Studio:
49
48
  teamspace: Optional[Union[str, Teamspace]] = None,
50
49
  org: Optional[Union[str, Organization]] = None,
51
50
  user: Optional[Union[str, User]] = None,
52
- cluster: Optional[str] = None,
51
+ cloud_account: Optional[str] = None,
53
52
  create_ok: bool = True,
53
+ cluster: Optional[str] = None, # deprecated in favor of cloud_account
54
54
  ) -> None:
55
55
  self._studio_api = StudioApi()
56
56
 
57
57
  self._teamspace = _resolve_teamspace(teamspace=teamspace, org=org, user=user)
58
- self._cluster = cluster
58
+ self._cloud_account = _resolve_deprecated_cluster(cloud_account, cluster)
59
59
  self._setup_done = False
60
60
 
61
61
  self._plugins = {}
@@ -70,7 +70,9 @@ class Studio:
70
70
  self._studio = self._studio_api.get_studio(name, self._teamspace.id)
71
71
  except ValueError as e:
72
72
  if create_ok:
73
- self._studio = self._studio_api.create_studio(name, self._teamspace.id, cluster=self._cluster)
73
+ self._studio = self._studio_api.create_studio(
74
+ name, self._teamspace.id, cloud_account=self._cloud_account
75
+ )
74
76
  else:
75
77
  raise ValueError(f"Studio {name} does not exist.") from e
76
78
 
@@ -144,6 +146,11 @@ class Studio:
144
146
  @property
145
147
  def cluster(self) -> str:
146
148
  """Returns the cluster the Studio is running on."""
149
+ warnings.warn("Studio.cluster is deprecated. Use Studio.cloud_account instead", DeprecationWarning)
150
+ return self.cloud_account
151
+
152
+ @property
153
+ def cloud_account(self) -> str:
147
154
  return self._studio.cluster_id
148
155
 
149
156
  def start(self, machine: Union[Machine, str] = Machine.CPU, interruptible: bool = False) -> None:
@@ -242,7 +249,7 @@ class Studio:
242
249
  self._studio_api.upload_file(
243
250
  studio_id=self._studio.id,
244
251
  teamspace_id=self._teamspace.id,
245
- cluster_id=self._studio.cluster_id,
252
+ cloud_account=self._studio.cluster_id,
246
253
  file_path=file_path,
247
254
  remote_path=os.path.normpath(remote_path),
248
255
  progress_bar=progress_bar,
@@ -258,7 +265,7 @@ class Studio:
258
265
  target_path=file_path,
259
266
  studio_id=self._studio.id,
260
267
  teamspace_id=self._teamspace.id,
261
- cluster_id=self._studio.cluster_id,
268
+ cloud_account=self._studio.cluster_id,
262
269
  )
263
270
 
264
271
  def download_folder(self, remote_path: str, target_path: Optional[str] = None) -> None:
@@ -271,7 +278,7 @@ class Studio:
271
278
  target_path=target_path,
272
279
  studio_id=self._studio.id,
273
280
  teamspace_id=self._teamspace.id,
274
- cluster_id=self._studio.cluster_id,
281
+ cloud_account=self._studio.cluster_id,
275
282
  )
276
283
 
277
284
  @property
@@ -1,3 +1,4 @@
1
+ import warnings
1
2
  from pathlib import Path
2
3
  from typing import TYPE_CHECKING, List, Optional, Union
3
4
 
@@ -97,23 +98,33 @@ class Teamspace:
97
98
  from lightning_sdk.studio import Studio
98
99
 
99
100
  studios = []
100
- clusters = self._teamspace_api.list_clusters(teamspace_id=self.id)
101
+ clusters = self._teamspace_api.list_cloud_accounts(teamspace_id=self.id)
101
102
  for cl in clusters:
102
- _studios = self._teamspace_api.list_studios(teamspace_id=self.id, cluster_id=cl.cluster_id)
103
+ _studios = self._teamspace_api.list_studios(teamspace_id=self.id, cloud_account=cl.cluster_id)
103
104
  for s in _studios:
104
105
  studios.append(Studio(name=s.name, teamspace=self, cluster=cl.cluster_name, create_ok=False))
105
106
 
106
107
  return studios
107
108
 
108
109
  @property
109
- def default_cluster(self) -> str:
110
+ def default_cloud_account(self) -> str:
110
111
  return self._teamspace.project_settings.preferred_cluster
111
112
 
113
+ @property
114
+ def cloud_accounts(self) -> List[str]:
115
+ """All cloud accounts associated with that teamspace."""
116
+ clusters = self._teamspace_api.list_cloud_accounts(teamspace_id=self.id)
117
+ return [cl.cluster_name for cl in clusters]
118
+
112
119
  @property
113
120
  def clusters(self) -> List[str]:
114
121
  """All clusters associated with that teamspace."""
115
- clusters = self._teamspace_api.list_clusters(teamspace_id=self.id)
116
- return [cl.cluster_name for cl in clusters]
122
+ warnings.warn(
123
+ "The 'clusters' attribute is deprecated and will be removed in the future. "
124
+ "Please use the 'cloud_accounts' attribute instead.",
125
+ DeprecationWarning,
126
+ )
127
+ return self.cloud_accounts
117
128
 
118
129
  def __eq__(self, other: "Teamspace") -> bool:
119
130
  """Checks whether the provided other object is equal to this one."""
@@ -179,7 +190,9 @@ class Teamspace:
179
190
  if not path.exists():
180
191
  raise FileNotFoundError(str(path))
181
192
 
182
- cloud_account = self._teamspace_api._determine_cluster_id(self.id) if cloud_account is None else cloud_account
193
+ cloud_account = (
194
+ self._teamspace_api._determine_cloud_account(self.id) if cloud_account is None else cloud_account
195
+ )
183
196
  filepaths = [path] if path.is_file() else [p for p in path.rglob("*") if p.is_file()]
184
197
 
185
198
  if not filepaths:
@@ -199,14 +212,14 @@ class Teamspace:
199
212
  metadata={"filenames": filenames},
200
213
  private=True,
201
214
  teamspace_id=self.id,
202
- cluster_id=cloud_account,
215
+ cloud_account=cloud_account,
203
216
  )
204
217
  self._teamspace_api.upload_model_files(
205
218
  model_id=model.model_id,
206
219
  version=model.version,
207
220
  root_path=root_path,
208
221
  filepaths=filepaths,
209
- cluster_id=cloud_account,
222
+ cloud_account=cloud_account,
210
223
  teamspace_id=self.id,
211
224
  progress_bar=progress_bar,
212
225
  )
@@ -46,6 +46,24 @@ def _resolve_deprecated_cloud_compute(machine: Machine, cloud_compute: Optional[
46
46
  return machine
47
47
 
48
48
 
49
+ def _resolve_deprecated_cluster(cloud_account: Optional[str], cluster: Optional[str]) -> Optional[str]:
50
+ if cluster is not None:
51
+ if cloud_account is not None:
52
+ raise ValueError(
53
+ "Cannot use both 'cluster' and 'cloud_account' at the same time."
54
+ "Please don't set the 'cluster' as it will be deprecated!"
55
+ )
56
+
57
+ warnings.warn(
58
+ "The 'cluster' argument will be deprecated in the future! "
59
+ "Please consider using the 'cloud_account' argument instead!",
60
+ DeprecationWarning,
61
+ )
62
+ return cluster
63
+
64
+ return cloud_account
65
+
66
+
49
67
  def _resolve_org_name(name: Optional[str]) -> Optional[str]:
50
68
  if name is None:
51
69
  name = os.environ.get("LIGHTNING_ORG", "") or None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.1.41
3
+ Version: 0.1.42
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License
@@ -45,6 +45,8 @@ Requires-Dist: tqdm
45
45
  Requires-Dist: fire
46
46
  Requires-Dist: simple-term-menu
47
47
  Requires-Dist: lightning-utilities
48
+ Provides-Extra: serve
49
+ Requires-Dist: litserve>=0.2.5; extra == "serve"
48
50
 
49
51
  # Lightning SDK
50
52