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.
Files changed (69) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/api/cloud_account_api.py +0 -2
  3. lightning_sdk/api/studio_api.py +8 -0
  4. lightning_sdk/base_studio.py +23 -12
  5. lightning_sdk/cli/base_studio/__init__.py +10 -0
  6. lightning_sdk/cli/base_studio/list.py +45 -0
  7. lightning_sdk/cli/entrypoint.py +2 -0
  8. lightning_sdk/cli/groups.py +7 -0
  9. lightning_sdk/cli/studio/connect.py +117 -22
  10. lightning_sdk/cli/studio/ssh.py +3 -6
  11. lightning_sdk/cli/utils/ssh_connection.py +8 -0
  12. lightning_sdk/job/job.py +5 -0
  13. lightning_sdk/job/v1.py +8 -0
  14. lightning_sdk/job/v2.py +8 -0
  15. lightning_sdk/lightning_cloud/openapi/__init__.py +20 -0
  16. lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
  17. lightning_sdk/lightning_cloud/openapi/api/assistants_service_api.py +19 -19
  18. lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +105 -0
  19. lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +1463 -240
  20. lightning_sdk/lightning_cloud/openapi/api/sdk_command_history_service_api.py +141 -0
  21. lightning_sdk/lightning_cloud/openapi/models/__init__.py +19 -0
  22. lightning_sdk/lightning_cloud/openapi/models/cloudspace_id_visibility_body.py +27 -1
  23. lightning_sdk/lightning_cloud/openapi/models/cluster_id_metrics_body.py +53 -1
  24. lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +27 -1
  25. lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +53 -1
  26. lightning_sdk/lightning_cloud/openapi/models/id_transfer_body.py +53 -1
  27. lightning_sdk/lightning_cloud/openapi/models/incident_id_messages_body.py +149 -0
  28. lightning_sdk/lightning_cloud/openapi/models/incidents_id_body.py +279 -0
  29. lightning_sdk/lightning_cloud/openapi/models/messages_message_id_body.py +149 -0
  30. lightning_sdk/lightning_cloud/openapi/models/project_id_incidents_body.py +279 -0
  31. lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +27 -1
  32. lightning_sdk/lightning_cloud/openapi/models/storage_complete_body.py +15 -15
  33. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_transfer_metadata.py +53 -1
  34. lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +27 -1
  35. lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_request.py +253 -0
  36. lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_response.py +97 -0
  37. lightning_sdk/lightning_cloud/openapi/models/v1_delete_incident_message_response.py +97 -0
  38. lightning_sdk/lightning_cloud/openapi/models/v1_delete_incident_response.py +97 -0
  39. lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +27 -1
  40. lightning_sdk/lightning_cloud/openapi/models/v1_get_cloud_space_transfer_estimate_response.py +123 -0
  41. lightning_sdk/lightning_cloud/openapi/models/v1_group_pod_metrics.py +1241 -0
  42. lightning_sdk/lightning_cloud/openapi/models/v1_incident.py +539 -0
  43. lightning_sdk/lightning_cloud/openapi/models/v1_incident_message.py +253 -0
  44. lightning_sdk/lightning_cloud/openapi/models/v1_incident_type.py +1 -0
  45. lightning_sdk/lightning_cloud/openapi/models/v1_job.py +53 -1
  46. lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +27 -1
  47. lightning_sdk/lightning_cloud/openapi/models/v1_kai_scheduler_queue_metrics.py +627 -0
  48. lightning_sdk/lightning_cloud/openapi/models/v1_list_group_pod_metrics_response.py +123 -0
  49. lightning_sdk/lightning_cloud/openapi/models/v1_list_incident_messages_response.py +149 -0
  50. lightning_sdk/lightning_cloud/openapi/models/v1_list_incidents_response.py +149 -0
  51. lightning_sdk/lightning_cloud/openapi/models/v1_list_kai_scheduler_queues_metrics_response.py +123 -0
  52. lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +53 -1
  53. lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +27 -1
  54. lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +27 -1
  55. lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +27 -1
  56. lightning_sdk/lightning_cloud/openapi/models/v1_resource_visibility.py +1 -27
  57. lightning_sdk/lightning_cloud/openapi/models/v1_sdk_command_history_severity.py +104 -0
  58. lightning_sdk/lightning_cloud/openapi/models/v1_sdk_command_history_type.py +104 -0
  59. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_type.py +1 -0
  60. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +157 -53
  61. lightning_sdk/machine.py +0 -1
  62. lightning_sdk/studio.py +42 -5
  63. lightning_sdk/utils/progress.py +32 -33
  64. {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/METADATA +1 -1
  65. {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/RECORD +69 -47
  66. {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/LICENSE +0 -0
  67. {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/WHEEL +0 -0
  68. {lightning_sdk-2025.9.30.dist-info → lightning_sdk-2025.10.14.dist-info}/entry_points.txt +0 -0
  69. {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, f251: 'bool' =None, f252: 'bool' =None, f253: 'bool' =None, f254: 'bool' =None, f255: 'bool' =None, f257: 'bool' =None, f258: '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, single_wallet: '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
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
@@ -6,7 +6,6 @@ from typing import Any, ClassVar, Optional, Tuple
6
6
  class CloudProvider(Enum):
7
7
  AWS = "AWS"
8
8
  GCP = "GCP"
9
- VULTR = "VULTR"
10
9
  LAMBDA_LABS = "LAMBDA_LABS"
11
10
  DGX = "DGX"
12
11
  VOLTAGE_PARK = "VOLTAGE_PARK"
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, self._teamspace.id, machine, interruptible=interruptible, max_runtime=max_runtime
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, machine, interruptible=interruptible, max_runtime=max_runtime
339
+ self._studio.id, self._teamspace.id, new_machine, interruptible=interruptible, max_runtime=max_runtime
303
340
  )
304
341
 
305
342
  self._setup()
@@ -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
- ALLOCATING_MACHINE = "Allocating machine from cloud provider..."
21
- STUDIO_STARTING = "Studio is starting up..."
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
- def get_switching_progress_message(percentage: int, is_base_studio: bool, is_new_cloud_space: bool) -> str:
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 = "Done"
38
+ message = StartupPhase.DONE.value
34
39
  elif percentage > 80:
35
- if is_new_cloud_space:
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 = "Setting up machine from cloud provider"
42
+ message = StartupPhase.SETTING_UP_MACHINE.value
41
43
  else:
42
- message = "Allocating machine from cloud provider"
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, is_new_cloud_space)
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.ALLOCATING_MACHINE.value)
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.ALLOCATING_MACHINE.value
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.COMPLETED.value)
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, 85)
190
- current_message = StartupPhase.FINALIZING_SETUP.value
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.SETTING_UP_ENVIRONMENT.value
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.STUDIO_STARTING.value
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.ALLOCATING_MACHINE.value
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.ALLOCATING_MACHINE.value
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.ALLOCATING_MACHINE.value != self._last_message and (
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.ALLOCATING_MACHINE.value)
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 2025.9.30
3
+ Version: 2025.10.14
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License