lightning-sdk 0.2.5__py3-none-any.whl → 0.2.7__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 (65) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/api/ai_hub_api.py +1 -0
  3. lightning_sdk/api/lit_container_api.py +84 -24
  4. lightning_sdk/api/teamspace_api.py +8 -9
  5. lightning_sdk/api/utils.py +0 -1
  6. lightning_sdk/cli/docker.py +1 -1
  7. lightning_sdk/cli/download.py +10 -2
  8. lightning_sdk/cli/serve.py +26 -19
  9. lightning_sdk/cli/upload.py +41 -6
  10. lightning_sdk/lightning_cloud/openapi/__init__.py +16 -0
  11. lightning_sdk/lightning_cloud/openapi/api/cloud_space_environment_template_service_api.py +9 -9
  12. lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +202 -0
  13. lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +105 -0
  14. lightning_sdk/lightning_cloud/openapi/api/lit_registry_service_api.py +15 -3
  15. lightning_sdk/lightning_cloud/openapi/models/__init__.py +16 -0
  16. lightning_sdk/lightning_cloud/openapi/models/alerts_config_billing.py +175 -0
  17. lightning_sdk/lightning_cloud/openapi/models/alerts_config_studios.py +149 -0
  18. lightning_sdk/lightning_cloud/openapi/models/environmenttemplates_id_body.py +27 -1
  19. lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +27 -1
  20. lightning_sdk/lightning_cloud/openapi/models/externalv1_cluster.py +27 -1
  21. lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +53 -1
  22. lightning_sdk/lightning_cloud/openapi/models/project_id_cloudspaces_body.py +27 -1
  23. lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +27 -1
  24. lightning_sdk/lightning_cloud/openapi/models/server_id_alerts_body.py +201 -0
  25. lightning_sdk/lightning_cloud/openapi/models/v1_alert_method.py +102 -0
  26. lightning_sdk/lightning_cloud/openapi/models/v1_alerts_config.py +149 -0
  27. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_cold_start_metrics.py +617 -0
  28. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template.py +27 -1
  29. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +123 -0
  30. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_security_options.py +27 -1
  31. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +131 -1
  32. lightning_sdk/lightning_cloud/openapi/models/v1_conversation_response_chunk.py +29 -3
  33. lightning_sdk/lightning_cloud/openapi/models/v1_create_cloud_space_environment_template_request.py +27 -1
  34. lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +27 -1
  35. lightning_sdk/lightning_cloud/openapi/models/v1_create_server_alert_response.py +97 -0
  36. lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +27 -1
  37. lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +81 -3
  38. lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py +1 -29
  39. lightning_sdk/lightning_cloud/openapi/models/v1_list_cloud_space_cold_start_metrics_response.py +123 -0
  40. lightning_sdk/lightning_cloud/openapi/models/v1_list_lit_registry_repository_image_artifact_versions_response.py +27 -1
  41. lightning_sdk/lightning_cloud/openapi/models/v1_message.py +29 -3
  42. lightning_sdk/lightning_cloud/openapi/models/v1_metadata.py +27 -1
  43. lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +53 -1
  44. lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +27 -1
  45. lightning_sdk/lightning_cloud/openapi/models/v1_report_cloud_space_instance_stop_at_response.py +97 -0
  46. lightning_sdk/lightning_cloud/openapi/models/v1_reservation_details.py +201 -0
  47. lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
  48. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert.py +201 -0
  49. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_phase.py +104 -0
  50. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_severity.py +103 -0
  51. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_type.py +105 -0
  52. lightning_sdk/lightning_cloud/openapi/models/v1_subnet_spec.py +149 -0
  53. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +131 -79
  54. lightning_sdk/lightning_cloud/openapi/models/v1_voltage_park_direct_v1.py +29 -29
  55. lightning_sdk/lightning_cloud/openapi/models/v1_vultr_direct_v1.py +1 -27
  56. lightning_sdk/lit_container.py +19 -4
  57. lightning_sdk/models.py +1 -1
  58. lightning_sdk/serve.py +86 -15
  59. lightning_sdk/teamspace.py +32 -18
  60. {lightning_sdk-0.2.5.dist-info → lightning_sdk-0.2.7.dist-info}/METADATA +1 -1
  61. {lightning_sdk-0.2.5.dist-info → lightning_sdk-0.2.7.dist-info}/RECORD +65 -49
  62. {lightning_sdk-0.2.5.dist-info → lightning_sdk-0.2.7.dist-info}/LICENSE +0 -0
  63. {lightning_sdk-0.2.5.dist-info → lightning_sdk-0.2.7.dist-info}/WHEEL +0 -0
  64. {lightning_sdk-0.2.5.dist-info → lightning_sdk-0.2.7.dist-info}/entry_points.txt +0 -0
  65. {lightning_sdk-0.2.5.dist-info → lightning_sdk-0.2.7.dist-info}/top_level.txt +0 -0
lightning_sdk/serve.py CHANGED
@@ -2,7 +2,7 @@ import os
2
2
  import shlex
3
3
  import subprocess
4
4
  from pathlib import Path
5
- from typing import Generator, Optional
5
+ from typing import Generator, List, Optional, Union
6
6
  from urllib.parse import urlencode
7
7
 
8
8
  import docker
@@ -10,7 +10,7 @@ from rich.console import Console
10
10
  from rich.progress import Progress
11
11
 
12
12
  from lightning_sdk import Deployment, Machine, Teamspace
13
- from lightning_sdk.api.deployment_api import AutoScaleConfig
13
+ from lightning_sdk.api.deployment_api import AutoScaleConfig, DeploymentApi, Env, Secret
14
14
  from lightning_sdk.api.lit_container_api import LitContainerApi
15
15
  from lightning_sdk.api.utils import _get_cloud_url
16
16
  from lightning_sdk.lightning_cloud import env
@@ -35,16 +35,18 @@ class _Auth(Auth):
35
35
  _AuthServer().login_with_browser(self)
36
36
 
37
37
 
38
+ def authenticate() -> None:
39
+ auth = _Auth()
40
+ auth.authenticate()
41
+
42
+
38
43
  class _LitServeDeployer:
39
- def __init__(self) -> None:
44
+ def __init__(self, name: Optional[str], teamspace: Optional[Teamspace]) -> None:
45
+ self.name = name
46
+ self.teamspace = teamspace
40
47
  self._console = Console()
41
48
  self._client = None
42
49
 
43
- @staticmethod
44
- def authenticate() -> None:
45
- auth = _Auth()
46
- auth.authenticate()
47
-
48
50
  @property
49
51
  def client(self) -> docker.DockerClient:
50
52
  if self._client is None:
@@ -56,6 +58,10 @@ class _LitServeDeployer:
56
58
  raise RuntimeError(_DOCKER_NOT_RUNNING_MSG) from None
57
59
  return self._client
58
60
 
61
+ @property
62
+ def created(self) -> bool:
63
+ return DeploymentApi().get_deployment_by_name(self.name, self.teamspace.id) is not None
64
+
59
65
  def dockerize_api(
60
66
  self,
61
67
  server_filename: str,
@@ -194,13 +200,19 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
194
200
  progress.update(build_task, description="[green]Build completed![/green]")
195
201
 
196
202
  def push_container(
197
- self, repository: str, tag: str, teamspace: Teamspace, lit_cr: LitContainerApi, progress: Progress
203
+ self,
204
+ repository: str,
205
+ tag: str,
206
+ teamspace: Teamspace,
207
+ lit_cr: LitContainerApi,
208
+ progress: Progress,
209
+ cloud_account: str,
198
210
  ) -> dict:
199
211
  console = self._console
200
212
  push_task = progress.add_task("Pushing to registry", total=None)
201
213
  console.print("\nPushing image...", style="bold blue")
202
214
  lit_cr.authenticate()
203
- push_status = lit_cr.upload_container(repository, teamspace, tag=tag)
215
+ push_status = lit_cr.upload_container(repository, teamspace, tag=tag, cloud_account=cloud_account)
204
216
  last_status = {}
205
217
  for line in push_status:
206
218
  last_status = line
@@ -214,7 +226,38 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
214
226
  progress.update(push_task, description="[green]Push completed![/green]")
215
227
  return last_status
216
228
 
217
- def _run_on_cloud(
229
+ def _update_deployment(
230
+ self,
231
+ deployment: Deployment,
232
+ machine: Optional[Machine] = None,
233
+ image: Optional[str] = None,
234
+ entrypoint: Optional[str] = None,
235
+ command: Optional[str] = None,
236
+ env: Optional[List[Union[Env, Secret]]] = None,
237
+ min_replica: Optional[int] = 0,
238
+ max_replica: Optional[int] = 1,
239
+ spot: Optional[bool] = None,
240
+ replicas: Optional[int] = 1,
241
+ cloud_account: Optional[str] = None,
242
+ port: Optional[int] = 8000,
243
+ include_credentials: Optional[bool] = True,
244
+ ) -> None:
245
+ return deployment.update(
246
+ machine=machine,
247
+ image=image,
248
+ entrypoint=entrypoint,
249
+ command=command,
250
+ env=env,
251
+ max_replicas=max_replica,
252
+ min_replicas=min_replica,
253
+ replicas=replicas,
254
+ spot=spot,
255
+ cloud_account=cloud_account,
256
+ ports=[port],
257
+ include_credentials=include_credentials,
258
+ )
259
+
260
+ def run_on_cloud(
218
261
  self,
219
262
  deployment_name: str,
220
263
  teamspace: Teamspace,
@@ -229,16 +272,44 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
229
272
  port: Optional[int] = 8000,
230
273
  include_credentials: Optional[bool] = True,
231
274
  ) -> dict:
275
+ """Run a deployment on the cloud. If the deployment already exists, it will be updated.
276
+
277
+ Args:
278
+ deployment_name: The name of the deployment.
279
+ teamspace: The teamspace to run the deployment on.
280
+ image: The image to run the deployment on.
281
+ metric: The metric to use for autoscaling. Defaults to None.
282
+ machine: The machine to run the deployment on. Defaults to None.
283
+ min_replica: The minimum number of replicas to run. Defaults to 0.
284
+ max_replica: The maximum number of replicas to run. Defaults to 1.
285
+ spot: Whether to run the deployment on spot instances. Defaults to None.
286
+ replicas: The number of replicas to run. Defaults to 1.
287
+ cloud_account: The cloud account to run the deployment on. Defaults to None.
288
+ port: The port to run the deployment on. Defaults to 8000.
289
+ include_credentials: Whether to include credentials in the deployment. Defaults to True.
290
+
291
+ Returns:
292
+ dict: The deployment and the URL of the deployment.
293
+ """
232
294
  url = f"{_get_cloud_url()}/{teamspace.owner.name}/{teamspace.name}/jobs/{deployment_name}"
233
295
  machine = machine or Machine.CPU
234
296
  metric = metric or ("CPU" if machine.is_cpu() else "GPU")
235
297
  deployment = Deployment(deployment_name, teamspace)
236
298
  if deployment.is_started:
237
- raise RuntimeError(
238
- f"Deployment with name {deployment_name} already running. "
239
- "Please stop the deployment before starting a new one.\n"
240
- f"You can access the deployment at {url}"
299
+ self._console.print(f"Deployment with name {deployment_name} already running. Updating the deployment.")
300
+ self._update_deployment(
301
+ deployment,
302
+ machine,
303
+ image,
304
+ min_replica=min_replica,
305
+ max_replica=max_replica,
306
+ spot=spot,
307
+ replicas=replicas,
308
+ cloud_account=cloud_account,
309
+ port=port,
310
+ include_credentials=include_credentials,
241
311
  )
312
+ return {"deployment": deployment, "url": url, "updated": True}
242
313
  autoscale = AutoScaleConfig(min_replicas=min_replica, max_replicas=max_replica, metric=metric, threshold=0.95)
243
314
  deployment.start(
244
315
  machine=machine,
@@ -243,7 +243,7 @@ class Teamspace:
243
243
 
244
244
  def upload_model(
245
245
  self,
246
- path: Union[str, Path],
246
+ path: Union[str, Path, List[Union[str, Path]]],
247
247
  name: str,
248
248
  cloud_account: Optional[str] = None,
249
249
  progress_bar: bool = True,
@@ -261,30 +261,33 @@ class Teamspace:
261
261
  raise ValueError("No path provided to upload")
262
262
  if not name:
263
263
  raise ValueError("No name provided for the model")
264
- path = Path(path).resolve()
265
- if not path.exists():
266
- raise FileNotFoundError(str(path))
267
264
 
268
- cloud_account = (
269
- self._teamspace_api._determine_cloud_account(self.id) if cloud_account is None else cloud_account
270
- )
271
- filepaths = [path] if path.is_file() else [p for p in path.rglob("*") if p.is_file()]
265
+ if isinstance(path, (str, Path)):
266
+ path = [path]
267
+ file_paths, relative_paths = [], []
268
+ for p in path:
269
+ lpaths, rpaths = _list_files(p)
270
+ file_paths.extend(lpaths)
271
+ relative_paths.extend(rpaths)
272
272
 
273
- if not filepaths:
273
+ if not file_paths:
274
274
  raise FileNotFoundError(
275
275
  "The path to upload doesn't contain any files. Make sure it points to a file or"
276
276
  f" non-empty folder: {path}"
277
277
  )
278
+ if len(relative_paths) != len(set(relative_paths)):
279
+ raise RuntimeError(
280
+ "The paths to upload contain files with the same name or relative path in folders."
281
+ f"The listed files are: {file_paths}\nThe relative paths are: {relative_paths}"
282
+ )
278
283
 
279
- root_path = path
280
- if len(filepaths) == 1:
281
- root_path = path.parent
282
-
283
- filenames = ",".join(str(f.relative_to(root_path)) for f in filepaths)
284
+ cloud_account = (
285
+ self._teamspace_api._determine_cloud_account(self.id) if cloud_account is None else cloud_account
286
+ )
284
287
 
285
288
  model = self._teamspace_api.create_model(
286
289
  name=name,
287
- metadata={"filenames": filenames},
290
+ metadata={"filenames": ",".join(relative_paths)},
288
291
  private=True,
289
292
  teamspace_id=self.id,
290
293
  cloud_account=cloud_account,
@@ -292,9 +295,8 @@ class Teamspace:
292
295
  self._teamspace_api.upload_model_files(
293
296
  model_id=model.model_id,
294
297
  version=model.version,
295
- root_path=root_path,
296
- filepaths=filepaths,
297
- cloud_account=cloud_account,
298
+ file_paths=file_paths,
299
+ remote_paths=relative_paths,
298
300
  teamspace_id=self.id,
299
301
  progress_bar=progress_bar,
300
302
  )
@@ -371,6 +373,18 @@ class Teamspace:
371
373
  self._teamspace_api.delete_model(name=name, version=version, teamspace_id=self.id)
372
374
 
373
375
 
376
+ def _list_files(path: Union[str, Path]) -> Tuple[List[Path], List[str]]:
377
+ """List all folders in a directory and return them as a list and relative path."""
378
+ path = Path(path).resolve()
379
+ if not path.exists():
380
+ raise FileNotFoundError(f"Path {path} does not exist")
381
+ if not path.is_dir():
382
+ return [path], [str(path.name)]
383
+ local_paths = [p for p in path.rglob("*") if p.is_file()]
384
+ relative_paths = [str(p.relative_to(path)) for p in local_paths]
385
+ return local_paths, relative_paths
386
+
387
+
374
388
  def _resolve_valueerror_message(error: ValueError, owner: Owner, teamspace_name: str) -> ValueError:
375
389
  """Resolves the ValueError Message and replaces it with a nicer message."""
376
390
  message = error.args[0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License