lightning-sdk 2025.9.11__py3-none-any.whl → 2025.9.23__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 +4 -2
- lightning_sdk/api/__init__.py +2 -0
- lightning_sdk/api/cloud_account_api.py +24 -6
- lightning_sdk/api/job_api.py +12 -11
- lightning_sdk/api/mmt_api.py +1 -1
- lightning_sdk/api/studio_api.py +1 -1
- lightning_sdk/api/teamspace_api.py +44 -0
- lightning_sdk/api/user_api.py +8 -2
- lightning_sdk/cli/utils/owner_selection.py +110 -0
- lightning_sdk/cli/utils/teamspace_selection.py +63 -62
- lightning_sdk/llm/llm.py +4 -4
- lightning_sdk/machine.py +16 -1
- lightning_sdk/teamspace.py +116 -3
- {lightning_sdk-2025.9.11.dist-info → lightning_sdk-2025.9.23.dist-info}/METADATA +1 -1
- {lightning_sdk-2025.9.11.dist-info → lightning_sdk-2025.9.23.dist-info}/RECORD +19 -18
- {lightning_sdk-2025.9.11.dist-info → lightning_sdk-2025.9.23.dist-info}/LICENSE +0 -0
- {lightning_sdk-2025.9.11.dist-info → lightning_sdk-2025.9.23.dist-info}/WHEEL +0 -0
- {lightning_sdk-2025.9.11.dist-info → lightning_sdk-2025.9.23.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-2025.9.11.dist-info → lightning_sdk-2025.9.23.dist-info}/top_level.txt +0 -0
lightning_sdk/__init__.py
CHANGED
|
@@ -10,14 +10,16 @@ from lightning_sdk.organization import Organization
|
|
|
10
10
|
from lightning_sdk.plugin import JobsPlugin, MultiMachineTrainingPlugin, Plugin, SlurmJobsPlugin
|
|
11
11
|
from lightning_sdk.status import Status
|
|
12
12
|
from lightning_sdk.studio import Studio
|
|
13
|
-
from lightning_sdk.teamspace import Teamspace
|
|
13
|
+
from lightning_sdk.teamspace import ConnectionType, FolderLocation, Teamspace
|
|
14
14
|
from lightning_sdk.user import User
|
|
15
15
|
|
|
16
16
|
__all__ = [
|
|
17
17
|
"AIHub",
|
|
18
18
|
"Agent",
|
|
19
19
|
"CloudProvider",
|
|
20
|
+
"ConnectionType",
|
|
20
21
|
"Deployment",
|
|
22
|
+
"FolderLocation",
|
|
21
23
|
"Job",
|
|
22
24
|
"JobsPlugin",
|
|
23
25
|
"Machine",
|
|
@@ -32,6 +34,6 @@ __all__ = [
|
|
|
32
34
|
"User",
|
|
33
35
|
]
|
|
34
36
|
|
|
35
|
-
__version__ = "2025.09.
|
|
37
|
+
__version__ = "2025.09.23"
|
|
36
38
|
_check_version_and_prompt_upgrade(__version__)
|
|
37
39
|
_set_tqdm_envvars_noninteractive()
|
lightning_sdk/api/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from lightning_sdk.api.agents_api import AgentApi
|
|
2
2
|
from lightning_sdk.api.ai_hub_api import AIHubApi
|
|
3
|
+
from lightning_sdk.api.cloud_account_api import CloudAccountApi
|
|
3
4
|
from lightning_sdk.api.org_api import OrgApi
|
|
4
5
|
from lightning_sdk.api.studio_api import StudioApi
|
|
5
6
|
from lightning_sdk.api.teamspace_api import TeamspaceApi
|
|
@@ -12,4 +13,5 @@ __all__ = [
|
|
|
12
13
|
"UserApi",
|
|
13
14
|
"AgentApi",
|
|
14
15
|
"AIHubApi",
|
|
16
|
+
"CloudAccountApi",
|
|
15
17
|
]
|
|
@@ -13,6 +13,7 @@ from lightning_sdk.lightning_cloud.rest_client import LightningClient
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from lightning_sdk.machine import CloudProvider
|
|
16
|
+
from lightning_sdk.teamspace import ConnectionType
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class CloudAccountApi:
|
|
@@ -131,13 +132,20 @@ class CloudAccountApi:
|
|
|
131
132
|
)
|
|
132
133
|
return list(filtered_cloud_accounts)
|
|
133
134
|
|
|
134
|
-
def get_cloud_account_provider_mapping(self, teamspace_id: str) -> Dict["CloudProvider",
|
|
135
|
+
def get_cloud_account_provider_mapping(self, teamspace_id: str) -> Dict["CloudProvider", V1ExternalCluster]:
|
|
135
136
|
"""Gets the cloud account <-> provider mapping."""
|
|
136
|
-
res = self.
|
|
137
|
-
|
|
137
|
+
res = self.list_cloud_accounts(teamspace_id=teamspace_id)
|
|
138
|
+
cloud_accounts = {cloud_account.id: cloud_account for cloud_account in res}
|
|
139
|
+
providers = {cloud_account.id: self._get_cloud_account_provider(cloud_account) for cloud_account in res}
|
|
140
|
+
|
|
141
|
+
mapping = {}
|
|
142
|
+
for cloud_account_id, provider in providers.items():
|
|
143
|
+
if provider is not None:
|
|
144
|
+
mapping[provider] = cloud_accounts[cloud_account_id]
|
|
145
|
+
return mapping
|
|
138
146
|
|
|
139
147
|
@staticmethod
|
|
140
|
-
def _get_cloud_account_provider(cloud_account: Optional[V1ExternalCluster]) -> "CloudProvider":
|
|
148
|
+
def _get_cloud_account_provider(cloud_account: Optional[V1ExternalCluster]) -> Optional["CloudProvider"]:
|
|
141
149
|
"""Determines the cloud provider based on the cloud_account configuration.
|
|
142
150
|
|
|
143
151
|
Args:
|
|
@@ -172,7 +180,7 @@ class CloudAccountApi:
|
|
|
172
180
|
if cloud_account.spec.nebius_v1:
|
|
173
181
|
return CloudProvider.NEBIUS
|
|
174
182
|
|
|
175
|
-
return
|
|
183
|
+
return None
|
|
176
184
|
|
|
177
185
|
def resolve_cloud_account(
|
|
178
186
|
self,
|
|
@@ -201,9 +209,19 @@ class CloudAccountApi:
|
|
|
201
209
|
if cloud_provider:
|
|
202
210
|
cloud_account_mapping = self.get_cloud_account_provider_mapping(teamspace_id=teamspace_id)
|
|
203
211
|
if cloud_provider and cloud_provider in cloud_account_mapping:
|
|
204
|
-
return cloud_account_mapping[cloud_provider]
|
|
212
|
+
return cloud_account_mapping[cloud_provider].id
|
|
205
213
|
|
|
206
214
|
if default_cloud_account:
|
|
207
215
|
return default_cloud_account
|
|
208
216
|
|
|
209
217
|
return None
|
|
218
|
+
|
|
219
|
+
@staticmethod
|
|
220
|
+
def get_cloud_provider_for_connection_type(connection_type: "ConnectionType") -> "CloudProvider":
|
|
221
|
+
from lightning_sdk.machine import CloudProvider
|
|
222
|
+
from lightning_sdk.teamspace import ConnectionType
|
|
223
|
+
|
|
224
|
+
if connection_type == ConnectionType.EFS:
|
|
225
|
+
return CloudProvider.AWS
|
|
226
|
+
|
|
227
|
+
raise ValueError(f"ConnectionType {ConnectionType} currently not supported!")
|
lightning_sdk/api/job_api.py
CHANGED
|
@@ -104,22 +104,23 @@ class JobApiV1:
|
|
|
104
104
|
org_id=org_id,
|
|
105
105
|
)
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
identifiers = []
|
|
108
108
|
|
|
109
109
|
if user_requested_compute_config and user_requested_compute_config.name:
|
|
110
|
-
|
|
110
|
+
identifiers.append(user_requested_compute_config.name)
|
|
111
111
|
else:
|
|
112
|
-
|
|
112
|
+
identifiers.append(spec.compute_config.instance_type)
|
|
113
113
|
|
|
114
114
|
for accelerator in accelerators:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
for ident in identifiers:
|
|
116
|
+
if ident in (
|
|
117
|
+
accelerator.slug,
|
|
118
|
+
accelerator.slug_multi_cloud,
|
|
119
|
+
accelerator.instance_id,
|
|
120
|
+
):
|
|
121
|
+
return Machine._from_accelerator(accelerator)
|
|
121
122
|
|
|
122
|
-
return Machine.from_str(
|
|
123
|
+
return Machine.from_str(identifiers[0])
|
|
123
124
|
|
|
124
125
|
def _get_machines_for_cloud_account(
|
|
125
126
|
self, teamspace_id: str, cloud_account_id: str, org_id: str
|
|
@@ -431,7 +432,7 @@ class JobApiV2:
|
|
|
431
432
|
if (spec.instance_name and spec.instance_name in possible_identifiers) or (
|
|
432
433
|
spec.instance_type and spec.instance_type in possible_identifiers
|
|
433
434
|
):
|
|
434
|
-
return Machine.
|
|
435
|
+
return Machine._from_accelerator(accelerator)
|
|
435
436
|
|
|
436
437
|
return Machine.from_str(spec.instance_name or spec.instance_type)
|
|
437
438
|
|
lightning_sdk/api/mmt_api.py
CHANGED
|
@@ -265,7 +265,7 @@ class MMTApiV2:
|
|
|
265
265
|
if (spec.instance_name and spec.instance_name in possible_identifiers) or (
|
|
266
266
|
spec.instance_type and spec.instance_type in possible_identifiers
|
|
267
267
|
):
|
|
268
|
-
return Machine.
|
|
268
|
+
return Machine._from_accelerator(accelerator)
|
|
269
269
|
|
|
270
270
|
return Machine.from_str(spec.instance_name or spec.instance_type)
|
|
271
271
|
|
lightning_sdk/api/studio_api.py
CHANGED
|
@@ -426,7 +426,7 @@ class StudioApi:
|
|
|
426
426
|
accelerator.slug_multi_cloud,
|
|
427
427
|
accelerator.instance_id,
|
|
428
428
|
):
|
|
429
|
-
return Machine.
|
|
429
|
+
return Machine._from_accelerator(accelerator)
|
|
430
430
|
|
|
431
431
|
return Machine.from_str(response.compute_config.name)
|
|
432
432
|
|
|
@@ -17,6 +17,7 @@ from lightning_sdk.api.utils import (
|
|
|
17
17
|
)
|
|
18
18
|
from lightning_sdk.lightning_cloud.login import Auth
|
|
19
19
|
from lightning_sdk.lightning_cloud.openapi import (
|
|
20
|
+
Create,
|
|
20
21
|
Externalv1LightningappInstance,
|
|
21
22
|
ModelIdVersionsBody,
|
|
22
23
|
ModelsStoreApi,
|
|
@@ -27,7 +28,10 @@ from lightning_sdk.lightning_cloud.openapi import (
|
|
|
27
28
|
V1Assistant,
|
|
28
29
|
V1CloudSpace,
|
|
29
30
|
V1ClusterAccelerator,
|
|
31
|
+
V1EfsConfig,
|
|
30
32
|
V1Endpoint,
|
|
33
|
+
V1ExternalCluster,
|
|
34
|
+
V1GCSFolderDataConnection,
|
|
31
35
|
V1Job,
|
|
32
36
|
V1LoginRequest,
|
|
33
37
|
V1Model,
|
|
@@ -36,6 +40,8 @@ from lightning_sdk.lightning_cloud.openapi import (
|
|
|
36
40
|
V1Project,
|
|
37
41
|
V1ProjectClusterBinding,
|
|
38
42
|
V1PromptSuggestion,
|
|
43
|
+
V1R2DataConnection,
|
|
44
|
+
V1S3FolderDataConnection,
|
|
39
45
|
V1Secret,
|
|
40
46
|
V1SecretType,
|
|
41
47
|
V1UpstreamOpenAI,
|
|
@@ -489,3 +495,41 @@ class TeamspaceApi:
|
|
|
489
495
|
"""
|
|
490
496
|
pattern = r"^[A-Za-z_][A-Za-z0-9_]*$"
|
|
491
497
|
return re.match(pattern, name) is not None
|
|
498
|
+
|
|
499
|
+
def new_folder(self, teamspace_id: str, name: str, cluster: Optional[V1ExternalCluster]) -> None:
|
|
500
|
+
create_request = Create(
|
|
501
|
+
name=name,
|
|
502
|
+
create_resources=True,
|
|
503
|
+
force=True,
|
|
504
|
+
writable=True,
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
if cluster is None:
|
|
508
|
+
create_request.r2 = V1R2DataConnection(name=name)
|
|
509
|
+
else:
|
|
510
|
+
create_request.cluster_id = cluster.id
|
|
511
|
+
create_request.access_cluster_ids = [cluster.id]
|
|
512
|
+
|
|
513
|
+
if cluster.spec.aws_v1:
|
|
514
|
+
create_request.s3_folder = V1S3FolderDataConnection()
|
|
515
|
+
elif cluster.spec.google_cloud_v1:
|
|
516
|
+
create_request.gcs_folder = V1GCSFolderDataConnection()
|
|
517
|
+
|
|
518
|
+
self._client.data_connection_service_create_data_connection(create_request, teamspace_id)
|
|
519
|
+
|
|
520
|
+
def new_connection(
|
|
521
|
+
self, teamspace_id: str, name: str, source: str, cluster: V1ExternalCluster, writable: bool, region: str
|
|
522
|
+
) -> None:
|
|
523
|
+
create_request = Create(
|
|
524
|
+
name=name,
|
|
525
|
+
create_resources=False,
|
|
526
|
+
force=True,
|
|
527
|
+
writable=writable,
|
|
528
|
+
cluster_id=cluster.id,
|
|
529
|
+
access_cluster_ids=[cluster.id],
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
# TODO: Add support for other connection types
|
|
533
|
+
create_request.efs = V1EfsConfig(file_system_id=source, region=region)
|
|
534
|
+
|
|
535
|
+
self._client.data_connection_service_create_data_connection(create_request, teamspace_id)
|
lightning_sdk/api/user_api.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from typing import Dict, List, Union
|
|
2
|
+
from typing import Dict, List, Optional, Union
|
|
3
3
|
|
|
4
4
|
from lightning_sdk.lightning_cloud.login import Auth
|
|
5
5
|
from lightning_sdk.lightning_cloud.openapi import (
|
|
@@ -61,8 +61,14 @@ class UserApi:
|
|
|
61
61
|
def _get_all_teamspace_memberships(
|
|
62
62
|
self,
|
|
63
63
|
user_id: str, # todo: this is unused, but still required
|
|
64
|
+
org_id: Optional[str] = None,
|
|
64
65
|
) -> List[V1Membership]:
|
|
65
|
-
|
|
66
|
+
kwargs: Dict[str, Union[bool, str]] = {"filter_by_user_id": True}
|
|
67
|
+
|
|
68
|
+
if org_id is not None:
|
|
69
|
+
kwargs["organization_id"] = org_id
|
|
70
|
+
|
|
71
|
+
return self._client.projects_service_list_memberships(**kwargs).memberships
|
|
66
72
|
|
|
67
73
|
def _get_authed_user_name(self) -> str:
|
|
68
74
|
"""Gets the currently logged-in user."""
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from contextlib import suppress
|
|
3
|
+
from typing import Dict, List, Optional, TypedDict
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from simple_term_menu import TerminalMenu
|
|
7
|
+
|
|
8
|
+
from lightning_sdk.cli.legacy.exceptions import StudioCliError
|
|
9
|
+
from lightning_sdk.organization import Organization
|
|
10
|
+
from lightning_sdk.owner import Owner
|
|
11
|
+
from lightning_sdk.user import User
|
|
12
|
+
from lightning_sdk.utils.resolve import ApiException, _get_authed_user, _resolve_org, _resolve_user
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _OwnerMenuType(TypedDict):
|
|
16
|
+
name: str
|
|
17
|
+
is_org: bool
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class OwnerMenu:
|
|
21
|
+
"""This class is used to select a teamspace owner (org/user) from a list of possible owners.
|
|
22
|
+
|
|
23
|
+
It can be used to select an owner from a list of possible owners, or to resolve an owner from a name.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def _get_owner_from_interactive_menu(self, possible_owners: Dict[str, _OwnerMenuType]) -> _OwnerMenuType:
|
|
27
|
+
owner_ids = sorted(possible_owners.keys())
|
|
28
|
+
terminal_menu = self._prepare_terminal_menu_owners([possible_owners[k] for k in owner_ids])
|
|
29
|
+
terminal_menu.show()
|
|
30
|
+
|
|
31
|
+
selected_id = owner_ids[terminal_menu.chosen_menu_index]
|
|
32
|
+
return possible_owners[selected_id]
|
|
33
|
+
|
|
34
|
+
def _get_owner_from_name(self, owner: str, possible_owners: Dict[str, _OwnerMenuType]) -> _OwnerMenuType:
|
|
35
|
+
for _, ts in possible_owners.items():
|
|
36
|
+
if ts["name"]:
|
|
37
|
+
return ts
|
|
38
|
+
|
|
39
|
+
click.echo(f"Could not find Owner {owner}, please select it from the list:")
|
|
40
|
+
return self._get_owner_from_interactive_menu(possible_owners)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _prepare_terminal_menu_owners(
|
|
44
|
+
possible_owners: List[_OwnerMenuType], title: Optional[str] = None
|
|
45
|
+
) -> TerminalMenu:
|
|
46
|
+
if title is None:
|
|
47
|
+
title = "Please select a Teamspace-Owner out of the following:"
|
|
48
|
+
|
|
49
|
+
return TerminalMenu(
|
|
50
|
+
[f"{to['name']} ({'Organization' if to['is_org'] else 'User'})" for to in possible_owners],
|
|
51
|
+
title=title,
|
|
52
|
+
clear_menu_on_exit=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _get_possible_owners(user: User) -> Dict[str, _OwnerMenuType]:
|
|
57
|
+
user_api = user._user_api
|
|
58
|
+
|
|
59
|
+
orgs = user_api._get_organizations_for_authed_user()
|
|
60
|
+
owners: Dict[str, _OwnerMenuType] = {user.id: {"name": user.name, "is_org": False}}
|
|
61
|
+
|
|
62
|
+
for org in orgs:
|
|
63
|
+
owners[org.id] = {"name": org.name, "is_org": True}
|
|
64
|
+
|
|
65
|
+
return owners
|
|
66
|
+
|
|
67
|
+
def __call__(self, owner: Optional[str] = None) -> Owner:
|
|
68
|
+
try:
|
|
69
|
+
# try to resolve the teamspace from the name, environment or config
|
|
70
|
+
resolved_owner = None
|
|
71
|
+
with suppress(ApiException, ValueError, RuntimeError):
|
|
72
|
+
resolved_owner = _resolve_org(owner)
|
|
73
|
+
|
|
74
|
+
if resolved_owner is not None:
|
|
75
|
+
return resolved_owner
|
|
76
|
+
|
|
77
|
+
with suppress(ApiException, ValueError, RuntimeError):
|
|
78
|
+
resolved_owner = _resolve_user(owner)
|
|
79
|
+
|
|
80
|
+
if resolved_owner is not None:
|
|
81
|
+
return resolved_owner
|
|
82
|
+
|
|
83
|
+
if os.environ.get("LIGHTNING_NON_INTERACTIVE", "0") == "1":
|
|
84
|
+
raise ValueError(
|
|
85
|
+
"Owner selection is not supported in non-interactive mode. Please provide an owner name."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# if the owner is not resolved, try to get the owner from the interactive menu
|
|
89
|
+
# this could mean that either no owner was provided or the provided owner is not valid
|
|
90
|
+
user = _get_authed_user()
|
|
91
|
+
|
|
92
|
+
possible_owners = self._get_possible_owners(user)
|
|
93
|
+
if owner is None:
|
|
94
|
+
owner_dict = self._get_owner_from_interactive_menu(possible_owners=possible_owners)
|
|
95
|
+
|
|
96
|
+
else:
|
|
97
|
+
owner_dict = self._get_owner_from_name(owner=owner, possible_owners=possible_owners)
|
|
98
|
+
|
|
99
|
+
if owner_dict.get("is_org", False):
|
|
100
|
+
return Organization(owner_dict.get("name", None))
|
|
101
|
+
|
|
102
|
+
return User(owner_dict.get("name", None))
|
|
103
|
+
except KeyboardInterrupt:
|
|
104
|
+
raise KeyboardInterrupt from None
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise StudioCliError(
|
|
108
|
+
f"Could not find the given Teamspace-Owner {owner}. "
|
|
109
|
+
"Please contact Lightning AI directly to resolve this issue."
|
|
110
|
+
) from e
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from contextlib import suppress
|
|
2
3
|
from typing import Dict, List, Optional
|
|
3
4
|
|
|
4
5
|
import click
|
|
5
6
|
from simple_term_menu import TerminalMenu
|
|
6
7
|
|
|
7
|
-
from lightning_sdk.api import OrgApi
|
|
8
8
|
from lightning_sdk.cli.legacy.exceptions import StudioCliError
|
|
9
9
|
from lightning_sdk.cli.utils.resolve import resolve_teamspace_owner_name_format
|
|
10
|
-
from lightning_sdk.teamspace import Teamspace
|
|
11
|
-
from lightning_sdk.user import User
|
|
12
|
-
from lightning_sdk.utils.resolve import _get_authed_user
|
|
10
|
+
from lightning_sdk.teamspace import Organization, Teamspace
|
|
11
|
+
from lightning_sdk.user import Owner, User
|
|
12
|
+
from lightning_sdk.utils.resolve import ApiException, _get_authed_user, _resolve_teamspace
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class TeamspacesMenu:
|
|
@@ -18,51 +18,45 @@ class TeamspacesMenu:
|
|
|
18
18
|
It can be used to select a teamspace from a list of possible teamspaces, or to resolve a teamspace from a name.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
def
|
|
21
|
+
def __init__(self, owner: Optional[Owner] = None) -> None:
|
|
22
|
+
self._owner: Owner = owner
|
|
23
|
+
|
|
24
|
+
def _get_teamspace_from_interactive_menu(self, possible_teamspaces: Dict[str, str]) -> str:
|
|
22
25
|
teamspace_ids = sorted(possible_teamspaces.keys())
|
|
23
|
-
terminal_menu = self._prepare_terminal_menu_teamspaces(
|
|
26
|
+
terminal_menu = self._prepare_terminal_menu_teamspaces(
|
|
27
|
+
[possible_teamspaces[k] for k in teamspace_ids], self._owner
|
|
28
|
+
)
|
|
24
29
|
terminal_menu.show()
|
|
25
30
|
|
|
26
31
|
selected_id = teamspace_ids[terminal_menu.chosen_menu_index]
|
|
27
32
|
return possible_teamspaces[selected_id]
|
|
28
33
|
|
|
29
|
-
def _get_teamspace_from_name(
|
|
30
|
-
self, teamspace: str, possible_teamspaces: Dict[str, Dict[str, str]]
|
|
31
|
-
) -> Dict[str, str]:
|
|
32
|
-
try:
|
|
33
|
-
owner, name = teamspace.split("/", maxsplit=1)
|
|
34
|
-
except ValueError as e:
|
|
35
|
-
raise ValueError(
|
|
36
|
-
f"Invalid teamspace format: '{teamspace}'. "
|
|
37
|
-
"Teamspace should be specified as '{teamspace_owner}/{teamspace_name}' "
|
|
38
|
-
"(e.g., 'my-org/my-teamspace')."
|
|
39
|
-
) from e
|
|
40
|
-
|
|
34
|
+
def _get_teamspace_from_name(self, teamspace: str, possible_teamspaces: Dict[str, str]) -> str:
|
|
41
35
|
for _, ts in possible_teamspaces.items():
|
|
42
|
-
if ts
|
|
36
|
+
if ts == teamspace:
|
|
43
37
|
return ts
|
|
44
38
|
|
|
45
|
-
click.echo(f"Could not find Teamspace {teamspace}, please select it from the list:")
|
|
39
|
+
click.echo(f"Could not find Teamspace {self._owner.name}/{teamspace}, please select it from the list:")
|
|
46
40
|
return self._get_teamspace_from_interactive_menu(possible_teamspaces)
|
|
47
41
|
|
|
48
42
|
@staticmethod
|
|
49
43
|
def _prepare_terminal_menu_teamspaces(
|
|
50
|
-
possible_teamspaces: List[
|
|
44
|
+
possible_teamspaces: List[str],
|
|
45
|
+
owner: Owner,
|
|
46
|
+
title: Optional[str] = None,
|
|
51
47
|
) -> TerminalMenu:
|
|
52
48
|
if title is None:
|
|
53
|
-
title = "Please select a Teamspace out of the following:"
|
|
49
|
+
title = f"Please select a Teamspace (owned by {owner.name}) out of the following:"
|
|
54
50
|
|
|
55
|
-
return TerminalMenu(
|
|
56
|
-
[f"{t['user'] or t['org']}/{t['name']}" for t in possible_teamspaces], title=title, clear_menu_on_exit=True
|
|
57
|
-
)
|
|
51
|
+
return TerminalMenu(possible_teamspaces, title=title, clear_menu_on_exit=True)
|
|
58
52
|
|
|
59
53
|
@staticmethod
|
|
60
|
-
def _get_possible_teamspaces(user: User) -> Dict[str,
|
|
61
|
-
org_api = OrgApi()
|
|
54
|
+
def _get_possible_teamspaces(user: User, owner: Owner) -> Dict[str, str]:
|
|
62
55
|
user_api = user._user_api
|
|
63
56
|
|
|
64
|
-
user_api.
|
|
65
|
-
|
|
57
|
+
memberships = user_api._get_all_teamspace_memberships(
|
|
58
|
+
user_id=user.id, org_id=owner.id if isinstance(owner, Organization) else None
|
|
59
|
+
)
|
|
66
60
|
|
|
67
61
|
teamspaces = {}
|
|
68
62
|
# get all teamspace memberships
|
|
@@ -70,56 +64,63 @@ class TeamspacesMenu:
|
|
|
70
64
|
teamspace_id = membership.project_id
|
|
71
65
|
teamspace_name = membership.name
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
org_name = org_api._get_org_by_id(membership.owner_id).name
|
|
76
|
-
user_name = None
|
|
77
|
-
else:
|
|
78
|
-
org_name = None
|
|
79
|
-
|
|
80
|
-
# don't do a request if not necessary
|
|
81
|
-
if membership.owner_id == user.id:
|
|
82
|
-
user_name = user.name
|
|
83
|
-
else:
|
|
84
|
-
user_name = user_api._get_user_by_id(membership.owner_id).username
|
|
85
|
-
|
|
86
|
-
teamspaces[teamspace_id] = {"user": user_name, "org": org_name, "name": teamspace_name}
|
|
67
|
+
if membership.owner_id == owner.id:
|
|
68
|
+
teamspaces[teamspace_id] = teamspace_name
|
|
87
69
|
|
|
88
70
|
return teamspaces
|
|
89
71
|
|
|
90
72
|
def __call__(self, teamspace: Optional[str] = None) -> Teamspace:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
73
|
+
resolved_teamspace = None
|
|
74
|
+
resolved_teamspace = resolve_teamspace_owner_name_format(teamspace)
|
|
75
|
+
if resolved_teamspace is not None:
|
|
76
|
+
return resolved_teamspace
|
|
94
77
|
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
if self._owner is None:
|
|
79
|
+
# resolve owner if required
|
|
80
|
+
from lightning_sdk.cli.utils.owner_selection import OwnerMenu
|
|
97
81
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
82
|
+
menu = OwnerMenu()
|
|
83
|
+
self._owner = menu()
|
|
84
|
+
|
|
85
|
+
if isinstance(self._owner, Organization):
|
|
86
|
+
org = self._owner
|
|
87
|
+
user = None
|
|
88
|
+
elif isinstance(self._owner, User):
|
|
89
|
+
org = None
|
|
90
|
+
user = self._owner
|
|
91
|
+
|
|
92
|
+
with suppress(ApiException, ValueError, RuntimeError):
|
|
93
|
+
resolved_teamspace = _resolve_teamspace(teamspace=teamspace, org=org, user=user)
|
|
103
94
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
user = _get_authed_user()
|
|
95
|
+
if resolved_teamspace is not None:
|
|
96
|
+
return resolved_teamspace
|
|
107
97
|
|
|
108
|
-
|
|
98
|
+
if os.environ.get("LIGHTNING_NON_INTERACTIVE", "0") == "1":
|
|
99
|
+
raise ValueError(
|
|
100
|
+
"Teamspace selection is not supported in non-interactive mode. "
|
|
101
|
+
"Please provide a teamspace name in the format of 'owner/teamspace'."
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# if the teamspace is not resolved, try to get the teamspace from the interactive menu
|
|
105
|
+
# this could mean that either no teamspace was provided or the provided teamspace is not valid
|
|
106
|
+
try:
|
|
107
|
+
auth_user = _get_authed_user()
|
|
108
|
+
|
|
109
|
+
possible_teamspaces = self._get_possible_teamspaces(auth_user, self._owner)
|
|
109
110
|
if teamspace is None:
|
|
110
|
-
|
|
111
|
-
teamspace_dict = self._get_teamspace_from_interactive_menu(possible_teamspaces=possible_teamspaces)
|
|
111
|
+
teamspace_name = self._get_teamspace_from_interactive_menu(possible_teamspaces=possible_teamspaces)
|
|
112
112
|
else:
|
|
113
|
-
|
|
113
|
+
teamspace_name = self._get_teamspace_from_name(
|
|
114
114
|
teamspace=teamspace, possible_teamspaces=possible_teamspaces
|
|
115
115
|
)
|
|
116
116
|
|
|
117
|
-
return Teamspace(
|
|
117
|
+
return Teamspace(teamspace_name, org=org, user=user)
|
|
118
|
+
|
|
118
119
|
except KeyboardInterrupt:
|
|
119
120
|
raise KeyboardInterrupt from None
|
|
120
121
|
|
|
121
122
|
except Exception as e:
|
|
122
123
|
raise StudioCliError(
|
|
123
|
-
f"Could not find the given Teamspace {
|
|
124
|
+
f"Could not find the given Teamspace owned by {self._owner.name}. "
|
|
124
125
|
"Please contact Lightning AI directly to resolve this issue."
|
|
125
126
|
) from e
|
lightning_sdk/llm/llm.py
CHANGED
|
@@ -368,7 +368,7 @@ class LLM:
|
|
|
368
368
|
metadata: Optional[Dict[str, str]] = None,
|
|
369
369
|
stream: bool = False,
|
|
370
370
|
full_response: bool = False,
|
|
371
|
-
reasoning_effort: Optional[Literal["low", "medium", "
|
|
371
|
+
reasoning_effort: Optional[Literal["none", "low", "medium", "high"]] = None,
|
|
372
372
|
**kwargs: Any,
|
|
373
373
|
) -> Union[str, AsyncGenerator[str, None]]:
|
|
374
374
|
conversation_id = self._conversations.get(conversation) if conversation else None
|
|
@@ -404,13 +404,13 @@ class LLM:
|
|
|
404
404
|
stream: bool = False,
|
|
405
405
|
full_response: bool = False,
|
|
406
406
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
407
|
-
reasoning_effort: Optional[Literal["low", "medium", "high"]] = None,
|
|
407
|
+
reasoning_effort: Optional[Literal["none", "low", "medium", "high"]] = None,
|
|
408
408
|
**kwargs: Any,
|
|
409
409
|
) -> Union[
|
|
410
410
|
V1ConversationResponseChunk, Generator[V1ConversationResponseChunk, None, None], str, Generator[str, None, None]
|
|
411
411
|
]:
|
|
412
|
-
if reasoning_effort is not None and reasoning_effort not in ["low", "medium", "high"]:
|
|
413
|
-
raise ValueError("reasoning_effort must be 'low', 'medium', 'high', or None")
|
|
412
|
+
if reasoning_effort is not None and reasoning_effort not in ["none", "low", "medium", "high"]:
|
|
413
|
+
raise ValueError("reasoning_effort must be 'none', 'low', 'medium', 'high', or None")
|
|
414
414
|
|
|
415
415
|
if conversation and conversation not in self._conversations:
|
|
416
416
|
self._get_conversations()
|
lightning_sdk/machine.py
CHANGED
|
@@ -116,7 +116,7 @@ class Machine:
|
|
|
116
116
|
)
|
|
117
117
|
for m in possible_values:
|
|
118
118
|
for machine_id in [machine, *additional_machine_ids]:
|
|
119
|
-
if machine_id in (
|
|
119
|
+
if machine_id and machine_id in (
|
|
120
120
|
getattr(m, "name", None),
|
|
121
121
|
getattr(m, "instance_type", None),
|
|
122
122
|
getattr(m, "slug", None),
|
|
@@ -127,6 +127,21 @@ class Machine:
|
|
|
127
127
|
return cls(machine, *additional_machine_ids)
|
|
128
128
|
return cls(machine, machine, machine)
|
|
129
129
|
|
|
130
|
+
@classmethod
|
|
131
|
+
def _from_accelerator(cls, accelerator: Any) -> "Machine":
|
|
132
|
+
if accelerator.accelerator_type == "GPU":
|
|
133
|
+
accelerator_resources_count = accelerator.resources.gpu
|
|
134
|
+
else:
|
|
135
|
+
accelerator_resources_count = accelerator.resources.cpu
|
|
136
|
+
|
|
137
|
+
return Machine.from_str(
|
|
138
|
+
accelerator.slug_multi_cloud,
|
|
139
|
+
accelerator.slug,
|
|
140
|
+
accelerator.instance_id,
|
|
141
|
+
accelerator.secondary_instance_id,
|
|
142
|
+
f"lit-{accelerator.family.lower()}-{accelerator_resources_count}",
|
|
143
|
+
)
|
|
144
|
+
|
|
130
145
|
|
|
131
146
|
# CPU machines
|
|
132
147
|
# default CPU machines
|
lightning_sdk/teamspace.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import glob
|
|
2
2
|
import os
|
|
3
3
|
import warnings
|
|
4
|
+
from enum import Enum
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
|
|
6
7
|
|
|
@@ -8,9 +9,9 @@ from tqdm.auto import tqdm
|
|
|
8
9
|
|
|
9
10
|
import lightning_sdk
|
|
10
11
|
from lightning_sdk.agents import Agent
|
|
11
|
-
from lightning_sdk.api import TeamspaceApi
|
|
12
|
-
from lightning_sdk.lightning_cloud.openapi import V1Model, V1ModelVersionArchive, V1ProjectClusterBinding
|
|
13
|
-
from lightning_sdk.machine import Machine
|
|
12
|
+
from lightning_sdk.api import CloudAccountApi, TeamspaceApi
|
|
13
|
+
from lightning_sdk.lightning_cloud.openapi import V1ClusterType, V1Model, V1ModelVersionArchive, V1ProjectClusterBinding
|
|
14
|
+
from lightning_sdk.machine import CloudProvider, Machine
|
|
14
15
|
from lightning_sdk.models import UploadedModelInfo
|
|
15
16
|
from lightning_sdk.organization import Organization
|
|
16
17
|
from lightning_sdk.owner import Owner
|
|
@@ -30,6 +31,27 @@ if TYPE_CHECKING:
|
|
|
30
31
|
from lightning_sdk.studio import Studio
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
class FolderLocation(Enum):
|
|
35
|
+
AWS = "AWS"
|
|
36
|
+
GCP = "GCP"
|
|
37
|
+
CLOUD_AGNOSTIC = "CLOUD_AGNOSTIC"
|
|
38
|
+
|
|
39
|
+
def __str__(self) -> str:
|
|
40
|
+
"""Converts the FolderLocation to a str."""
|
|
41
|
+
return self.value
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ConnectionType(Enum):
|
|
45
|
+
EFS = "EFS"
|
|
46
|
+
S3 = "S3"
|
|
47
|
+
GCS = "GCS"
|
|
48
|
+
FILESTORE = "FILESTORE"
|
|
49
|
+
|
|
50
|
+
def __str__(self) -> str:
|
|
51
|
+
"""Converts the FolderLocation to a str."""
|
|
52
|
+
return self.value
|
|
53
|
+
|
|
54
|
+
|
|
33
55
|
class Teamspace:
|
|
34
56
|
"""A teamspace is a collection of Studios, Clusters, Members and an associated Budget.
|
|
35
57
|
|
|
@@ -54,6 +76,7 @@ class Teamspace:
|
|
|
54
76
|
user: Optional[Union[str, User]] = None,
|
|
55
77
|
) -> None:
|
|
56
78
|
self._teamspace_api = TeamspaceApi()
|
|
79
|
+
self._cloud_account_api = CloudAccountApi()
|
|
57
80
|
|
|
58
81
|
name = _resolve_teamspace_name(name)
|
|
59
82
|
|
|
@@ -515,6 +538,96 @@ class Teamspace:
|
|
|
515
538
|
cloud_account=self.default_cloud_account,
|
|
516
539
|
)
|
|
517
540
|
|
|
541
|
+
def new_folder(
|
|
542
|
+
self, name: str, location: Optional[FolderLocation] = None, cloud_account: Optional[str] = None
|
|
543
|
+
) -> None:
|
|
544
|
+
"""Create a new folder in this Teamspace.
|
|
545
|
+
|
|
546
|
+
Args:
|
|
547
|
+
name: The name of the folder. Folders will be accesible under `/teamspace/folders/<name>`
|
|
548
|
+
location: The location of the folder. Defaults to cloud agnostic.
|
|
549
|
+
cloud_account: The cloud account to create the folder in. Not used for cloud agnostic folders.
|
|
550
|
+
"""
|
|
551
|
+
if cloud_account is None:
|
|
552
|
+
cloud_account = self.default_cloud_account
|
|
553
|
+
|
|
554
|
+
cloud_accounts = self._cloud_account_api.list_cloud_accounts(self.id)
|
|
555
|
+
resolved_cloud_accounts = [
|
|
556
|
+
external_cloud for external_cloud in cloud_accounts if external_cloud.id == cloud_account
|
|
557
|
+
]
|
|
558
|
+
|
|
559
|
+
if len(resolved_cloud_accounts) == 0:
|
|
560
|
+
raise ValueError(f"Cloud account not found: {cloud_account}")
|
|
561
|
+
|
|
562
|
+
resolved_cloud_account = resolved_cloud_accounts[0]
|
|
563
|
+
|
|
564
|
+
# if the cloud account is global, default to agnostic
|
|
565
|
+
if location is None and resolved_cloud_account.spec.cluster_type == V1ClusterType.GLOBAL:
|
|
566
|
+
location = FolderLocation.CLOUD_AGNOSTIC
|
|
567
|
+
|
|
568
|
+
# if it's global, then default to agnostic, and aws / gcp otherwise if set
|
|
569
|
+
if (
|
|
570
|
+
location is not None
|
|
571
|
+
and location != FolderLocation.CLOUD_AGNOSTIC
|
|
572
|
+
and resolved_cloud_account.spec.cluster_type == V1ClusterType.GLOBAL
|
|
573
|
+
):
|
|
574
|
+
providers = self._cloud_account_api.get_cloud_account_provider_mapping(self.id)
|
|
575
|
+
|
|
576
|
+
if location == FolderLocation.AWS:
|
|
577
|
+
resolved_cloud_account = providers[CloudProvider.AWS]
|
|
578
|
+
elif location == FolderLocation.GCP:
|
|
579
|
+
resolved_cloud_account = providers[CloudProvider.GCP]
|
|
580
|
+
|
|
581
|
+
if location == FolderLocation.CLOUD_AGNOSTIC:
|
|
582
|
+
self._teamspace_api.new_folder(self.id, name, None)
|
|
583
|
+
else:
|
|
584
|
+
self._teamspace_api.new_folder(self.id, name, resolved_cloud_account)
|
|
585
|
+
|
|
586
|
+
return
|
|
587
|
+
|
|
588
|
+
def new_connection(
|
|
589
|
+
self,
|
|
590
|
+
name: str,
|
|
591
|
+
source: str,
|
|
592
|
+
connection_type: ConnectionType,
|
|
593
|
+
writable: bool = True,
|
|
594
|
+
cloud_account: Optional[str] = None,
|
|
595
|
+
region: Optional[str] = None,
|
|
596
|
+
) -> None:
|
|
597
|
+
"""Add an existing data source to this Teamspace.
|
|
598
|
+
|
|
599
|
+
Args:
|
|
600
|
+
name: the name under which your data will be available in this Teamspace
|
|
601
|
+
source: the source spec of your data. Format depends on the type of data to connect.
|
|
602
|
+
For EFS, this should be the filsystem id
|
|
603
|
+
connection_type: the kind of data to connect to this Teamspace
|
|
604
|
+
writable: whether to support write-back to this data source. If False, the data is connected as read-only
|
|
605
|
+
cloud_account: which cloud-account to connect to the data source to.
|
|
606
|
+
If not specified, will retrieve the cloud-account that matches the required provider type
|
|
607
|
+
starting with private cloud accounts and falling back to public if necessary.
|
|
608
|
+
region: which provider region this data is in. Required for some connection types only.
|
|
609
|
+
"""
|
|
610
|
+
provider_for_connection = self._cloud_account_api.get_cloud_provider_for_connection_type(connection_type)
|
|
611
|
+
|
|
612
|
+
if connection_type == ConnectionType.EFS and region is None:
|
|
613
|
+
raise ValueError("Region must be specified")
|
|
614
|
+
|
|
615
|
+
cloud_account = self._cloud_account_api.resolve_cloud_account(
|
|
616
|
+
self.id, cloud_account, provider_for_connection, None
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
cloud_accounts = self._cloud_account_api.list_cloud_accounts(self.id)
|
|
620
|
+
resolved_cloud_accounts = [
|
|
621
|
+
external_cloud for external_cloud in cloud_accounts if external_cloud.id == cloud_account
|
|
622
|
+
]
|
|
623
|
+
|
|
624
|
+
if len(resolved_cloud_accounts) == 0:
|
|
625
|
+
raise ValueError(f"Cloud account not found: {cloud_account}")
|
|
626
|
+
|
|
627
|
+
resolved_cloud_account = resolved_cloud_accounts[0]
|
|
628
|
+
|
|
629
|
+
self._teamspace_api.new_connection(self.id, name, source, resolved_cloud_account, writable, region or "")
|
|
630
|
+
|
|
518
631
|
|
|
519
632
|
def _list_files(path: Union[str, Path]) -> Tuple[List[Path], List[str]]:
|
|
520
633
|
"""List all folders in a directory and return them as a list and relative path."""
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
docs/source/conf.py,sha256=r8yX20eC-4mHhMTd0SbQb5TlSWHhO6wnJ0VJ_FBFpag,13249
|
|
2
|
-
lightning_sdk/__init__.py,sha256=
|
|
2
|
+
lightning_sdk/__init__.py,sha256=i1LQ7zzjJrjKEzaMjFBS0esHYmtvvMuXySVY_i34Upg,1221
|
|
3
3
|
lightning_sdk/agents.py,sha256=ly6Ma1j0ZgGPFyvPvMN28JWiB9dATIstFa5XM8pMi6I,1577
|
|
4
4
|
lightning_sdk/ai_hub.py,sha256=iI1vNhgcz_Ff1c3rN1ogN7dK-r-HXRj6NMtS2cA14UA,6925
|
|
5
5
|
lightning_sdk/base_studio.py,sha256=_Pwwl37R9GRd7t-f2kO5aQXiLNrP4sUtUNht2ZkP8LE,3678
|
|
6
6
|
lightning_sdk/constants.py,sha256=ztl1PTUBULnqTf3DyKUSJaV_O20hNtUYT6XvAYIrmIk,749
|
|
7
7
|
lightning_sdk/helpers.py,sha256=KWMWnORHItIIA3PGn71YPs-7RjzGi8IXa2kQ5Qo4U8M,2459
|
|
8
8
|
lightning_sdk/lit_container.py,sha256=8ys49TXI9MO89jLTA7MwDrKrssTRARAIF9OVmolDLq0,5273
|
|
9
|
-
lightning_sdk/machine.py,sha256=
|
|
9
|
+
lightning_sdk/machine.py,sha256=WXBAkO42GdvL3rYykVTl5UUhpQpnbLThngzymijBInk,9462
|
|
10
10
|
lightning_sdk/models.py,sha256=ur1My3oivAe0p2tAYtOAGM_1tPBht3Oh-xLun-oUK08,7861
|
|
11
11
|
lightning_sdk/organization.py,sha256=jizjG4oW_oxkP2Qz4vL5cle4Cg12xB_vf4eT-bnvLP0,1352
|
|
12
12
|
lightning_sdk/owner.py,sha256=t5svD2it4C9pbSpVuG9WJL46CYi37JXNziwnXxhiU5U,1361
|
|
@@ -15,24 +15,24 @@ lightning_sdk/sandbox.py,sha256=_NvnWotEXW2rBiVFZZ4krKXxVjuAqfNh04qELSM0-Pg,5786
|
|
|
15
15
|
lightning_sdk/serve.py,sha256=uW7zLhQ3X90ifetpxzTb8FNxifv5vIs7qZlgfEjVKzk,11794
|
|
16
16
|
lightning_sdk/status.py,sha256=lLGAuSvXBoXQFEEsEYwdCi0RcSNatUn5OPjJVjDtoM0,386
|
|
17
17
|
lightning_sdk/studio.py,sha256=3BE44Ya-2HXmDkF58lVQmd7KVzzzPktqX1SV7K3nkfo,31438
|
|
18
|
-
lightning_sdk/teamspace.py,sha256=
|
|
18
|
+
lightning_sdk/teamspace.py,sha256=eMatrnUr6E-ok96HIHRhghT2x_yEj_ToA6chSgYddGk,26265
|
|
19
19
|
lightning_sdk/user.py,sha256=TSYh38rxoi7qKOfrK2JYh_Nknya2Kbz2ngDIY85fFOY,1778
|
|
20
|
-
lightning_sdk/api/__init__.py,sha256=
|
|
20
|
+
lightning_sdk/api/__init__.py,sha256=xrp_RNECJGQtL5rZHF69WOzEuEIbWSLtjWAJAz4R5K4,500
|
|
21
21
|
lightning_sdk/api/agents_api.py,sha256=G47TbFo9kYqnBMqdw2RW-lfS1VAUBSXDmzs6fpIEMUs,4059
|
|
22
22
|
lightning_sdk/api/ai_hub_api.py,sha256=azqDZ-PzasVAcoQHno7k7OO_xFOHQ4NDozxF8jEh83Y,7864
|
|
23
23
|
lightning_sdk/api/base_studio_api.py,sha256=3R8tucZX2e9yKHBcY2rWFRP4dxqLrC6H75vdBDkH0ck,3617
|
|
24
|
-
lightning_sdk/api/cloud_account_api.py,sha256=
|
|
24
|
+
lightning_sdk/api/cloud_account_api.py,sha256=B9-Ixy6OESAH_5wn6gKJLpcazj_48eiFLRTpunuyzjc,9191
|
|
25
25
|
lightning_sdk/api/deployment_api.py,sha256=v2AfoTDkQ-1CBh75FOjFkRpf6yc3U_edDy43uYSn19I,24852
|
|
26
|
-
lightning_sdk/api/job_api.py,sha256=
|
|
26
|
+
lightning_sdk/api/job_api.py,sha256=4uaqLiEGRmvFk2chiOltbgAfEC7seeNTmsBENsaft88,16468
|
|
27
27
|
lightning_sdk/api/license_api.py,sha256=XV3RhefyPQDYjwY9AaBZe4rByZTEAnsvLDxcdm9q0Wo,2438
|
|
28
28
|
lightning_sdk/api/lit_container_api.py,sha256=jCJVwd-3MNjejL9FyvH89pzt-SeG3G8qCJD16iTMJAQ,11454
|
|
29
29
|
lightning_sdk/api/llm_api.py,sha256=8ouowlX-Ld0hRvueIS6fQqaEJLQMYskvhKV5-Z_A6gE,11886
|
|
30
|
-
lightning_sdk/api/mmt_api.py,sha256=
|
|
30
|
+
lightning_sdk/api/mmt_api.py,sha256=adVGNFpinnsE3lkY4QZhpWxq4ZQjhyC1XTmOhpBWXvk,10691
|
|
31
31
|
lightning_sdk/api/org_api.py,sha256=Ze3z_ATVrukobujV5YdC42DKj45Vuwl7X52q_Vr-o3U,803
|
|
32
32
|
lightning_sdk/api/pipeline_api.py,sha256=rJYp_FN7uUjC5xbc6K67l2eRSmVuOkijd5i8Nm5BF7I,4621
|
|
33
|
-
lightning_sdk/api/studio_api.py,sha256=
|
|
34
|
-
lightning_sdk/api/teamspace_api.py,sha256=
|
|
35
|
-
lightning_sdk/api/user_api.py,sha256=
|
|
33
|
+
lightning_sdk/api/studio_api.py,sha256=ZwyaRcjPiE2O5gZ3Ko5zuB_QtzzDLZI9vUF6k7Z9Hl0,39484
|
|
34
|
+
lightning_sdk/api/teamspace_api.py,sha256=UZ6Ka6TL7zggs5qhQB4wl47VRusVTMpth1-toGVWbjQ,19974
|
|
35
|
+
lightning_sdk/api/user_api.py,sha256=o9gZmtvqNfj4kdSpo2fyyRuFAP7bM5w7mx0Oj9__Ads,4702
|
|
36
36
|
lightning_sdk/api/utils.py,sha256=1NJgW4HCfzMqgnAqbMA7RRr2v3iM3KTuPIUQK5klDeQ,27127
|
|
37
37
|
lightning_sdk/cli/__init__.py,sha256=lksw08t_ZIuHOH47LCIqSVHeZ8cUXI2aJWHYhyujYHM,32
|
|
38
38
|
lightning_sdk/cli/entrypoint.py,sha256=85icG0fmUqXuFErkD2v_kOlqnr18veD8oxe7gPBWHE8,4556
|
|
@@ -83,11 +83,12 @@ lightning_sdk/cli/studio/switch.py,sha256=qhWhLvjk-BbwU8Br3rXPQIMVQLTUTq21f0v2P-
|
|
|
83
83
|
lightning_sdk/cli/utils/__init__.py,sha256=0gHdWY3bqrIyiFiEh_uSBuxWpOykCjqUc8fPEV0z3no,186
|
|
84
84
|
lightning_sdk/cli/utils/cloud_account_map.py,sha256=7oM7ns4ZJfkxxZhl-GMkxEkkinKbVkskx5dLcyEQiz4,414
|
|
85
85
|
lightning_sdk/cli/utils/coloring.py,sha256=YEb1LiYb6CekVfCRb83-npAmNgd-7c1LzXuNDo4GLSc,2415
|
|
86
|
+
lightning_sdk/cli/utils/owner_selection.py,sha256=PbKbFoGblxi60lF_kZxnlqxjCmI9r9b9iDZClHkJcpQ,4216
|
|
86
87
|
lightning_sdk/cli/utils/resolve.py,sha256=RWQ8MgXEJCdsoY50y8Pa9B-A6NA_SvxOqL5pVKfvSr8,917
|
|
87
88
|
lightning_sdk/cli/utils/richt_print.py,sha256=psSY65nLAQbxK_K0w93Qq9857aUUbm77FLS1sc3Oecg,1262
|
|
88
89
|
lightning_sdk/cli/utils/save_to_config.py,sha256=mMjjfA4Yv1e7MtE03iADTXcTSAuUL0Ws9OZObx6ufo0,1164
|
|
89
90
|
lightning_sdk/cli/utils/studio_selection.py,sha256=tjYTm4sY3NSQaa-6Ob9R0UQ60wIXiTNT2406BUJvJbU,3927
|
|
90
|
-
lightning_sdk/cli/utils/teamspace_selection.py,sha256=
|
|
91
|
+
lightning_sdk/cli/utils/teamspace_selection.py,sha256=n-FFfWLTV63SxoK6Fi2VQikBIfKYqMNTew9b9v-1UQk,4945
|
|
91
92
|
lightning_sdk/deployment/__init__.py,sha256=dXsa4psDzFYFklsq3JC-2V_L4FQjGZnQAf-ZiVlqG9c,545
|
|
92
93
|
lightning_sdk/deployment/deployment.py,sha256=7Sk4ORKmgMDk7Owpk_q-89ws8-Y9orX0jRZF99tNv1E,21775
|
|
93
94
|
lightning_sdk/job/__init__.py,sha256=1MxjQ6rHkyUHCypSW9RuXuVMVH11WiqhIXcU2LCFMwE,64
|
|
@@ -1152,7 +1153,7 @@ lightning_sdk/lightning_cloud/utils/dataset.py,sha256=4nUspe8iAaRPgSYpXA2uAQCgyd
|
|
|
1152
1153
|
lightning_sdk/lightning_cloud/utils/name_generator.py,sha256=MkciuA10332V0mcE2PxLIiwWomWE0Fm_gNGK01vwRr4,58046
|
|
1153
1154
|
lightning_sdk/lightning_cloud/utils/network.py,sha256=axPgl8rhyPcPjxiztDxyksfxax3VNg2OXL5F5Uc81b4,406
|
|
1154
1155
|
lightning_sdk/llm/__init__.py,sha256=ErZva0HqN2iPtK_6hI6GN7A_HPGNrHo3wYh7vyFdO3Q,57
|
|
1155
|
-
lightning_sdk/llm/llm.py,sha256=
|
|
1156
|
+
lightning_sdk/llm/llm.py,sha256=pjBs8fbGZjs0tQRKHx-WdfTmeECKAwI_T1ShVBgdyO4,20836
|
|
1156
1157
|
lightning_sdk/llm/public_assistants.py,sha256=k0yc41AyrKImnRa8Fv-ow9javnlrRQeP63507p2VybA,1579
|
|
1157
1158
|
lightning_sdk/mmt/__init__.py,sha256=ExMu90-96bGBnyp5h0CErQszUGB1-PcjC4-R8_NYbeY,117
|
|
1158
1159
|
lightning_sdk/mmt/base.py,sha256=iqVudKDxazomuezj6l7pa-m9I1EQnM82OKs4ZQbo4Ck,16434
|
|
@@ -1177,9 +1178,9 @@ lightning_sdk/utils/enum.py,sha256=h2JRzqoBcSlUdanFHmkj_j5DleBHAu1esQYUsdNI-hU,4
|
|
|
1177
1178
|
lightning_sdk/utils/names.py,sha256=1EuXbIh7wldkDp1FG10oz9vIOyWrpGWeFFVy-DQBgzA,18162
|
|
1178
1179
|
lightning_sdk/utils/progress.py,sha256=IXfEcUF-rL5jIw0Hir6eSxN7VBZfR--1O2LaEhGAU70,12698
|
|
1179
1180
|
lightning_sdk/utils/resolve.py,sha256=4TyEnIgIrvkSvYk5i5PmcIogD_5Y9pBhiphRLfLMttc,10477
|
|
1180
|
-
lightning_sdk-2025.9.
|
|
1181
|
-
lightning_sdk-2025.9.
|
|
1182
|
-
lightning_sdk-2025.9.
|
|
1183
|
-
lightning_sdk-2025.9.
|
|
1184
|
-
lightning_sdk-2025.9.
|
|
1185
|
-
lightning_sdk-2025.9.
|
|
1181
|
+
lightning_sdk-2025.9.23.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
|
|
1182
|
+
lightning_sdk-2025.9.23.dist-info/METADATA,sha256=vBeooGy4iWhjSE6eAD-ZHrX1v5_0CXTqb5UeSsCb8WQ,4130
|
|
1183
|
+
lightning_sdk-2025.9.23.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
1184
|
+
lightning_sdk-2025.9.23.dist-info/entry_points.txt,sha256=OoZa4Fc8NMs6GSN0cdA1J8e6couzAcL82CbM1yo4f_M,122
|
|
1185
|
+
lightning_sdk-2025.9.23.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
|
|
1186
|
+
lightning_sdk-2025.9.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|