lightning-sdk 0.1.48__py3-none-any.whl → 0.1.49__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 CHANGED
@@ -4,6 +4,7 @@ from lightning_sdk.constants import __GLOBAL_LIGHTNING_UNIQUE_IDS_STORE__ # noq
4
4
  from lightning_sdk.helpers import _check_version_and_prompt_upgrade
5
5
  from lightning_sdk.job import Job
6
6
  from lightning_sdk.machine import Machine
7
+ from lightning_sdk.mmt import MMT
7
8
  from lightning_sdk.organization import Organization
8
9
  from lightning_sdk.plugin import JobsPlugin, MultiMachineTrainingPlugin, Plugin, SlurmJobsPlugin
9
10
  from lightning_sdk.status import Status
@@ -15,6 +16,7 @@ __all__ = [
15
16
  "Job",
16
17
  "JobsPlugin",
17
18
  "Machine",
19
+ "MMT",
18
20
  "MultiMachineTrainingPlugin",
19
21
  "Organization",
20
22
  "Plugin",
@@ -27,5 +29,5 @@ __all__ = [
27
29
  "AIHub",
28
30
  ]
29
31
 
30
- __version__ = "0.1.48"
32
+ __version__ = "0.1.49"
31
33
  _check_version_and_prompt_upgrade(__version__)
@@ -180,6 +180,10 @@ class JobApiV1:
180
180
 
181
181
  raise RuntimeError("Could not extract command from app")
182
182
 
183
+ def get_total_cost(self, job: Externalv1LightningappInstance) -> float:
184
+ status: V1LightningappInstanceStatus = job.status
185
+ return status.total_cost
186
+
183
187
 
184
188
  class JobApiV2:
185
189
  # these are stages the job can be in.
@@ -337,3 +341,6 @@ class JobApiV2:
337
341
  return _COMPUTE_NAME_TO_MACHINE.get(
338
342
  instance_type, _COMPUTE_NAME_TO_MACHINE.get(instance_name, instance_type or instance_name)
339
343
  )
344
+
345
+ def get_total_cost(self, job: V1Job) -> float:
346
+ return job.total_cost
@@ -1,7 +1,9 @@
1
- from typing import List
1
+ from typing import Generator, List
2
2
 
3
+ from lightning_sdk.api.utils import _get_registry_url
3
4
  from lightning_sdk.lightning_cloud.openapi.models import V1DeleteLitRepositoryResponse
4
5
  from lightning_sdk.lightning_cloud.rest_client import LightningClient
6
+ from lightning_sdk.teamspace import Teamspace
5
7
 
6
8
 
7
9
  class LitContainerApi:
@@ -17,3 +19,24 @@ class LitContainerApi:
17
19
  return self._client.lit_registry_service_delete_lit_repository(project_id, container)
18
20
  except Exception as ex:
19
21
  raise ValueError(f"Could not delete container {container} from project {project_id}") from ex
22
+
23
+ def upload_container(self, container: str, teamspace: Teamspace, tag: str) -> Generator[str, None, None]:
24
+ import docker
25
+
26
+ try:
27
+ client = docker.from_env()
28
+ client.ping()
29
+ except docker.errors.DockerException as e:
30
+ raise RuntimeError(f"Failed to connect to Docker daemon: {e!s}. Is Docker running?") from None
31
+
32
+ try:
33
+ client.images.get(container)
34
+ except docker.errors.ImageNotFound:
35
+ raise ValueError(f"Container {container} does not exist") from None
36
+
37
+ registry_url = _get_registry_url()
38
+ repository = f"{registry_url}/lit-container/{teamspace.owner.name}/{teamspace.name}/{container}"
39
+ tagged = client.api.tag(container, repository, tag)
40
+ if not tagged:
41
+ raise ValueError(f"Could not tag container {container} with {repository}:{tag}")
42
+ return client.api.push(repository, stream=True, decode=True)
@@ -203,3 +203,9 @@ class MMTApiV2:
203
203
  return _COMPUTE_NAME_TO_MACHINE.get(
204
204
  instance_type, _COMPUTE_NAME_TO_MACHINE.get(instance_name, instance_type or instance_name)
205
205
  )
206
+
207
+ def get_total_cost(self, job: V1MultiMachineJob) -> float:
208
+ return job.total_cost
209
+
210
+ def get_num_machines(self, job: V1MultiMachineJob) -> int:
211
+ return job.machines
@@ -354,6 +354,7 @@ def _machine_to_compute_name(machine: Union[Machine, str]) -> str:
354
354
  _COMPUTE_NAME_TO_MACHINE: Dict[str, Machine] = {v: k for k, v in _MACHINE_TO_COMPUTE_NAME.items()}
355
355
 
356
356
  _DEFAULT_CLOUD_URL = "https://lightning.ai"
357
+ _DEFAULT_REGISTRY_URL = "litcr.io"
357
358
 
358
359
 
359
360
  def _get_cloud_url() -> str:
@@ -362,6 +363,12 @@ def _get_cloud_url() -> str:
362
363
  return cloud_url
363
364
 
364
365
 
366
+ def _get_registry_url() -> str:
367
+ registry_url = os.environ.get("LIGHTNING_REGISTRY_URL", _DEFAULT_REGISTRY_URL)
368
+ os.environ["LIGHTNING_REGISTRY_URL"] = registry_url
369
+ return registry_url
370
+
371
+
365
372
  def _sanitize_studio_remote_path(path: str, studio_id: str) -> str:
366
373
  return f"/cloudspaces/{studio_id}/code/content/{path.replace('/teamspace/studios/this_studio/', '')}"
367
374
 
@@ -1,3 +1,7 @@
1
+ import sys
2
+ from types import TracebackType
3
+ from typing import Type
4
+
1
5
  from fire import Fire
2
6
  from lightning_utilities.core.imports import RequirementCache
3
7
 
@@ -32,6 +36,8 @@ class StudioCLI:
32
36
  self.inspect = _Inspect()
33
37
  self.stop = _Stop()
34
38
 
39
+ sys.excepthook = _notify_exception
40
+
35
41
  def login(self) -> None:
36
42
  """Login to Lightning AI Studios."""
37
43
  auth = Auth()
@@ -48,6 +54,11 @@ class StudioCLI:
48
54
  auth.clear()
49
55
 
50
56
 
57
+ def _notify_exception(exception_type: Type[BaseException], value: BaseException, tb: TracebackType) -> None: # No
58
+ """CLI won't show tracebacks, just print the exception message."""
59
+ print(value)
60
+
61
+
51
62
  def main_cli() -> None:
52
63
  """CLI entrypoint."""
53
64
  Fire(StudioCLI(), name="lightning")
lightning_sdk/cli/list.py CHANGED
@@ -20,7 +20,36 @@ class _List(_TeamspacesMenu):
20
20
  """
21
21
  resolved_teamspace = self._resolve_teamspace(teamspace=teamspace)
22
22
 
23
- print("Available Jobs:\n" + "\n".join([j.name for j in resolved_teamspace.jobs]))
23
+ jobs = resolved_teamspace.jobs
24
+
25
+ table = Table(
26
+ pad_edge=True,
27
+ )
28
+ table.add_column("Name")
29
+ table.add_column("Teamspace")
30
+ table.add_column("Studio")
31
+ table.add_column("Image")
32
+ table.add_column("Status")
33
+ table.add_column("Machine")
34
+ table.add_column("Total Cost")
35
+ for j in jobs:
36
+ # we know we just fetched these, so no need to refetch
37
+ j._prevent_refetch_latest = True
38
+ j._internal_job._prevent_refetch_latest = True
39
+
40
+ studio = j.studio
41
+ table.add_row(
42
+ j.name,
43
+ f"{j.teamspace.owner.name}/{j.teamspace.name}",
44
+ studio.name if studio else None,
45
+ j.image,
46
+ str(j.status),
47
+ str(j.machine),
48
+ f"{j.total_cost:.3f}",
49
+ )
50
+
51
+ console = Console()
52
+ console.print(table)
24
53
 
25
54
  def mmts(self, teamspace: Optional[str] = None) -> None:
26
55
  """List multi-machine jobs for a given teamspace.
@@ -32,7 +61,36 @@ class _List(_TeamspacesMenu):
32
61
  """
33
62
  resolved_teamspace = self._resolve_teamspace(teamspace=teamspace)
34
63
 
35
- print("Available MMTs:\n" + "\n".join([j.name for j in resolved_teamspace.multi_machine_jobs]))
64
+ jobs = resolved_teamspace.multi_machine_jobs
65
+
66
+ table = Table(pad_edge=True)
67
+ table.add_column("Name")
68
+ table.add_column("Teamspace")
69
+ table.add_column("Studio")
70
+ table.add_column("Image")
71
+ table.add_column("Status")
72
+ table.add_column("Machine")
73
+ table.add_column("Num Machines")
74
+ table.add_column("Total Cost")
75
+ for j in jobs:
76
+ # we know we just fetched these, so no need to refetch
77
+ j._prevent_refetch_latest = True
78
+ j._internal_job._prevent_refetch_latest = True
79
+
80
+ studio = j.studio
81
+ table.add_row(
82
+ j.name,
83
+ f"{j.teamspace.owner.name}/{j.teamspace.name}",
84
+ studio.name if studio else None,
85
+ j.image,
86
+ str(j.status),
87
+ str(j.machine),
88
+ str(j.num_machines),
89
+ str(j.total_cost),
90
+ )
91
+
92
+ console = Console()
93
+ console.print(table)
36
94
 
37
95
  def containers(self, teamspace: Optional[str] = None) -> None:
38
96
  """Display the list of available containers.
lightning_sdk/cli/run.py CHANGED
@@ -111,7 +111,7 @@ class _Run:
111
111
  # might need to move to different cli library
112
112
  def job(
113
113
  self,
114
- name: str,
114
+ name: Optional[str] = None,
115
115
  machine: Optional[str] = None,
116
116
  command: Optional[str] = None,
117
117
  studio: Optional[str] = None,
@@ -128,16 +128,23 @@ class _Run:
128
128
  artifacts_remote: Optional[str] = None,
129
129
  entrypoint: str = "sh -c",
130
130
  ) -> None:
131
+ if not name:
132
+ from datetime import datetime
133
+
134
+ timestr = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
135
+ name = f"job-{timestr}"
136
+
131
137
  if machine is None:
132
138
  # TODO: infer from studio
133
139
  machine = "CPU"
134
- machine_enum = Machine(machine.upper())
140
+ machine_enum = Machine[machine.upper()]
135
141
 
136
142
  resolved_teamspace = Teamspace(name=teamspace, org=org, user=user)
137
143
 
138
144
  if cloud_account is None:
139
145
  cloud_account = resolved_teamspace.default_cloud_account
140
146
  machine_enum = Machine(machine.upper())
147
+
141
148
  Job.run(
142
149
  name=name,
143
150
  machine=machine_enum,
@@ -188,7 +195,7 @@ class _Run:
188
195
  if machine is None:
189
196
  # TODO: infer from studio
190
197
  machine = "CPU"
191
- machine_enum = Machine(machine.upper())
198
+ machine_enum = Machine[machine.upper()]
192
199
 
193
200
  resolved_teamspace = Teamspace(name=teamspace, org=org, user=user)
194
201
  if cloud_account is None:
@@ -4,18 +4,22 @@ import os
4
4
  from pathlib import Path
5
5
  from typing import Dict, List, Optional
6
6
 
7
+ from rich.console import Console
8
+ from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
7
9
  from simple_term_menu import TerminalMenu
8
10
  from tqdm import tqdm
9
11
 
12
+ from lightning_sdk.api.lit_container_api import LitContainerApi
10
13
  from lightning_sdk.api.utils import _get_cloud_url
11
14
  from lightning_sdk.cli.exceptions import StudioCliError
12
15
  from lightning_sdk.cli.studios_menu import _StudiosMenu
16
+ from lightning_sdk.cli.teamspace_menu import _TeamspacesMenu
13
17
  from lightning_sdk.models import upload_model
14
18
  from lightning_sdk.studio import Studio
15
19
  from lightning_sdk.utils.resolve import _get_authed_user, skip_studio_init
16
20
 
17
21
 
18
- class _Uploads(_StudiosMenu):
22
+ class _Uploads(_StudiosMenu, _TeamspacesMenu):
19
23
  """Upload files and folders to Lightning AI."""
20
24
 
21
25
  _studio_upload_status_path = "~/.lightning/studios/uploads"
@@ -146,6 +150,33 @@ class _Uploads(_StudiosMenu):
146
150
  )
147
151
  print(f"See your file at {studio_url}")
148
152
 
153
+ def container(self, container: str, tag: str = "latest", teamspace: Optional[str] = None) -> None:
154
+ teamspace = self._resolve_teamspace(teamspace)
155
+ api = LitContainerApi()
156
+ console = Console()
157
+ with Progress(
158
+ SpinnerColumn(),
159
+ TextColumn("[progress.description]{task.description}"),
160
+ TimeElapsedColumn(),
161
+ console=console,
162
+ transient=False,
163
+ ) as progress:
164
+ push_task = progress.add_task("Pushing Docker image", total=None)
165
+ resp = api.upload_container(container, teamspace, tag)
166
+ for line in resp:
167
+ if "status" in line:
168
+ console.print(line["status"], style="bright_black")
169
+ progress.update(push_task, description="Pushing Docker image")
170
+ elif "aux" in line:
171
+ console.print(line["aux"], style="bright_black")
172
+ elif "error" in line:
173
+ progress.stop()
174
+ console.print(f"\n[red]{line}[/red]")
175
+ return
176
+ else:
177
+ console.print(line, style="bright_black")
178
+ progress.update(push_task, description="[green]Container pushed![/green]")
179
+
149
180
  def _start_parallel_upload(
150
181
  self, executor: concurrent.futures.ThreadPoolExecutor, studio: Studio, upload_state: Dict[str, str]
151
182
  ) -> List[concurrent.futures.Future]:
lightning_sdk/job/base.py CHANGED
@@ -24,6 +24,7 @@ class JobDict(MachineDict):
24
24
  teamspace: str
25
25
  studio: Optional[str]
26
26
  image: Optional[str]
27
+ total_cost: float
27
28
 
28
29
 
29
30
  class _BaseJob(ABC):
@@ -61,6 +62,8 @@ class _BaseJob(ABC):
61
62
  if _fetch_job:
62
63
  self._update_internal_job()
63
64
 
65
+ self._prevent_refetch_latest = False
66
+
64
67
  @classmethod
65
68
  def run(
66
69
  cls,
@@ -332,6 +335,7 @@ class _BaseJob(ABC):
332
335
  "command": self.command,
333
336
  "status": self.status,
334
337
  "machine": self.machine,
338
+ "total_cost": self.total_cost,
335
339
  }
336
340
 
337
341
  def json(self) -> str:
@@ -361,3 +365,18 @@ class _BaseJob(ABC):
361
365
  self._update_internal_job()
362
366
 
363
367
  return self._job
368
+
369
+ @property
370
+ def total_cost(self) -> float:
371
+ """The number of credits the job was consuming so far."""
372
+ return self._job_api.get_total_cost(self._latest_job)
373
+
374
+ @property
375
+ def _latest_job(self) -> Any:
376
+ """Guarantees to fetch the latest version of a job before returning it."""
377
+ # in some cases we know we just refetched the latest state, no need to refetch again
378
+ if self._prevent_refetch_latest:
379
+ return self._guaranteed_job
380
+
381
+ self._update_internal_job()
382
+ return self._job
lightning_sdk/job/v1.py CHANGED
@@ -174,7 +174,7 @@ class _JobV1(_BaseJob):
174
174
 
175
175
  def stop(self) -> None:
176
176
  """Stops the job. is blocking until the ob is stopped."""
177
- if self.status in (Status.Stopped, Status.Failed):
177
+ if self.status in (Status.Stopped, Status.Completed, Status.Failed):
178
178
  return None
179
179
 
180
180
  return self._job_api.stop_job(self._job.id, self.teamspace.id)
lightning_sdk/job/v2.py CHANGED
@@ -1,13 +1,13 @@
1
- from typing import TYPE_CHECKING, Any, Dict, Optional, Union
1
+ from typing import TYPE_CHECKING, Dict, Optional, Union
2
2
 
3
3
  from lightning_sdk.api.job_api import JobApiV2
4
4
  from lightning_sdk.api.utils import _get_cloud_url
5
5
  from lightning_sdk.job.base import _BaseJob
6
+ from lightning_sdk.status import Status
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from lightning_sdk.machine import Machine
9
10
  from lightning_sdk.organization import Organization
10
- from lightning_sdk.status import Status
11
11
  from lightning_sdk.studio import Studio
12
12
  from lightning_sdk.teamspace import Teamspace
13
13
  from lightning_sdk.user import User
@@ -121,6 +121,9 @@ class _JobV2(_BaseJob):
121
121
 
122
122
  def stop(self) -> None:
123
123
  """Stop the job. If the job is already stopped, this is a no-op. This is blocking until the job is stopped."""
124
+ if self.status in (Status.Stopped, Status.Completed, Status.Failed):
125
+ return
126
+
124
127
  self._job_api.stop_job(job_id=self._guaranteed_job.id, teamspace_id=self._teamspace.id)
125
128
 
126
129
  def delete(self) -> None:
@@ -134,12 +137,6 @@ class _JobV2(_BaseJob):
134
137
  cloudspace_id=self._guaranteed_job.spec.cloudspace_id,
135
138
  )
136
139
 
137
- @property
138
- def _latest_job(self) -> Any:
139
- """Guarantees to fetch the latest version of a job before returning it."""
140
- self._update_internal_job()
141
- return self._job
142
-
143
140
  @property
144
141
  def status(self) -> "Status":
145
142
  """The current status of the job."""
@@ -42,7 +42,6 @@ class V1ClusterSpec(object):
42
42
  """
43
43
  swagger_types = {
44
44
  'auth_token': 'str',
45
- 'available_instance_types': 'list[str]',
46
45
  'aws_v1': 'V1AWSDirectV1',
47
46
  'cluster_type': 'V1ClusterType',
48
47
  'deletion_options': 'V1ClusterDeletionOptions',
@@ -63,7 +62,6 @@ class V1ClusterSpec(object):
63
62
 
64
63
  attribute_map = {
65
64
  'auth_token': 'authToken',
66
- 'available_instance_types': 'availableInstanceTypes',
67
65
  'aws_v1': 'awsV1',
68
66
  'cluster_type': 'clusterType',
69
67
  'deletion_options': 'deletionOptions',
@@ -82,10 +80,9 @@ class V1ClusterSpec(object):
82
80
  'vultr_v1': 'vultrV1'
83
81
  }
84
82
 
85
- def __init__(self, auth_token: 'str' =None, available_instance_types: 'list[str]' =None, aws_v1: 'V1AWSDirectV1' =None, cluster_type: 'V1ClusterType' =None, deletion_options: 'V1ClusterDeletionOptions' =None, desired_state: 'V1ClusterState' =None, domain: 'str' =None, freeze_accelerators: 'bool' =None, google_cloud_v1: 'V1GoogleCloudDirectV1' =None, insurer_disabled: 'bool' =None, lambda_labs_v1: 'V1LambdaLabsDirectV1' =None, overprovisioning: 'list[V1InstanceOverprovisioningSpec]' =None, pause_automation: 'bool' =None, security_options: 'V1ClusterSecurityOptions' =None, slurm_v1: 'V1SlurmV1' =None, tagging_options: 'V1ClusterTaggingOptions' =None, user_id: 'str' =None, vultr_v1: 'V1VultrDirectV1' =None): # noqa: E501
83
+ def __init__(self, auth_token: 'str' =None, aws_v1: 'V1AWSDirectV1' =None, cluster_type: 'V1ClusterType' =None, deletion_options: 'V1ClusterDeletionOptions' =None, desired_state: 'V1ClusterState' =None, domain: 'str' =None, freeze_accelerators: 'bool' =None, google_cloud_v1: 'V1GoogleCloudDirectV1' =None, insurer_disabled: 'bool' =None, lambda_labs_v1: 'V1LambdaLabsDirectV1' =None, overprovisioning: 'list[V1InstanceOverprovisioningSpec]' =None, pause_automation: 'bool' =None, security_options: 'V1ClusterSecurityOptions' =None, slurm_v1: 'V1SlurmV1' =None, tagging_options: 'V1ClusterTaggingOptions' =None, user_id: 'str' =None, vultr_v1: 'V1VultrDirectV1' =None): # noqa: E501
86
84
  """V1ClusterSpec - a model defined in Swagger""" # noqa: E501
87
85
  self._auth_token = None
88
- self._available_instance_types = None
89
86
  self._aws_v1 = None
90
87
  self._cluster_type = None
91
88
  self._deletion_options = None
@@ -105,8 +102,6 @@ class V1ClusterSpec(object):
105
102
  self.discriminator = None
106
103
  if auth_token is not None:
107
104
  self.auth_token = auth_token
108
- if available_instance_types is not None:
109
- self.available_instance_types = available_instance_types
110
105
  if aws_v1 is not None:
111
106
  self.aws_v1 = aws_v1
112
107
  if cluster_type is not None:
@@ -161,29 +156,6 @@ class V1ClusterSpec(object):
161
156
 
162
157
  self._auth_token = auth_token
163
158
 
164
- @property
165
- def available_instance_types(self) -> 'list[str]':
166
- """Gets the available_instance_types of this V1ClusterSpec. # noqa: E501
167
-
168
- available_instance_types is a list of instance types that are available for the cluster. This is just a soft filter to prevent users from using instances that we haven't prepared for. If the list is empty, no filtering is done. # noqa: E501
169
-
170
- :return: The available_instance_types of this V1ClusterSpec. # noqa: E501
171
- :rtype: list[str]
172
- """
173
- return self._available_instance_types
174
-
175
- @available_instance_types.setter
176
- def available_instance_types(self, available_instance_types: 'list[str]'):
177
- """Sets the available_instance_types of this V1ClusterSpec.
178
-
179
- available_instance_types is a list of instance types that are available for the cluster. This is just a soft filter to prevent users from using instances that we haven't prepared for. If the list is empty, no filtering is done. # noqa: E501
180
-
181
- :param available_instance_types: The available_instance_types of this V1ClusterSpec. # noqa: E501
182
- :type: list[str]
183
- """
184
-
185
- self._available_instance_types = available_instance_types
186
-
187
159
  @property
188
160
  def aws_v1(self) -> 'V1AWSDirectV1':
189
161
  """Gets the aws_v1 of this V1ClusterSpec. # noqa: E501
@@ -41,19 +41,24 @@ class V1LambdaLabsDirectV1(object):
41
41
  and the value is json key in definition.
42
42
  """
43
43
  swagger_types = {
44
- 'credentials_secret_id': 'str'
44
+ 'credentials_secret_id': 'str',
45
+ 'parent_cluster_id': 'str'
45
46
  }
46
47
 
47
48
  attribute_map = {
48
- 'credentials_secret_id': 'credentialsSecretId'
49
+ 'credentials_secret_id': 'credentialsSecretId',
50
+ 'parent_cluster_id': 'parentClusterId'
49
51
  }
50
52
 
51
- def __init__(self, credentials_secret_id: 'str' =None): # noqa: E501
53
+ def __init__(self, credentials_secret_id: 'str' =None, parent_cluster_id: 'str' =None): # noqa: E501
52
54
  """V1LambdaLabsDirectV1 - a model defined in Swagger""" # noqa: E501
53
55
  self._credentials_secret_id = None
56
+ self._parent_cluster_id = None
54
57
  self.discriminator = None
55
58
  if credentials_secret_id is not None:
56
59
  self.credentials_secret_id = credentials_secret_id
60
+ if parent_cluster_id is not None:
61
+ self.parent_cluster_id = parent_cluster_id
57
62
 
58
63
  @property
59
64
  def credentials_secret_id(self) -> 'str':
@@ -78,6 +83,29 @@ class V1LambdaLabsDirectV1(object):
78
83
 
79
84
  self._credentials_secret_id = credentials_secret_id
80
85
 
86
+ @property
87
+ def parent_cluster_id(self) -> 'str':
88
+ """Gets the parent_cluster_id of this V1LambdaLabsDirectV1. # noqa: E501
89
+
90
+ Note: LambdaLabs is missing object store in their offering, we will need to use either GCP or AWS S3 for that. # noqa: E501
91
+
92
+ :return: The parent_cluster_id of this V1LambdaLabsDirectV1. # noqa: E501
93
+ :rtype: str
94
+ """
95
+ return self._parent_cluster_id
96
+
97
+ @parent_cluster_id.setter
98
+ def parent_cluster_id(self, parent_cluster_id: 'str'):
99
+ """Sets the parent_cluster_id of this V1LambdaLabsDirectV1.
100
+
101
+ Note: LambdaLabs is missing object store in their offering, we will need to use either GCP or AWS S3 for that. # noqa: E501
102
+
103
+ :param parent_cluster_id: The parent_cluster_id of this V1LambdaLabsDirectV1. # noqa: E501
104
+ :type: str
105
+ """
106
+
107
+ self._parent_cluster_id = parent_cluster_id
108
+
81
109
  def to_dict(self) -> dict:
82
110
  """Returns the model properties as a dict"""
83
111
  result = {}
@@ -120,6 +120,7 @@ class V1UserFeatures(object):
120
120
  'teamspace_storage_tab': 'bool',
121
121
  'trainium2': 'bool',
122
122
  'use_rclone_mounts_only': 'bool',
123
+ 'vultr': 'bool',
123
124
  'writable_data_connections': 'bool'
124
125
  }
125
126
 
@@ -203,10 +204,11 @@ class V1UserFeatures(object):
203
204
  'teamspace_storage_tab': 'teamspaceStorageTab',
204
205
  'trainium2': 'trainium2',
205
206
  'use_rclone_mounts_only': 'useRcloneMountsOnly',
207
+ 'vultr': 'vultr',
206
208
  'writable_data_connections': 'writableDataConnections'
207
209
  }
208
210
 
209
- def __init__(self, advanced_deployment_autoscaling: 'bool' =None, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, custom_instance_types: 'bool' =None, default_one_cluster: 'bool' =None, deployment_customize_api: 'bool' =None, deployment_data_path: 'bool' =None, deployment_gallery: 'bool' =None, deployment_persistent_disk: 'bool' =None, deployment_version_visibility: 'bool' =None, docs_agent: 'bool' =None, drive_v2: 'bool' =None, enable_crypto_crackdown: 'bool' =None, enable_efs: 'bool' =None, enable_storage_limits: 'bool' =None, featured_studios_admin: 'bool' =None, filesystem_optimisation: 'bool' =None, gcp: 'bool' =None, inference_job_deployment_plugin: 'bool' =None, instant_capacity_reservation: 'bool' =None, jobs_init: 'bool' =None, jobs_v2: 'bool' =None, landing_studios: 'bool' =None, lightning_registry: 'bool' =None, lit_logger: 'bool' =None, lit_logger_storage_v2: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, mmt_v2: 'bool' =None, model_store: 'bool' =None, multiple_deployment_versions: 'bool' =None, multiple_studio_versions: 'bool' =None, org_level_member_permissions: 'bool' =None, pipelines: 'bool' =None, plugin_biz_chat: 'bool' =None, plugin_distributed: 'bool' =None, plugin_fiftyone: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_lightning_apps: 'bool' =None, plugin_lightning_apps_distributed: 'bool' =None, plugin_mage_ai: 'bool' =None, plugin_milvus: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_react: 'bool' =None, plugin_service: 'bool' =None, plugin_sweeps: 'bool' =None, plugin_weviate: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, project_selector: 'bool' =None, restart_ide_on_hang: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, show_dev_admin: 'bool' =None, slurm: 'bool' =None, slurm_machine_selector: 'bool' =None, snapshotter_service: 'bool' =None, snowflake_connection: 'bool' =None, spot_v2: 'bool' =None, studio_config: 'bool' =None, studio_on_stop: 'bool' =None, studio_version_visibility: 'bool' =None, teamspace_storage_tab: 'bool' =None, trainium2: 'bool' =None, use_rclone_mounts_only: 'bool' =None, writable_data_connections: 'bool' =None): # noqa: E501
211
+ def __init__(self, advanced_deployment_autoscaling: 'bool' =None, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, custom_instance_types: 'bool' =None, default_one_cluster: 'bool' =None, deployment_customize_api: 'bool' =None, deployment_data_path: 'bool' =None, deployment_gallery: 'bool' =None, deployment_persistent_disk: 'bool' =None, deployment_version_visibility: 'bool' =None, docs_agent: 'bool' =None, drive_v2: 'bool' =None, enable_crypto_crackdown: 'bool' =None, enable_efs: 'bool' =None, enable_storage_limits: 'bool' =None, featured_studios_admin: 'bool' =None, filesystem_optimisation: 'bool' =None, gcp: 'bool' =None, inference_job_deployment_plugin: 'bool' =None, instant_capacity_reservation: 'bool' =None, jobs_init: 'bool' =None, jobs_v2: 'bool' =None, landing_studios: 'bool' =None, lightning_registry: 'bool' =None, lit_logger: 'bool' =None, lit_logger_storage_v2: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, mmt_v2: 'bool' =None, model_store: 'bool' =None, multiple_deployment_versions: 'bool' =None, multiple_studio_versions: 'bool' =None, org_level_member_permissions: 'bool' =None, pipelines: 'bool' =None, plugin_biz_chat: 'bool' =None, plugin_distributed: 'bool' =None, plugin_fiftyone: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_lightning_apps: 'bool' =None, plugin_lightning_apps_distributed: 'bool' =None, plugin_mage_ai: 'bool' =None, plugin_milvus: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_react: 'bool' =None, plugin_service: 'bool' =None, plugin_sweeps: 'bool' =None, plugin_weviate: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, project_selector: 'bool' =None, restart_ide_on_hang: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, show_dev_admin: 'bool' =None, slurm: 'bool' =None, slurm_machine_selector: 'bool' =None, snapshotter_service: 'bool' =None, snowflake_connection: 'bool' =None, spot_v2: 'bool' =None, studio_config: 'bool' =None, studio_on_stop: 'bool' =None, studio_version_visibility: 'bool' =None, teamspace_storage_tab: 'bool' =None, trainium2: 'bool' =None, use_rclone_mounts_only: 'bool' =None, vultr: 'bool' =None, writable_data_connections: 'bool' =None): # noqa: E501
210
212
  """V1UserFeatures - a model defined in Swagger""" # noqa: E501
211
213
  self._advanced_deployment_autoscaling = None
212
214
  self._affiliate_links = None
@@ -287,6 +289,7 @@ class V1UserFeatures(object):
287
289
  self._teamspace_storage_tab = None
288
290
  self._trainium2 = None
289
291
  self._use_rclone_mounts_only = None
292
+ self._vultr = None
290
293
  self._writable_data_connections = None
291
294
  self.discriminator = None
292
295
  if advanced_deployment_autoscaling is not None:
@@ -447,6 +450,8 @@ class V1UserFeatures(object):
447
450
  self.trainium2 = trainium2
448
451
  if use_rclone_mounts_only is not None:
449
452
  self.use_rclone_mounts_only = use_rclone_mounts_only
453
+ if vultr is not None:
454
+ self.vultr = vultr
450
455
  if writable_data_connections is not None:
451
456
  self.writable_data_connections = writable_data_connections
452
457
 
@@ -2109,6 +2114,27 @@ class V1UserFeatures(object):
2109
2114
 
2110
2115
  self._use_rclone_mounts_only = use_rclone_mounts_only
2111
2116
 
2117
+ @property
2118
+ def vultr(self) -> 'bool':
2119
+ """Gets the vultr of this V1UserFeatures. # noqa: E501
2120
+
2121
+
2122
+ :return: The vultr of this V1UserFeatures. # noqa: E501
2123
+ :rtype: bool
2124
+ """
2125
+ return self._vultr
2126
+
2127
+ @vultr.setter
2128
+ def vultr(self, vultr: 'bool'):
2129
+ """Sets the vultr of this V1UserFeatures.
2130
+
2131
+
2132
+ :param vultr: The vultr of this V1UserFeatures. # noqa: E501
2133
+ :type: bool
2134
+ """
2135
+
2136
+ self._vultr = vultr
2137
+
2112
2138
  @property
2113
2139
  def writable_data_connections(self) -> 'bool':
2114
2140
  """Gets the writable_data_connections of this V1UserFeatures. # noqa: E501
@@ -42,24 +42,29 @@ class V1VultrDirectV1(object):
42
42
  """
43
43
  swagger_types = {
44
44
  'credentials_secret_id': 'str',
45
+ 'parent_cluster_id': 'str',
45
46
  'primary_region': 'str',
46
47
  'regions': 'list[str]'
47
48
  }
48
49
 
49
50
  attribute_map = {
50
51
  'credentials_secret_id': 'credentialsSecretId',
52
+ 'parent_cluster_id': 'parentClusterId',
51
53
  'primary_region': 'primaryRegion',
52
54
  'regions': 'regions'
53
55
  }
54
56
 
55
- def __init__(self, credentials_secret_id: 'str' =None, primary_region: 'str' =None, regions: 'list[str]' =None): # noqa: E501
57
+ def __init__(self, credentials_secret_id: 'str' =None, parent_cluster_id: 'str' =None, primary_region: 'str' =None, regions: 'list[str]' =None): # noqa: E501
56
58
  """V1VultrDirectV1 - a model defined in Swagger""" # noqa: E501
57
59
  self._credentials_secret_id = None
60
+ self._parent_cluster_id = None
58
61
  self._primary_region = None
59
62
  self._regions = None
60
63
  self.discriminator = None
61
64
  if credentials_secret_id is not None:
62
65
  self.credentials_secret_id = credentials_secret_id
66
+ if parent_cluster_id is not None:
67
+ self.parent_cluster_id = parent_cluster_id
63
68
  if primary_region is not None:
64
69
  self.primary_region = primary_region
65
70
  if regions is not None:
@@ -88,6 +93,27 @@ class V1VultrDirectV1(object):
88
93
 
89
94
  self._credentials_secret_id = credentials_secret_id
90
95
 
96
+ @property
97
+ def parent_cluster_id(self) -> 'str':
98
+ """Gets the parent_cluster_id of this V1VultrDirectV1. # noqa: E501
99
+
100
+
101
+ :return: The parent_cluster_id of this V1VultrDirectV1. # noqa: E501
102
+ :rtype: str
103
+ """
104
+ return self._parent_cluster_id
105
+
106
+ @parent_cluster_id.setter
107
+ def parent_cluster_id(self, parent_cluster_id: 'str'):
108
+ """Sets the parent_cluster_id of this V1VultrDirectV1.
109
+
110
+
111
+ :param parent_cluster_id: The parent_cluster_id of this V1VultrDirectV1. # noqa: E501
112
+ :type: str
113
+ """
114
+
115
+ self._parent_cluster_id = parent_cluster_id
116
+
91
117
  @property
92
118
  def primary_region(self) -> 'str':
93
119
  """Gets the primary_region of this V1VultrDirectV1. # noqa: E501
@@ -55,3 +55,24 @@ class LitContainer:
55
55
  raise ValueError("Could not resolve teamspace") from e
56
56
  project_id = teamspace.id
57
57
  return self._api.delete_container(project_id, container)
58
+
59
+ def upload_container(
60
+ self, container: str, teamspace: str, org: Optional[str] = None, user: Optional[str] = None, tag: str = "latest"
61
+ ) -> None:
62
+ """Upload a container to the docker registry.
63
+
64
+ Args:
65
+ container: The name of the container to upload.
66
+ teamspace: The teamspace which contains the container.
67
+ org: The organization which contains the container.
68
+ user: The user which contains the container.
69
+ tag: The tag to use for the container.
70
+ """
71
+ try:
72
+ teamspace = _resolve_teamspace(teamspace=teamspace, org=org, user=user)
73
+ except Exception as e:
74
+ raise ValueError(f"Could not resolve teamspace: {e}") from e
75
+
76
+ resp = self._api.upload_container(container, teamspace, tag)
77
+ for line in resp:
78
+ print(line)
lightning_sdk/mmt/base.py CHANGED
@@ -250,6 +250,11 @@ class _BaseMMT(_BaseJob):
250
250
  def machines(self) -> Tuple[MMTMachine, ...]:
251
251
  """Returns the sub-jobs for each individual instance."""
252
252
 
253
+ @property
254
+ def num_machines(self) -> int:
255
+ """Returns the number of machines assigned to this multi-machine job."""
256
+ return len(self.machines)
257
+
253
258
  @property
254
259
  @abstractmethod
255
260
  def machine(self) -> "Machine":
@@ -303,7 +308,18 @@ class _BaseMMT(_BaseJob):
303
308
 
304
309
  def dict(
305
310
  self
306
- ) -> Dict[str, Union[str, "Studio", "Status", "Machine", None, List[Dict[str, Union[str, "Status", "Machine"]]]]]:
311
+ ) -> Dict[
312
+ str,
313
+ Union[
314
+ str,
315
+ float,
316
+ "Studio",
317
+ "Status",
318
+ "Machine",
319
+ None,
320
+ List[Dict[str, Union[str, "Status", "Machine"]]],
321
+ ],
322
+ ]:
307
323
  """Dict representation of this job."""
308
324
  studio = self.studio
309
325
 
@@ -319,6 +335,7 @@ class _BaseMMT(_BaseJob):
319
335
  {"name": d["name"], "status": d["status"], "machine": d["machine"]}
320
336
  for d in (x.dict() for x in self.machines)
321
337
  ],
338
+ "total_cost": self.total_cost,
322
339
  }
323
340
 
324
341
  @abstractmethod
lightning_sdk/mmt/v1.py CHANGED
@@ -4,11 +4,11 @@ from lightning_sdk.api.mmt_api import MMTApiV1
4
4
  from lightning_sdk.api.utils import _get_cloud_url
5
5
  from lightning_sdk.job.v1 import _internal_status_to_external_status
6
6
  from lightning_sdk.job.work import Work
7
+ from lightning_sdk.status import Status
7
8
 
8
9
  if TYPE_CHECKING:
9
10
  from lightning_sdk.machine import Machine
10
11
  from lightning_sdk.organization import Organization
11
- from lightning_sdk.status import Status
12
12
  from lightning_sdk.studio import Studio
13
13
  from lightning_sdk.teamspace import Teamspace
14
14
  from lightning_sdk.user import User
@@ -133,6 +133,8 @@ class _MMTV1(_BaseMMT):
133
133
 
134
134
  def stop(self) -> None:
135
135
  """Stops the job."""
136
+ if self.status in (Status.Stopped, Status.Completed, Status.Failed):
137
+ return
136
138
  self._job_api.stop_job(self._guaranteed_job.id, self.teamspace.id)
137
139
 
138
140
  def delete(self) -> None:
lightning_sdk/mmt/v2.py CHANGED
@@ -1,13 +1,13 @@
1
- from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
1
+ from typing import TYPE_CHECKING, Dict, Optional, Tuple, Union
2
2
 
3
3
  from lightning_sdk.api.mmt_api import MMTApiV2
4
4
  from lightning_sdk.api.utils import _get_cloud_url
5
+ from lightning_sdk.status import Status
5
6
 
6
7
  if TYPE_CHECKING:
7
8
  from lightning_sdk.job.job import Job
8
9
  from lightning_sdk.machine import Machine
9
10
  from lightning_sdk.organization import Organization
10
- from lightning_sdk.status import Status
11
11
  from lightning_sdk.studio import Studio
12
12
  from lightning_sdk.teamspace import Teamspace
13
13
  from lightning_sdk.user import User
@@ -137,6 +137,8 @@ class _MMTV2(_BaseMMT):
137
137
 
138
138
  def stop(self) -> None:
139
139
  """Stops the job."""
140
+ if self.status in (Status.Stopped, Status.Completed, Status.Failed):
141
+ return
140
142
  self._job_api.stop_job(job_id=self._guaranteed_job.id, teamspace_id=self._teamspace.id)
141
143
 
142
144
  def delete(self) -> None:
@@ -149,12 +151,6 @@ class _MMTV2(_BaseMMT):
149
151
  teamspace_id=self._teamspace.id,
150
152
  )
151
153
 
152
- @property
153
- def _latest_job(self) -> Any:
154
- """Guarantees to fetch the latest version of a job before returning it."""
155
- self._update_internal_job()
156
- return self._job
157
-
158
154
  @property
159
155
  def status(self) -> "Status":
160
156
  """The current status of the job."""
@@ -220,3 +216,8 @@ class _MMTV2(_BaseMMT):
220
216
  def command(self) -> str:
221
217
  """The command the job is running."""
222
218
  return self._job_api.get_command(self._guaranteed_job)
219
+
220
+ @property
221
+ def num_machines(self) -> int:
222
+ """Returns the number of machines assigned to this multi-machine job."""
223
+ return self._job_api.get_num_machines(self._guaranteed_job)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.1.48
3
+ Version: 0.1.49
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License
@@ -1,10 +1,10 @@
1
1
  docs/source/conf.py,sha256=r8yX20eC-4mHhMTd0SbQb5TlSWHhO6wnJ0VJ_FBFpag,13249
2
- lightning_sdk/__init__.py,sha256=e-z42Ud9d3en8_MesDM8ZmP-uq7DC8lW5Y0dMWI9IUM,925
2
+ lightning_sdk/__init__.py,sha256=pghaQ6_YR2SmOR4N7VM5mlRGqecB5VgWJpqV0JMLxiE,970
3
3
  lightning_sdk/agents.py,sha256=ly6Ma1j0ZgGPFyvPvMN28JWiB9dATIstFa5XM8pMi6I,1577
4
4
  lightning_sdk/ai_hub.py,sha256=kBjtmrzVHPCgqtV_TrSNkuf4oT2DLm8SYRTz4iTQmmY,6624
5
5
  lightning_sdk/constants.py,sha256=ztl1PTUBULnqTf3DyKUSJaV_O20hNtUYT6XvAYIrmIk,749
6
6
  lightning_sdk/helpers.py,sha256=RnQwUquc_YPotjh6YXOoJvZs8krX_QFhd7kGv4U_spQ,1844
7
- lightning_sdk/lit_container.py,sha256=MLdhLtKjRICDikdXfFUMAW39kC-oC9IONGUv2yh8gRU,2090
7
+ lightning_sdk/lit_container.py,sha256=Yh24NmVBsixKSYIZ_p0QqcZ0kjJO58OvXYDLC7ptx8w,2954
8
8
  lightning_sdk/machine.py,sha256=qutfVwQJHC02c2ygB_O5wrFI-Eq9zbfA0E1OPEYcCO0,861
9
9
  lightning_sdk/models.py,sha256=d27VAYUcbWKd4kuL_CqwCi3IguyjmKUR9EVWfXWTwmc,5606
10
10
  lightning_sdk/organization.py,sha256=WCfzdgjtvY1_A07DnxOpp74V2JR2gQwtXbIEcFDnoVU,1232
@@ -18,39 +18,39 @@ lightning_sdk/api/__init__.py,sha256=Qn2VVRvir_gO7w4yxGLkZY-R3T7kdiTPKgQ57BhIA9k
18
18
  lightning_sdk/api/agents_api.py,sha256=G47TbFo9kYqnBMqdw2RW-lfS1VAUBSXDmzs6fpIEMUs,4059
19
19
  lightning_sdk/api/ai_hub_api.py,sha256=CYQLFLA89m3xQ-6Ss3UX4TDK6ZWRwmPGA5DjyJqW3RM,5578
20
20
  lightning_sdk/api/deployment_api.py,sha256=T480Nej7LqmtkAx8SBkPGQ5JxeyQ-GVIDqUCc7Z1yfk,21448
21
- lightning_sdk/api/job_api.py,sha256=ykok7Fg3iNOKysgO601gt8gidXc9vO8IRqpjJel9lS8,11980
22
- lightning_sdk/api/lit_container_api.py,sha256=BF5AOvHmF8i2eYBIRgIKcS1R_y3wn2PL_LhZruQyEAo,821
23
- lightning_sdk/api/mmt_api.py,sha256=rgMVDdlC3h-KqGI2FGp7Im99gnrHg5xx4FLwQqYWqxI,7136
21
+ lightning_sdk/api/job_api.py,sha256=eu0YKA27m8nEX6d9VzyMvQsl_qnDwtDJwbD4uT1o2Ks,12230
22
+ lightning_sdk/api/lit_container_api.py,sha256=wMX1FdTGiia-fqYFvJLH-Rf6eJIRJ9ggqrI84DtSAFI,1875
23
+ lightning_sdk/api/mmt_api.py,sha256=NHLFaqHx0v2uwq9JEUkYPpDAf-L6EJkJS7nulj66ASA,7322
24
24
  lightning_sdk/api/org_api.py,sha256=Ze3z_ATVrukobujV5YdC42DKj45Vuwl7X52q_Vr-o3U,803
25
25
  lightning_sdk/api/studio_api.py,sha256=Cfsq8HFc4uUsj8hncnhnD_TLhw0cg-ryclGowj8S6Y0,26374
26
26
  lightning_sdk/api/teamspace_api.py,sha256=KYNyfx3aUYJyPeluM9iYphcIogBc--Bt3cV4IAgY7A4,11236
27
27
  lightning_sdk/api/user_api.py,sha256=sL7RIjjtmZmvCZWx7BBZslhj1BeNh4Idn-RVcdmf7M0,2598
28
- lightning_sdk/api/utils.py,sha256=pvDK_qUv8kgDTGumN2f7YcCy-HNnn_VUwZ5SbZTDgxA,22530
28
+ lightning_sdk/api/utils.py,sha256=VG3sCxWjn6MHONYghA73PZH-ErgqsHyj1ZMU6qzBCFk,22762
29
29
  lightning_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  lightning_sdk/cli/ai_hub.py,sha256=8oy6TogDiWnHuLT3cv33XEW7vPqXPA0dDMds8kX3Z4g,1649
31
31
  lightning_sdk/cli/delete.py,sha256=TePfbCUKR2Bzq3D-avAX6AATQAR0GfFIxj_Qw3qSczo,2431
32
32
  lightning_sdk/cli/download.py,sha256=nyQN3q1vZ0fg4_cfit8cKaokQ9VUd46l_TNcAQWkLwU,5996
33
- lightning_sdk/cli/entrypoint.py,sha256=8CRA_jAg6CkHmFWUbrDQRRYd-oJccE6A7DPvNoAdGtk,1803
33
+ lightning_sdk/cli/entrypoint.py,sha256=dybKJ9lTs7ixzaVRLGk4Gv1b11j3VKlAJr5B7itfDRA,2120
34
34
  lightning_sdk/cli/exceptions.py,sha256=QUF3OMAMZwBikvlusimSHSBjb6ywvHpfAumJBEaodSw,169
35
35
  lightning_sdk/cli/inspect.py,sha256=VeiazH-9DNn0SrQmP-ZM5JDdy8veQy5yxVe_Dj-KQWI,1349
36
36
  lightning_sdk/cli/job_and_mmt_action.py,sha256=OV_i5K3g-NnMUF8Sq6QliQdltnhGVRdtoyZqJVXu4Ss,1659
37
37
  lightning_sdk/cli/jobs_menu.py,sha256=6VqJecnyybYjdozj7MXH1gJehskJlwP8SoewQEXDz8s,2119
38
38
  lightning_sdk/cli/legacy.py,sha256=ocTVNwlsLRS5aMjbMkwFPjT3uEYvS8C40CJ0PeRRv8g,4707
39
- lightning_sdk/cli/list.py,sha256=sQzzwP6CxiL5YO4JZMgZ-THE4NII4h7mMl_9tmPZ_-8,2109
39
+ lightning_sdk/cli/list.py,sha256=gLfIf9iXPPyotqIy8MkWGJXWmGF8BV3jtmcZ8cCd3Ng,3856
40
40
  lightning_sdk/cli/mmts_menu.py,sha256=OAwWywYeFSdmXBLR7raZlL7tpAhZld4r71LUHvmnZdA,2175
41
- lightning_sdk/cli/run.py,sha256=0jfijJCzUYON-OGgCljk6nhzN4o0pS2f8Il1LEOEPKk,11620
41
+ lightning_sdk/cli/run.py,sha256=4hcPuawGPVoHMoLUw6uwTNv1qPd4Js-PomUJgjmLkfw,11806
42
42
  lightning_sdk/cli/serve.py,sha256=UaXhGHU6nbAzrnVigSKOTrMjLwSs-sjyhuJCdVUBwzc,8722
43
43
  lightning_sdk/cli/stop.py,sha256=qBlVaYAJGxiNSwskxqB7zizTVPIpBGlJ4c7kIXII7iw,1373
44
44
  lightning_sdk/cli/studios_menu.py,sha256=0kQGqGel8gAbpdJtjOM1a6NEat_TnIqRNprNn8QiK58,3236
45
45
  lightning_sdk/cli/teamspace_menu.py,sha256=GVTrMAqxxL3INX83alo5wybnrl6rBBKENo01ZNkWPik,3753
46
- lightning_sdk/cli/upload.py,sha256=H9OyipYTYAQ9Mzy2e8jtoaa-B34-uXHbTQTzY2Vmhv4,9078
46
+ lightning_sdk/cli/upload.py,sha256=pn7yIq98e_gMoaFhETHfiXai_15qdyG6t1hsdjN-oWg,10589
47
47
  lightning_sdk/deployment/__init__.py,sha256=BLu7_cVLp97TYxe6qe-J1zKUSZXAVcvCjgcA7plV2k4,497
48
48
  lightning_sdk/deployment/deployment.py,sha256=Dp15pn8rFAfMfaDhKn0v3bphFuvLgkPFs3KSNxW6eyc,15472
49
49
  lightning_sdk/job/__init__.py,sha256=1MxjQ6rHkyUHCypSW9RuXuVMVH11WiqhIXcU2LCFMwE,64
50
- lightning_sdk/job/base.py,sha256=CaysK2JiWTlTp7WJfC1Ebht2auCrMncgqn6EKVf-c_Q,15615
50
+ lightning_sdk/job/base.py,sha256=MT1p8RGIhJ9j7LVNTOfk6PTokP6GCdLe4U83vQ_P9dw,16272
51
51
  lightning_sdk/job/job.py,sha256=JSd2UUvBJof_ZVaO-FWWbv-Jml7othL8ZSuP6F9Sp7Y,13425
52
- lightning_sdk/job/v1.py,sha256=pmu-adVC0fh4jKwXvjBQb9iIDKPuC5eOo0a2BiBq1fw,10184
53
- lightning_sdk/job/v2.py,sha256=5DhGK9KQhkRH-M3qzALhO83T1L0w9LEziaX4AFjL1Jo,10285
52
+ lightning_sdk/job/v1.py,sha256=ncQcP7pBLUmyLSYwRNM6DVMhxVzRwIfs4EhmSJOe5aI,10202
53
+ lightning_sdk/job/v2.py,sha256=gxrVjFOeHgvEBARE2w5nSUfNSuNEgdNl_RVGIvNPvlM,10180
54
54
  lightning_sdk/job/work.py,sha256=pe1kWU3_GPuN5QlKIDOx_DKyzP1ARhJqY-ACKmklo8U,2313
55
55
  lightning_sdk/lightning_cloud/__init__.py,sha256=o91SMAlwr4Ke5ESe8fHjqXcj31_h7rT-MlFoXA-n2EI,173
56
56
  lightning_sdk/lightning_cloud/__version__.py,sha256=lOfmWHtjmiuSG28TbKQqd2B3nwmSGOlKVFwhaj_cRJk,23
@@ -301,7 +301,7 @@ lightning_sdk/lightning_cloud/openapi/models/v1_cluster_names.py,sha256=Xs3mhVEi
301
301
  lightning_sdk/lightning_cloud/openapi/models/v1_cluster_proxy.py,sha256=4LbHvINs2CwQnuPg_uWw03GNNRT_wdqX42m_Zlqg2dY,5547
302
302
  lightning_sdk/lightning_cloud/openapi/models/v1_cluster_resource_tag.py,sha256=U6DfNNAIBZQ8SOF-2RXp2-CgmxaT1XJrNaCnZzaqjHg,4274
303
303
  lightning_sdk/lightning_cloud/openapi/models/v1_cluster_security_options.py,sha256=rr-Y_51425UxWZY9PEE9OW-m6mvqgmOP1yc3RB5FkIY,12571
304
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py,sha256=PnRnqmq4FxzpreRvJ34Bc1jGp9k5-AQW-aLDl93HNqY,18931
304
+ lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py,sha256=xGy5pWDcuKn1p90M4BGFlhAscswRMRmfRIRHdItR9aQ,17392
305
305
  lightning_sdk/lightning_cloud/openapi/models/v1_cluster_state.py,sha256=Mvl3dEhdtb7-rU4wUsR_-YOMpd7wE8uUAyXv3MiOcOk,3331
306
306
  lightning_sdk/lightning_cloud/openapi/models/v1_cluster_status.py,sha256=n9NhKdWg51q_7d4VM9Bsk5aakctU-o3R-0YmdzTsMW0,13267
307
307
  lightning_sdk/lightning_cloud/openapi/models/v1_cluster_tagging_options.py,sha256=E3uMncqfSA1IxGGAUsNYdfeXYkY4NNs6p7cLWBMoHMw,6283
@@ -528,7 +528,7 @@ lightning_sdk/lightning_cloud/openapi/models/v1_job_timing.py,sha256=qnnGfuKbAU_
528
528
  lightning_sdk/lightning_cloud/openapi/models/v1_joinable_organization.py,sha256=IkuGZ89NWOMpe8JsxXJvkRKdcDUvV4F3akA_USvl5rs,9586
529
529
  lightning_sdk/lightning_cloud/openapi/models/v1_keep_alive_cloud_space_instance_response.py,sha256=NRrP0aqQbpd8ejQUApJ2L1vUoSx1UhNOlSh4JeQ2_es,3112
530
530
  lightning_sdk/lightning_cloud/openapi/models/v1_knowledge_configuration.py,sha256=zEm-VKsmvL6aJtICeq1w3nn-V-6GvYLRNYDbnvPGn-4,8841
531
- lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py,sha256=fYXcwvKIgeNWWCrtynvO5YCgbbPu0ETR6TtPnGbAPqY,4133
531
+ lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py,sha256=aI89GSYPsCDMH2Xuk4bTcBmRDwv3ZQtvv7PqYT0TT3w,5290
532
532
  lightning_sdk/lightning_cloud/openapi/models/v1_lightning_app_user.py,sha256=5jJlea7GP24fkRtNsTVl0AYrotiODCYe8-qyIxr3w0w,4352
533
533
  lightning_sdk/lightning_cloud/openapi/models/v1_lightning_auth.py,sha256=-ccSh5ZorAALrYlIw6HhbFZ1NpF6YiU0WHuV1EnyBYM,4448
534
534
  lightning_sdk/lightning_cloud/openapi/models/v1_lightning_basic_auth.py,sha256=fgPODETba7KvV3JGrpgy44c6nXMt-rOHiK40SCgB0gI,4434
@@ -815,7 +815,7 @@ lightning_sdk/lightning_cloud/openapi/models/v1_upstream_open_ai.py,sha256=jt1qQ
815
815
  lightning_sdk/lightning_cloud/openapi/models/v1_usage.py,sha256=RhhnH9ygScZyExg06WhvMNPPRLSe8FYkIftqF-D9NIU,13408
816
816
  lightning_sdk/lightning_cloud/openapi/models/v1_usage_details.py,sha256=U7qC698Xj5tb3D93ZskG6sDf3lTXE13UTlGeDTvtRU4,14062
817
817
  lightning_sdk/lightning_cloud/openapi/models/v1_usage_report.py,sha256=iH67BcONBSLYzcZpGpKWSOzJTCpuqYt7FU4OUs8BJ9k,6076
818
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py,sha256=2KlY1j_YxyEb228z8YLiDssXc1FFfwUFKk62X7T6RFE,73647
818
+ lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py,sha256=BVJiD5oLzTBceVjdk2qS0_eA4xG4ANQzQAQNsoAYG-c,74282
819
819
  lightning_sdk/lightning_cloud/openapi/models/v1_user_requested_compute_config.py,sha256=3jeJfpbBpYY2B2Ao2j2N93CMO2CnvmPqndE4Lw3ZfMA,13056
820
820
  lightning_sdk/lightning_cloud/openapi/models/v1_user_requested_flow_compute_config.py,sha256=3WpZ-lf7xPwuYyQDMdP7Uc6-dh3vf5TaaUlcMfesfMk,5208
821
821
  lightning_sdk/lightning_cloud/openapi/models/v1_user_slurm_job_action_response.py,sha256=BdNzXH8Vsf5PHjl9Rd-TVkpAgx1YC9rf8LD0js-ba20,3058
@@ -829,7 +829,7 @@ lightning_sdk/lightning_cloud/openapi/models/v1_validate_managed_endpoint_respon
829
829
  lightning_sdk/lightning_cloud/openapi/models/v1_validate_managed_model_response.py,sha256=LshfheXdKDqRYgg5Sa5dV0L9CW3BVfFts_f2qqmnH7k,3767
830
830
  lightning_sdk/lightning_cloud/openapi/models/v1_verify_verification_response.py,sha256=VQrBJk2pQQJuu-1Om-kvKr5N9ioxEPeV2l70udHEWSw,3058
831
831
  lightning_sdk/lightning_cloud/openapi/models/v1_volume.py,sha256=UIEsGm_TA6Qustavo2Umxq1No4pP-VImzsYw7CfNXMk,4702
832
- lightning_sdk/lightning_cloud/openapi/models/v1_vultr_direct_v1.py,sha256=jq4ODNqWXJqkkyMdod6C7eiuWDPAfqMC1sEI6DSJDH0,5594
832
+ lightning_sdk/lightning_cloud/openapi/models/v1_vultr_direct_v1.py,sha256=5xp2xBJR823Xa-lTBf0bs9E1OnrhAidknF_LPnzgvuI,6465
833
833
  lightning_sdk/lightning_cloud/openapi/models/v1_work.py,sha256=MwXPSG8TE_CcGiffx6OI6U7kyf1NnSsDvJEM6LuwcYA,4910
834
834
  lightning_sdk/lightning_cloud/openapi/models/validate.py,sha256=wrCNhZpBR2PiA_a56C01w5fuxOSSGkbEh3Y8iMwUcYs,8086
835
835
  lightning_sdk/lightning_cloud/openapi/models/validateautojoindomain_domain_body.py,sha256=gRI7XdvbY7w09gIH6BkFai8UA-y71T2AmiR5Y2XcTe8,3781
@@ -851,10 +851,10 @@ lightning_sdk/lightning_cloud/utils/dataset.py,sha256=4nUspe8iAaRPgSYpXA2uAQCgyd
851
851
  lightning_sdk/lightning_cloud/utils/name_generator.py,sha256=MkciuA10332V0mcE2PxLIiwWomWE0Fm_gNGK01vwRr4,58046
852
852
  lightning_sdk/lightning_cloud/utils/network.py,sha256=axPgl8rhyPcPjxiztDxyksfxax3VNg2OXL5F5Uc81b4,406
853
853
  lightning_sdk/mmt/__init__.py,sha256=ExMu90-96bGBnyp5h0CErQszUGB1-PcjC4-R8_NYbeY,117
854
- lightning_sdk/mmt/base.py,sha256=yXmussF0qEh7S9KeYcKo7xzBlIAg1DCjgdf1iWc-L6M,14489
854
+ lightning_sdk/mmt/base.py,sha256=KBqNMsbAQPGy5CPUCkZMbAGLnjyVG9H-o-xDAPQ-vng,14822
855
855
  lightning_sdk/mmt/mmt.py,sha256=v-dOMS1bqUGoGYIe45YZJc0aXPUDsUGNdRoeu8DMw60,14029
856
- lightning_sdk/mmt/v1.py,sha256=3c28zivn2ZVhp4uXsyNwTpa4nN3vU021AyR6PCCw5_g,9255
857
- lightning_sdk/mmt/v2.py,sha256=LUwNSxeJVorCkJllRhFGtDgjGRBAsx81lLTaJWSFXHQ,9589
856
+ lightning_sdk/mmt/v1.py,sha256=qdd8wrGlyg-75rYLGFY4-PfIg_O9fYvVRL-xryNg2U8,9347
857
+ lightning_sdk/mmt/v2.py,sha256=97sIFx55MAgkaOq3pb5I8GB8pQoHg7HB8pezccH-vuw,9682
858
858
  lightning_sdk/services/__init__.py,sha256=gSWUjccEhMI9CIWL_nbrFHUK2S6TM2725mEzrLMfK1Y,225
859
859
  lightning_sdk/services/file_endpoint.py,sha256=we5HC_o74J4Y6fSP_31jIizi_I_1FO_Rb2qblspD9eE,7855
860
860
  lightning_sdk/services/utilities.py,sha256=IeOx8hc3F8ZevHeKBysh08BXhJliTNzvKp1gwpEfdik,4087
@@ -863,9 +863,9 @@ lightning_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
863
863
  lightning_sdk/utils/dynamic.py,sha256=glUTO1JC9APtQ6Gr9SO02a3zr56-sPAXM5C3NrTpgyQ,1959
864
864
  lightning_sdk/utils/enum.py,sha256=h2JRzqoBcSlUdanFHmkj_j5DleBHAu1esQYUsdNI-hU,4106
865
865
  lightning_sdk/utils/resolve.py,sha256=RWvlOWLHjaHhR0W0zT3mN719cbzhFfYCKBss38zfv3k,5783
866
- lightning_sdk-0.1.48.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
867
- lightning_sdk-0.1.48.dist-info/METADATA,sha256=8eqGkORoyWrF3suijKWe2UnwH71uucciC5ajYlGemzk,4031
868
- lightning_sdk-0.1.48.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
869
- lightning_sdk-0.1.48.dist-info/entry_points.txt,sha256=msB9PJWIJ784dX-OP8by51d4IbKYH3Fj1vCuA9oXjHY,68
870
- lightning_sdk-0.1.48.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
871
- lightning_sdk-0.1.48.dist-info/RECORD,,
866
+ lightning_sdk-0.1.49.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
867
+ lightning_sdk-0.1.49.dist-info/METADATA,sha256=tBtxBwoidv39GiVZ8kKllvqj9UEomokZZpD9_zlMSqs,4031
868
+ lightning_sdk-0.1.49.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
869
+ lightning_sdk-0.1.49.dist-info/entry_points.txt,sha256=msB9PJWIJ784dX-OP8by51d4IbKYH3Fj1vCuA9oXjHY,68
870
+ lightning_sdk-0.1.49.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
871
+ lightning_sdk-0.1.49.dist-info/RECORD,,