lightning-sdk 2025.9.30__py3-none-any.whl → 2025.10.14__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 +1 -1
- lightning_sdk/api/cloud_account_api.py +0 -2
- lightning_sdk/api/studio_api.py +8 -0
- lightning_sdk/base_studio.py +23 -12
- lightning_sdk/cli/base_studio/__init__.py +10 -0
- lightning_sdk/cli/base_studio/list.py +45 -0
- lightning_sdk/cli/entrypoint.py +2 -0
- lightning_sdk/cli/groups.py +7 -0
- lightning_sdk/cli/studio/connect.py +117 -22
- lightning_sdk/cli/studio/ssh.py +3 -6
- lightning_sdk/cli/utils/ssh_connection.py +8 -0
- lightning_sdk/job/job.py +5 -0
- lightning_sdk/job/v1.py +8 -0
- lightning_sdk/job/v2.py +8 -0
- lightning_sdk/lightning_cloud/openapi/__init__.py +20 -0
- lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
- lightning_sdk/lightning_cloud/openapi/api/assistants_service_api.py +19 -19
- lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +105 -0
- lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +1463 -240
- lightning_sdk/lightning_cloud/openapi/api/sdk_command_history_service_api.py +141 -0
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +19 -0
- lightning_sdk/lightning_cloud/openapi/models/cloudspace_id_visibility_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/cluster_id_metrics_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/id_transfer_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/incident_id_messages_body.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/incidents_id_body.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/messages_message_id_body.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/project_id_incidents_body.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/storage_complete_body.py +15 -15
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_transfer_metadata.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_request.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_incident_message_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_incident_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_get_cloud_space_transfer_estimate_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_group_pod_metrics.py +1241 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident.py +539 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_message.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_job.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_kai_scheduler_queue_metrics.py +627 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_group_pod_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_incident_messages_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_incidents_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_kai_scheduler_queues_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_resource_visibility.py +1 -27
- lightning_sdk/lightning_cloud/openapi/models/v1_sdk_command_history_severity.py +104 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_sdk_command_history_type.py +104 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +157 -53
- lightning_sdk/machine.py +0 -1
- lightning_sdk/studio.py +42 -5
- lightning_sdk/utils/progress.py +32 -33
- {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/METADATA +1 -1
- {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/RECORD +69 -47
- {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/LICENSE +0 -0
- {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/WHEEL +0 -0
- {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/top_level.txt +0 -0
|
@@ -75,13 +75,18 @@ class V1UserFeatures(object):
|
|
|
75
75
|
'f247': 'bool',
|
|
76
76
|
'f248': 'bool',
|
|
77
77
|
'f250': 'bool',
|
|
78
|
-
'f251': 'bool',
|
|
79
78
|
'f252': 'bool',
|
|
80
79
|
'f253': 'bool',
|
|
81
80
|
'f254': 'bool',
|
|
82
81
|
'f255': 'bool',
|
|
83
82
|
'f257': 'bool',
|
|
84
83
|
'f258': 'bool',
|
|
84
|
+
'f259': 'bool',
|
|
85
|
+
'f260': 'bool',
|
|
86
|
+
'f261': 'bool',
|
|
87
|
+
'f262': 'bool',
|
|
88
|
+
'f263': 'bool',
|
|
89
|
+
'f264': 'bool',
|
|
85
90
|
'fair_share': 'bool',
|
|
86
91
|
'featured_studios_admin': 'bool',
|
|
87
92
|
'gcs_connections_optimized': 'bool',
|
|
@@ -116,7 +121,6 @@ class V1UserFeatures(object):
|
|
|
116
121
|
'runnable_public_studio_page': 'bool',
|
|
117
122
|
'security_docs': 'bool',
|
|
118
123
|
'show_dev_admin': 'bool',
|
|
119
|
-
'single_wallet': 'bool',
|
|
120
124
|
'slurm': 'bool',
|
|
121
125
|
'specialised_studios': 'bool',
|
|
122
126
|
'storage_overuse_deletion': 'bool',
|
|
@@ -164,13 +168,18 @@ class V1UserFeatures(object):
|
|
|
164
168
|
'f247': 'f247',
|
|
165
169
|
'f248': 'f248',
|
|
166
170
|
'f250': 'f250',
|
|
167
|
-
'f251': 'f251',
|
|
168
171
|
'f252': 'f252',
|
|
169
172
|
'f253': 'f253',
|
|
170
173
|
'f254': 'f254',
|
|
171
174
|
'f255': 'f255',
|
|
172
175
|
'f257': 'f257',
|
|
173
176
|
'f258': 'f258',
|
|
177
|
+
'f259': 'f259',
|
|
178
|
+
'f260': 'f260',
|
|
179
|
+
'f261': 'f261',
|
|
180
|
+
'f262': 'f262',
|
|
181
|
+
'f263': 'f263',
|
|
182
|
+
'f264': 'f264',
|
|
174
183
|
'fair_share': 'fairShare',
|
|
175
184
|
'featured_studios_admin': 'featuredStudiosAdmin',
|
|
176
185
|
'gcs_connections_optimized': 'gcsConnectionsOptimized',
|
|
@@ -205,7 +214,6 @@ class V1UserFeatures(object):
|
|
|
205
214
|
'runnable_public_studio_page': 'runnablePublicStudioPage',
|
|
206
215
|
'security_docs': 'securityDocs',
|
|
207
216
|
'show_dev_admin': 'showDevAdmin',
|
|
208
|
-
'single_wallet': 'singleWallet',
|
|
209
217
|
'slurm': 'slurm',
|
|
210
218
|
'specialised_studios': 'specialisedStudios',
|
|
211
219
|
'storage_overuse_deletion': 'storageOveruseDeletion',
|
|
@@ -218,7 +226,7 @@ class V1UserFeatures(object):
|
|
|
218
226
|
'writable_s3_connections': 'writableS3Connections'
|
|
219
227
|
}
|
|
220
228
|
|
|
221
|
-
def __init__(self, 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, byo_machine_type: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloudspace_schedules: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, control_center_monitoring: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_persistent_disk: 'bool' =None, drive_v2: 'bool' =None, enterprise_compute_admin: 'bool' =None, f227: 'bool' =None, f234: 'bool' =None, f236: 'bool' =None, f239: 'bool' =None, f240: 'bool' =None, f241: 'bool' =None, f243: 'bool' =None, f245: 'bool' =None, f247: 'bool' =None, f248: 'bool' =None, f250: 'bool' =None,
|
|
229
|
+
def __init__(self, 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, byo_machine_type: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloudspace_schedules: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, control_center_monitoring: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_persistent_disk: 'bool' =None, drive_v2: 'bool' =None, enterprise_compute_admin: 'bool' =None, f227: 'bool' =None, f234: 'bool' =None, f236: 'bool' =None, f239: 'bool' =None, f240: 'bool' =None, f241: 'bool' =None, f243: 'bool' =None, f245: 'bool' =None, f247: 'bool' =None, f248: 'bool' =None, f250: 'bool' =None, f252: 'bool' =None, f253: 'bool' =None, f254: 'bool' =None, f255: 'bool' =None, f257: 'bool' =None, f258: 'bool' =None, f259: 'bool' =None, f260: 'bool' =None, f261: 'bool' =None, f262: 'bool' =None, f263: 'bool' =None, f264: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, gcs_connections_optimized: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, kubernetes_cluster_ui: 'bool' =None, kubernetes_clusters: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, model_api_dashboard: 'bool' =None, multiple_studio_versions: 'bool' =None, nerf_fs_nonpaying: 'bool' =None, org_level_member_permissions: 'bool' =None, org_usage_limits: 'bool' =None, persistent_disk: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_sweeps: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, product_license: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, reserved_machines_tab: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, slurm: 'bool' =None, specialised_studios: 'bool' =None, storage_overuse_deletion: 'bool' =None, studio_config: 'bool' =None, studio_sharing_v2: 'bool' =None, studio_version_visibility: 'bool' =None, trainium2: 'bool' =None, vultr: 'bool' =None, weka: 'bool' =None, writable_s3_connections: 'bool' =None): # noqa: E501
|
|
222
230
|
"""V1UserFeatures - a model defined in Swagger""" # noqa: E501
|
|
223
231
|
self._affiliate_links = None
|
|
224
232
|
self._agents_v2 = None
|
|
@@ -254,13 +262,18 @@ class V1UserFeatures(object):
|
|
|
254
262
|
self._f247 = None
|
|
255
263
|
self._f248 = None
|
|
256
264
|
self._f250 = None
|
|
257
|
-
self._f251 = None
|
|
258
265
|
self._f252 = None
|
|
259
266
|
self._f253 = None
|
|
260
267
|
self._f254 = None
|
|
261
268
|
self._f255 = None
|
|
262
269
|
self._f257 = None
|
|
263
270
|
self._f258 = None
|
|
271
|
+
self._f259 = None
|
|
272
|
+
self._f260 = None
|
|
273
|
+
self._f261 = None
|
|
274
|
+
self._f262 = None
|
|
275
|
+
self._f263 = None
|
|
276
|
+
self._f264 = None
|
|
264
277
|
self._fair_share = None
|
|
265
278
|
self._featured_studios_admin = None
|
|
266
279
|
self._gcs_connections_optimized = None
|
|
@@ -295,7 +308,6 @@ class V1UserFeatures(object):
|
|
|
295
308
|
self._runnable_public_studio_page = None
|
|
296
309
|
self._security_docs = None
|
|
297
310
|
self._show_dev_admin = None
|
|
298
|
-
self._single_wallet = None
|
|
299
311
|
self._slurm = None
|
|
300
312
|
self._specialised_studios = None
|
|
301
313
|
self._storage_overuse_deletion = None
|
|
@@ -375,8 +387,6 @@ class V1UserFeatures(object):
|
|
|
375
387
|
self.f248 = f248
|
|
376
388
|
if f250 is not None:
|
|
377
389
|
self.f250 = f250
|
|
378
|
-
if f251 is not None:
|
|
379
|
-
self.f251 = f251
|
|
380
390
|
if f252 is not None:
|
|
381
391
|
self.f252 = f252
|
|
382
392
|
if f253 is not None:
|
|
@@ -389,6 +399,18 @@ class V1UserFeatures(object):
|
|
|
389
399
|
self.f257 = f257
|
|
390
400
|
if f258 is not None:
|
|
391
401
|
self.f258 = f258
|
|
402
|
+
if f259 is not None:
|
|
403
|
+
self.f259 = f259
|
|
404
|
+
if f260 is not None:
|
|
405
|
+
self.f260 = f260
|
|
406
|
+
if f261 is not None:
|
|
407
|
+
self.f261 = f261
|
|
408
|
+
if f262 is not None:
|
|
409
|
+
self.f262 = f262
|
|
410
|
+
if f263 is not None:
|
|
411
|
+
self.f263 = f263
|
|
412
|
+
if f264 is not None:
|
|
413
|
+
self.f264 = f264
|
|
392
414
|
if fair_share is not None:
|
|
393
415
|
self.fair_share = fair_share
|
|
394
416
|
if featured_studios_admin is not None:
|
|
@@ -457,8 +479,6 @@ class V1UserFeatures(object):
|
|
|
457
479
|
self.security_docs = security_docs
|
|
458
480
|
if show_dev_admin is not None:
|
|
459
481
|
self.show_dev_admin = show_dev_admin
|
|
460
|
-
if single_wallet is not None:
|
|
461
|
-
self.single_wallet = single_wallet
|
|
462
482
|
if slurm is not None:
|
|
463
483
|
self.slurm = slurm
|
|
464
484
|
if specialised_studios is not None:
|
|
@@ -1194,27 +1214,6 @@ class V1UserFeatures(object):
|
|
|
1194
1214
|
|
|
1195
1215
|
self._f250 = f250
|
|
1196
1216
|
|
|
1197
|
-
@property
|
|
1198
|
-
def f251(self) -> 'bool':
|
|
1199
|
-
"""Gets the f251 of this V1UserFeatures. # noqa: E501
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
:return: The f251 of this V1UserFeatures. # noqa: E501
|
|
1203
|
-
:rtype: bool
|
|
1204
|
-
"""
|
|
1205
|
-
return self._f251
|
|
1206
|
-
|
|
1207
|
-
@f251.setter
|
|
1208
|
-
def f251(self, f251: 'bool'):
|
|
1209
|
-
"""Sets the f251 of this V1UserFeatures.
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
:param f251: The f251 of this V1UserFeatures. # noqa: E501
|
|
1213
|
-
:type: bool
|
|
1214
|
-
"""
|
|
1215
|
-
|
|
1216
|
-
self._f251 = f251
|
|
1217
|
-
|
|
1218
1217
|
@property
|
|
1219
1218
|
def f252(self) -> 'bool':
|
|
1220
1219
|
"""Gets the f252 of this V1UserFeatures. # noqa: E501
|
|
@@ -1341,6 +1340,132 @@ class V1UserFeatures(object):
|
|
|
1341
1340
|
|
|
1342
1341
|
self._f258 = f258
|
|
1343
1342
|
|
|
1343
|
+
@property
|
|
1344
|
+
def f259(self) -> 'bool':
|
|
1345
|
+
"""Gets the f259 of this V1UserFeatures. # noqa: E501
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
:return: The f259 of this V1UserFeatures. # noqa: E501
|
|
1349
|
+
:rtype: bool
|
|
1350
|
+
"""
|
|
1351
|
+
return self._f259
|
|
1352
|
+
|
|
1353
|
+
@f259.setter
|
|
1354
|
+
def f259(self, f259: 'bool'):
|
|
1355
|
+
"""Sets the f259 of this V1UserFeatures.
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
:param f259: The f259 of this V1UserFeatures. # noqa: E501
|
|
1359
|
+
:type: bool
|
|
1360
|
+
"""
|
|
1361
|
+
|
|
1362
|
+
self._f259 = f259
|
|
1363
|
+
|
|
1364
|
+
@property
|
|
1365
|
+
def f260(self) -> 'bool':
|
|
1366
|
+
"""Gets the f260 of this V1UserFeatures. # noqa: E501
|
|
1367
|
+
|
|
1368
|
+
|
|
1369
|
+
:return: The f260 of this V1UserFeatures. # noqa: E501
|
|
1370
|
+
:rtype: bool
|
|
1371
|
+
"""
|
|
1372
|
+
return self._f260
|
|
1373
|
+
|
|
1374
|
+
@f260.setter
|
|
1375
|
+
def f260(self, f260: 'bool'):
|
|
1376
|
+
"""Sets the f260 of this V1UserFeatures.
|
|
1377
|
+
|
|
1378
|
+
|
|
1379
|
+
:param f260: The f260 of this V1UserFeatures. # noqa: E501
|
|
1380
|
+
:type: bool
|
|
1381
|
+
"""
|
|
1382
|
+
|
|
1383
|
+
self._f260 = f260
|
|
1384
|
+
|
|
1385
|
+
@property
|
|
1386
|
+
def f261(self) -> 'bool':
|
|
1387
|
+
"""Gets the f261 of this V1UserFeatures. # noqa: E501
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
:return: The f261 of this V1UserFeatures. # noqa: E501
|
|
1391
|
+
:rtype: bool
|
|
1392
|
+
"""
|
|
1393
|
+
return self._f261
|
|
1394
|
+
|
|
1395
|
+
@f261.setter
|
|
1396
|
+
def f261(self, f261: 'bool'):
|
|
1397
|
+
"""Sets the f261 of this V1UserFeatures.
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
:param f261: The f261 of this V1UserFeatures. # noqa: E501
|
|
1401
|
+
:type: bool
|
|
1402
|
+
"""
|
|
1403
|
+
|
|
1404
|
+
self._f261 = f261
|
|
1405
|
+
|
|
1406
|
+
@property
|
|
1407
|
+
def f262(self) -> 'bool':
|
|
1408
|
+
"""Gets the f262 of this V1UserFeatures. # noqa: E501
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
:return: The f262 of this V1UserFeatures. # noqa: E501
|
|
1412
|
+
:rtype: bool
|
|
1413
|
+
"""
|
|
1414
|
+
return self._f262
|
|
1415
|
+
|
|
1416
|
+
@f262.setter
|
|
1417
|
+
def f262(self, f262: 'bool'):
|
|
1418
|
+
"""Sets the f262 of this V1UserFeatures.
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
:param f262: The f262 of this V1UserFeatures. # noqa: E501
|
|
1422
|
+
:type: bool
|
|
1423
|
+
"""
|
|
1424
|
+
|
|
1425
|
+
self._f262 = f262
|
|
1426
|
+
|
|
1427
|
+
@property
|
|
1428
|
+
def f263(self) -> 'bool':
|
|
1429
|
+
"""Gets the f263 of this V1UserFeatures. # noqa: E501
|
|
1430
|
+
|
|
1431
|
+
|
|
1432
|
+
:return: The f263 of this V1UserFeatures. # noqa: E501
|
|
1433
|
+
:rtype: bool
|
|
1434
|
+
"""
|
|
1435
|
+
return self._f263
|
|
1436
|
+
|
|
1437
|
+
@f263.setter
|
|
1438
|
+
def f263(self, f263: 'bool'):
|
|
1439
|
+
"""Sets the f263 of this V1UserFeatures.
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
:param f263: The f263 of this V1UserFeatures. # noqa: E501
|
|
1443
|
+
:type: bool
|
|
1444
|
+
"""
|
|
1445
|
+
|
|
1446
|
+
self._f263 = f263
|
|
1447
|
+
|
|
1448
|
+
@property
|
|
1449
|
+
def f264(self) -> 'bool':
|
|
1450
|
+
"""Gets the f264 of this V1UserFeatures. # noqa: E501
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
:return: The f264 of this V1UserFeatures. # noqa: E501
|
|
1454
|
+
:rtype: bool
|
|
1455
|
+
"""
|
|
1456
|
+
return self._f264
|
|
1457
|
+
|
|
1458
|
+
@f264.setter
|
|
1459
|
+
def f264(self, f264: 'bool'):
|
|
1460
|
+
"""Sets the f264 of this V1UserFeatures.
|
|
1461
|
+
|
|
1462
|
+
|
|
1463
|
+
:param f264: The f264 of this V1UserFeatures. # noqa: E501
|
|
1464
|
+
:type: bool
|
|
1465
|
+
"""
|
|
1466
|
+
|
|
1467
|
+
self._f264 = f264
|
|
1468
|
+
|
|
1344
1469
|
@property
|
|
1345
1470
|
def fair_share(self) -> 'bool':
|
|
1346
1471
|
"""Gets the fair_share of this V1UserFeatures. # noqa: E501
|
|
@@ -2055,27 +2180,6 @@ class V1UserFeatures(object):
|
|
|
2055
2180
|
|
|
2056
2181
|
self._show_dev_admin = show_dev_admin
|
|
2057
2182
|
|
|
2058
|
-
@property
|
|
2059
|
-
def single_wallet(self) -> 'bool':
|
|
2060
|
-
"""Gets the single_wallet of this V1UserFeatures. # noqa: E501
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
:return: The single_wallet of this V1UserFeatures. # noqa: E501
|
|
2064
|
-
:rtype: bool
|
|
2065
|
-
"""
|
|
2066
|
-
return self._single_wallet
|
|
2067
|
-
|
|
2068
|
-
@single_wallet.setter
|
|
2069
|
-
def single_wallet(self, single_wallet: 'bool'):
|
|
2070
|
-
"""Sets the single_wallet of this V1UserFeatures.
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
:param single_wallet: The single_wallet of this V1UserFeatures. # noqa: E501
|
|
2074
|
-
:type: bool
|
|
2075
|
-
"""
|
|
2076
|
-
|
|
2077
|
-
self._single_wallet = single_wallet
|
|
2078
|
-
|
|
2079
2183
|
@property
|
|
2080
2184
|
def slurm(self) -> 'bool':
|
|
2081
2185
|
"""Gets the slurm of this V1UserFeatures. # noqa: E501
|
lightning_sdk/machine.py
CHANGED
lightning_sdk/studio.py
CHANGED
|
@@ -8,6 +8,7 @@ from tqdm.auto import tqdm
|
|
|
8
8
|
|
|
9
9
|
from lightning_sdk.api.cloud_account_api import CloudAccountApi
|
|
10
10
|
from lightning_sdk.api.studio_api import StudioApi
|
|
11
|
+
from lightning_sdk.base_studio import BaseStudio
|
|
11
12
|
from lightning_sdk.constants import _LIGHTNING_DEBUG
|
|
12
13
|
from lightning_sdk.lightning_cloud.openapi import V1ClusterType
|
|
13
14
|
from lightning_sdk.machine import CloudProvider, Machine
|
|
@@ -51,6 +52,8 @@ class Studio:
|
|
|
51
52
|
If not specified, falls backto the teamspace default cloud account.
|
|
52
53
|
create_ok: whether the studio will be created if it does not yet exist. Defaults to True
|
|
53
54
|
provider: the provider of the machine, the studio should be created on.
|
|
55
|
+
studio_type: Type of studio to create. Only effective during initial creation;
|
|
56
|
+
ignored for existing studios.
|
|
54
57
|
|
|
55
58
|
Note:
|
|
56
59
|
Since a teamspace can either be owned by an org or by a user directly,
|
|
@@ -78,6 +81,7 @@ class Studio:
|
|
|
78
81
|
source: Optional[str] = None,
|
|
79
82
|
disable_secrets: bool = False,
|
|
80
83
|
provider: Optional[Union[CloudProvider, str]] = None, # deprecated in favor of cloud_provider
|
|
84
|
+
studio_type: Optional[str] = None, # for base studio templates
|
|
81
85
|
) -> None:
|
|
82
86
|
self._studio_api = StudioApi()
|
|
83
87
|
self._cloud_account_api = CloudAccountApi()
|
|
@@ -113,6 +117,25 @@ class Studio:
|
|
|
113
117
|
default_cloud_account=self._teamspace.default_cloud_account,
|
|
114
118
|
)
|
|
115
119
|
|
|
120
|
+
self._studio_type = None
|
|
121
|
+
if studio_type:
|
|
122
|
+
self._base_studio = BaseStudio()
|
|
123
|
+
self._available_base_studios = self._base_studio.list()
|
|
124
|
+
for bst in self._available_base_studios:
|
|
125
|
+
if (
|
|
126
|
+
bst.id == studio_type
|
|
127
|
+
or bst.name == studio_type
|
|
128
|
+
or bst.name.lower().replace(" ", "-") == studio_type
|
|
129
|
+
):
|
|
130
|
+
self._studio_type = bst.id
|
|
131
|
+
|
|
132
|
+
if not self._studio_type:
|
|
133
|
+
raise ValueError(
|
|
134
|
+
f"Could not find studio type with ID or name '{studio_type}'. "
|
|
135
|
+
f"Available studio types: "
|
|
136
|
+
f"{[bst.name.lower().replace(' ', '-') for bst in self._available_base_studios]}"
|
|
137
|
+
)
|
|
138
|
+
|
|
116
139
|
# Resolve studio name if not provided: explicit → env (LIGHTNING_CLOUD_SPACE_ID) → config defaults
|
|
117
140
|
if name is None and not getattr(self._skip_init, "value", False):
|
|
118
141
|
studio_id = os.environ.get("LIGHTNING_CLOUD_SPACE_ID", None)
|
|
@@ -150,6 +173,7 @@ class Studio:
|
|
|
150
173
|
cloud_account=_cloud_account,
|
|
151
174
|
source=source,
|
|
152
175
|
disable_secrets=self._disable_secrets,
|
|
176
|
+
cloud_space_environment_template_id=self._studio_type,
|
|
153
177
|
)
|
|
154
178
|
else:
|
|
155
179
|
raise e
|
|
@@ -218,6 +242,14 @@ class Studio:
|
|
|
218
242
|
_get_org_id(self._teamspace),
|
|
219
243
|
)
|
|
220
244
|
|
|
245
|
+
@property
|
|
246
|
+
def public_ip(self) -> Optional[str]:
|
|
247
|
+
"""Returns the public IP address of the machine the Studio is running on."""
|
|
248
|
+
return self._studio_api.get_public_ip(
|
|
249
|
+
self._studio.id,
|
|
250
|
+
self._teamspace.id,
|
|
251
|
+
)
|
|
252
|
+
|
|
221
253
|
@property
|
|
222
254
|
def interruptible(self) -> bool:
|
|
223
255
|
"""Returns whether the Studio is running on a interruptible instance."""
|
|
@@ -264,10 +296,11 @@ class Studio:
|
|
|
264
296
|
else:
|
|
265
297
|
interruptible = self.teamspace.start_studios_on_interruptible
|
|
266
298
|
|
|
299
|
+
new_machine = machine
|
|
300
|
+
if not isinstance(machine, Machine):
|
|
301
|
+
new_machine = Machine.from_str(machine)
|
|
302
|
+
|
|
267
303
|
if status == Status.Running:
|
|
268
|
-
new_machine = machine
|
|
269
|
-
if not isinstance(machine, Machine):
|
|
270
|
-
new_machine = Machine.from_str(machine)
|
|
271
304
|
if new_machine != self.machine:
|
|
272
305
|
raise RuntimeError(
|
|
273
306
|
f"Requested to start {self._cls_name} on {new_machine}, "
|
|
@@ -289,7 +322,11 @@ class Studio:
|
|
|
289
322
|
with StudioProgressTracker("start", show_progress=True) as progress:
|
|
290
323
|
# Start the studio without blocking
|
|
291
324
|
self._studio_api.start_studio_async(
|
|
292
|
-
self._studio.id,
|
|
325
|
+
self._studio.id,
|
|
326
|
+
self._teamspace.id,
|
|
327
|
+
new_machine,
|
|
328
|
+
interruptible=interruptible,
|
|
329
|
+
max_runtime=max_runtime,
|
|
293
330
|
)
|
|
294
331
|
|
|
295
332
|
# Track progress through completion
|
|
@@ -299,7 +336,7 @@ class Studio:
|
|
|
299
336
|
else:
|
|
300
337
|
# Use the blocking version if no progress is needed
|
|
301
338
|
self._studio_api.start_studio(
|
|
302
|
-
self._studio.id, self._teamspace.id,
|
|
339
|
+
self._studio.id, self._teamspace.id, new_machine, interruptible=interruptible, max_runtime=max_runtime
|
|
303
340
|
)
|
|
304
341
|
|
|
305
342
|
self._setup()
|
lightning_sdk/utils/progress.py
CHANGED
|
@@ -17,30 +17,31 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_get_cloud_space_instance_st
|
|
|
17
17
|
class StartupPhase(Enum):
|
|
18
18
|
"""Studio startup phase messages."""
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
SETTING_UP_ENVIRONMENT = "Setting up Studio environment..."
|
|
23
|
-
RESTORING_STATE = "Restoring Studio state..."
|
|
24
|
-
FINALIZING_SETUP = "Finalizing Studio setup..."
|
|
25
|
-
COMPLETED = "Studio started successfully"
|
|
20
|
+
STARTING_STUDIO = "Starting Studio..."
|
|
21
|
+
GETTING_MACHINE = "Getting a machine..."
|
|
26
22
|
|
|
23
|
+
SWITCHING_STUDIO = "Switching Studio..."
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
SETTING_UP_MACHINE = "Setting up machine..."
|
|
26
|
+
RESTORING_STUDIO = "Restoring Studio..."
|
|
27
|
+
PREPARING_STUDIO = "Preparing Studio..."
|
|
28
|
+
RESTORING_BASE_STUDIO = "Restoring Base Studio..."
|
|
29
|
+
SETTING_UP_BASE_STUDIO = "Setting up Base Studio..."
|
|
30
|
+
DONE = "Done"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_switching_progress_message(percentage: int, is_base_studio: bool) -> str:
|
|
29
34
|
"""Get progress message for switching studios."""
|
|
30
35
|
percentage = max(0, min(100, round(percentage)))
|
|
31
36
|
|
|
32
37
|
if percentage > 98:
|
|
33
|
-
message =
|
|
38
|
+
message = StartupPhase.DONE.value
|
|
34
39
|
elif percentage > 80:
|
|
35
|
-
if
|
|
36
|
-
message = "Setting up Base Studio..." if is_base_studio else "Preparing Studio..."
|
|
37
|
-
else:
|
|
38
|
-
message = "Restoring Studio..."
|
|
40
|
+
message = StartupPhase.RESTORING_BASE_STUDIO.value if is_base_studio else StartupPhase.RESTORING_STUDIO.value
|
|
39
41
|
elif percentage > 60:
|
|
40
|
-
message =
|
|
42
|
+
message = StartupPhase.SETTING_UP_MACHINE.value
|
|
41
43
|
else:
|
|
42
|
-
message =
|
|
43
|
-
|
|
44
|
+
message = StartupPhase.SWITCHING_STUDIO.value
|
|
44
45
|
return f"({percentage}%) {message}"
|
|
45
46
|
|
|
46
47
|
|
|
@@ -110,15 +111,13 @@ class StudioProgressTracker:
|
|
|
110
111
|
if self.progress:
|
|
111
112
|
self.progress.stop()
|
|
112
113
|
|
|
113
|
-
def update_progress(
|
|
114
|
-
self, percentage: int, message: str = "", is_base_studio: bool = False, is_new_cloud_space: bool = False
|
|
115
|
-
) -> None:
|
|
114
|
+
def update_progress(self, percentage: int, message: str = "", is_base_studio: bool = False) -> None:
|
|
116
115
|
"""Update progress bar with current percentage and message."""
|
|
117
116
|
if not self.progress or self.task_id is None:
|
|
118
117
|
return
|
|
119
118
|
|
|
120
119
|
if self.operation_type == "switch":
|
|
121
|
-
display_message = get_switching_progress_message(percentage, is_base_studio
|
|
120
|
+
display_message = get_switching_progress_message(percentage, is_base_studio)
|
|
122
121
|
else:
|
|
123
122
|
display_message = message or f"{self.operation_type.capitalize()}ing Studio..."
|
|
124
123
|
|
|
@@ -153,7 +152,7 @@ class StudioProgressTracker:
|
|
|
153
152
|
message_stability_delay = 3.0 # Seconds to wait before changing message
|
|
154
153
|
|
|
155
154
|
# Show initial progress immediately
|
|
156
|
-
self.update_progress(5, StartupPhase.
|
|
155
|
+
self.update_progress(5, StartupPhase.STARTING_STUDIO.value)
|
|
157
156
|
|
|
158
157
|
while True:
|
|
159
158
|
try:
|
|
@@ -163,7 +162,7 @@ class StudioProgressTracker:
|
|
|
163
162
|
# Default fallback progress based on time
|
|
164
163
|
time_based_progress = min(95, int((elapsed / timeout) * 100))
|
|
165
164
|
current_progress = max(last_progress, time_based_progress)
|
|
166
|
-
current_message = StartupPhase.
|
|
165
|
+
current_message = StartupPhase.STARTING_STUDIO.value
|
|
167
166
|
|
|
168
167
|
# Check if we have detailed status information
|
|
169
168
|
if hasattr(status, "in_use") and status.in_use:
|
|
@@ -178,7 +177,7 @@ class StudioProgressTracker:
|
|
|
178
177
|
hasattr(startup_status, "top_up_restore_finished")
|
|
179
178
|
and startup_status.top_up_restore_finished
|
|
180
179
|
):
|
|
181
|
-
self.complete(StartupPhase.
|
|
180
|
+
self.complete(StartupPhase.DONE.value)
|
|
182
181
|
break
|
|
183
182
|
|
|
184
183
|
# Check other phases in descending priority
|
|
@@ -186,14 +185,14 @@ class StudioProgressTracker:
|
|
|
186
185
|
hasattr(startup_status, "initial_restore_finished")
|
|
187
186
|
and startup_status.initial_restore_finished
|
|
188
187
|
):
|
|
189
|
-
current_progress = max(current_progress,
|
|
190
|
-
current_message = StartupPhase.
|
|
188
|
+
current_progress = max(current_progress, 80)
|
|
189
|
+
current_message = StartupPhase.PREPARING_STUDIO.value
|
|
191
190
|
elif hasattr(startup_status, "container_ready") and startup_status.container_ready:
|
|
192
|
-
current_progress = max(current_progress, 70)
|
|
193
|
-
current_message = StartupPhase.RESTORING_STATE.value
|
|
194
|
-
elif hasattr(startup_status, "machine_ready") and startup_status.machine_ready:
|
|
195
191
|
current_progress = max(current_progress, 60)
|
|
196
|
-
current_message = StartupPhase.
|
|
192
|
+
current_message = StartupPhase.SETTING_UP_MACHINE.value
|
|
193
|
+
elif hasattr(startup_status, "machine_ready") and startup_status.machine_ready:
|
|
194
|
+
current_progress = max(current_progress, 30)
|
|
195
|
+
current_message = StartupPhase.GETTING_MACHINE.value
|
|
197
196
|
|
|
198
197
|
# Check general phase information
|
|
199
198
|
if hasattr(in_use, "phase") and in_use.phase:
|
|
@@ -201,7 +200,7 @@ class StudioProgressTracker:
|
|
|
201
200
|
|
|
202
201
|
if phase == "CLOUD_SPACE_INSTANCE_STATE_RUNNING":
|
|
203
202
|
current_progress = max(current_progress, 80)
|
|
204
|
-
current_message = StartupPhase.
|
|
203
|
+
current_message = StartupPhase.SETTING_UP_MACHINE.value
|
|
205
204
|
elif phase == "CLOUD_SPACE_INSTANCE_STATE_PENDING":
|
|
206
205
|
# Track time in pending phase for smoother progress
|
|
207
206
|
if "pending" not in phase_start_times:
|
|
@@ -211,7 +210,7 @@ class StudioProgressTracker:
|
|
|
211
210
|
# Progress more smoothly through pending phase (10-60%)
|
|
212
211
|
pending_progress = 10 + min(50, int((pending_elapsed / 60) * 50))
|
|
213
212
|
current_progress = max(current_progress, pending_progress)
|
|
214
|
-
current_message = StartupPhase.
|
|
213
|
+
current_message = StartupPhase.GETTING_MACHINE.value
|
|
215
214
|
|
|
216
215
|
# Check for requested machine status (pre-allocation)
|
|
217
216
|
elif hasattr(status, "requested") and status.requested:
|
|
@@ -222,7 +221,7 @@ class StudioProgressTracker:
|
|
|
222
221
|
# Progress through allocation phase (5-30%)
|
|
223
222
|
allocation_progress = 5 + min(25, int((allocation_elapsed / 30) * 25))
|
|
224
223
|
current_progress = max(current_progress, allocation_progress)
|
|
225
|
-
current_message = StartupPhase.
|
|
224
|
+
current_message = StartupPhase.GETTING_MACHINE.value
|
|
226
225
|
|
|
227
226
|
# Ensure progress never decreases and moves smoothly
|
|
228
227
|
if current_progress > last_progress:
|
|
@@ -262,12 +261,12 @@ class StudioProgressTracker:
|
|
|
262
261
|
|
|
263
262
|
# Only update message if enough time has passed
|
|
264
263
|
current_time = time.time()
|
|
265
|
-
should_update_message = StartupPhase.
|
|
264
|
+
should_update_message = StartupPhase.GETTING_MACHINE.value != self._last_message and (
|
|
266
265
|
current_time - last_message_time >= message_stability_delay or last_message_time == 0
|
|
267
266
|
)
|
|
268
267
|
|
|
269
268
|
if should_update_message:
|
|
270
|
-
self.update_progress(fallback_progress, StartupPhase.
|
|
269
|
+
self.update_progress(fallback_progress, StartupPhase.GETTING_MACHINE.value)
|
|
271
270
|
last_message_time = current_time
|
|
272
271
|
else:
|
|
273
272
|
# Update progress but keep existing message
|