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 +3 -1
- lightning_sdk/api/job_api.py +7 -0
- lightning_sdk/api/lit_container_api.py +24 -1
- lightning_sdk/api/mmt_api.py +6 -0
- lightning_sdk/api/utils.py +7 -0
- lightning_sdk/cli/entrypoint.py +11 -0
- lightning_sdk/cli/list.py +60 -2
- lightning_sdk/cli/run.py +10 -3
- lightning_sdk/cli/upload.py +32 -1
- lightning_sdk/job/base.py +19 -0
- lightning_sdk/job/v1.py +1 -1
- lightning_sdk/job/v2.py +5 -8
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +1 -29
- lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py +31 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_vultr_direct_v1.py +27 -1
- lightning_sdk/lit_container.py +21 -0
- lightning_sdk/mmt/base.py +18 -1
- lightning_sdk/mmt/v1.py +3 -1
- lightning_sdk/mmt/v2.py +9 -8
- {lightning_sdk-0.1.48.dist-info → lightning_sdk-0.1.49.dist-info}/METADATA +1 -1
- {lightning_sdk-0.1.48.dist-info → lightning_sdk-0.1.49.dist-info}/RECORD +26 -26
- {lightning_sdk-0.1.48.dist-info → lightning_sdk-0.1.49.dist-info}/LICENSE +0 -0
- {lightning_sdk-0.1.48.dist-info → lightning_sdk-0.1.49.dist-info}/WHEEL +0 -0
- {lightning_sdk-0.1.48.dist-info → lightning_sdk-0.1.49.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-0.1.48.dist-info → lightning_sdk-0.1.49.dist-info}/top_level.txt +0 -0
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.
|
|
32
|
+
__version__ = "0.1.49"
|
|
31
33
|
_check_version_and_prompt_upgrade(__version__)
|
lightning_sdk/api/job_api.py
CHANGED
|
@@ -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)
|
lightning_sdk/api/mmt_api.py
CHANGED
|
@@ -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
|
lightning_sdk/api/utils.py
CHANGED
|
@@ -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
|
|
lightning_sdk/cli/entrypoint.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
lightning_sdk/cli/upload.py
CHANGED
|
@@ -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,
|
|
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,
|
|
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
|
lightning_sdk/lit_container.py
CHANGED
|
@@ -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[
|
|
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,
|
|
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,10 +1,10 @@
|
|
|
1
1
|
docs/source/conf.py,sha256=r8yX20eC-4mHhMTd0SbQb5TlSWHhO6wnJ0VJ_FBFpag,13249
|
|
2
|
-
lightning_sdk/__init__.py,sha256=
|
|
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=
|
|
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=
|
|
22
|
-
lightning_sdk/api/lit_container_api.py,sha256=
|
|
23
|
-
lightning_sdk/api/mmt_api.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
53
|
-
lightning_sdk/job/v2.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
857
|
-
lightning_sdk/mmt/v2.py,sha256=
|
|
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.
|
|
867
|
-
lightning_sdk-0.1.
|
|
868
|
-
lightning_sdk-0.1.
|
|
869
|
-
lightning_sdk-0.1.
|
|
870
|
-
lightning_sdk-0.1.
|
|
871
|
-
lightning_sdk-0.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|