lightning-sdk 2025.8.6rc2__py3-none-any.whl → 2025.11.5__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 (330) hide show
  1. lightning_sdk/__init__.py +13 -7
  2. lightning_sdk/__version__.py +3 -0
  3. lightning_sdk/agents.py +2 -1
  4. lightning_sdk/ai_hub.py +2 -1
  5. lightning_sdk/api/__init__.py +2 -0
  6. lightning_sdk/api/base_studio_api.py +13 -9
  7. lightning_sdk/api/cloud_account_api.py +31 -10
  8. lightning_sdk/api/deployment_api.py +27 -1
  9. lightning_sdk/api/job_api.py +16 -12
  10. lightning_sdk/api/license_api.py +26 -59
  11. lightning_sdk/api/llm_api.py +25 -2
  12. lightning_sdk/api/mmt_api.py +5 -2
  13. lightning_sdk/api/studio_api.py +252 -55
  14. lightning_sdk/api/teamspace_api.py +106 -30
  15. lightning_sdk/api/user_api.py +56 -2
  16. lightning_sdk/api/utils.py +108 -18
  17. lightning_sdk/base_studio.py +51 -27
  18. lightning_sdk/cli/__init__.py +1 -0
  19. lightning_sdk/cli/base_studio/__init__.py +10 -0
  20. lightning_sdk/cli/base_studio/list.py +43 -0
  21. lightning_sdk/cli/config/__init__.py +14 -0
  22. lightning_sdk/cli/config/get.py +57 -0
  23. lightning_sdk/cli/config/set.py +92 -0
  24. lightning_sdk/cli/config/show.py +9 -0
  25. lightning_sdk/cli/entrypoint.py +71 -71
  26. lightning_sdk/cli/groups.py +56 -0
  27. lightning_sdk/cli/job/__init__.py +7 -0
  28. lightning_sdk/cli/{clusters_menu.py → legacy/clusters_menu.py} +9 -6
  29. lightning_sdk/cli/{configure.py → legacy/configure.py} +2 -2
  30. lightning_sdk/cli/{connect.py → legacy/connect.py} +2 -2
  31. lightning_sdk/cli/{create.py → legacy/create.py} +12 -14
  32. lightning_sdk/cli/{delete.py → legacy/delete.py} +5 -5
  33. lightning_sdk/cli/legacy/deploy/__init__.py +0 -0
  34. lightning_sdk/cli/{deploy → legacy/deploy}/_auth.py +5 -6
  35. lightning_sdk/cli/{deploy → legacy/deploy}/devbox.py +8 -2
  36. lightning_sdk/cli/{deploy → legacy/deploy}/serve.py +19 -8
  37. lightning_sdk/cli/{download.py → legacy/download.py} +14 -15
  38. lightning_sdk/cli/legacy/entrypoint.py +110 -0
  39. lightning_sdk/cli/{generate.py → legacy/generate.py} +1 -1
  40. lightning_sdk/cli/{inspection.py → legacy/inspection.py} +1 -1
  41. lightning_sdk/cli/{job_and_mmt_action.py → legacy/job_and_mmt_action.py} +6 -6
  42. lightning_sdk/cli/{jobs_menu.py → legacy/jobs_menu.py} +1 -1
  43. lightning_sdk/cli/{list.py → legacy/list.py} +12 -13
  44. lightning_sdk/cli/{mmts_menu.py → legacy/mmts_menu.py} +1 -1
  45. lightning_sdk/cli/{open.py → legacy/open.py} +4 -4
  46. lightning_sdk/cli/{start.py → legacy/start.py} +1 -0
  47. lightning_sdk/cli/{stop.py → legacy/stop.py} +1 -1
  48. lightning_sdk/cli/{switch.py → legacy/switch.py} +1 -0
  49. lightning_sdk/cli/{teamspace_menu.py → legacy/teamspace_menu.py} +1 -1
  50. lightning_sdk/cli/{upload.py → legacy/upload.py} +7 -8
  51. lightning_sdk/cli/license/__init__.py +14 -0
  52. lightning_sdk/cli/license/get.py +15 -0
  53. lightning_sdk/cli/license/list.py +45 -0
  54. lightning_sdk/cli/license/set.py +13 -0
  55. lightning_sdk/cli/mmt/__init__.py +7 -0
  56. lightning_sdk/cli/studio/__init__.py +24 -0
  57. lightning_sdk/cli/studio/connect.py +139 -0
  58. lightning_sdk/cli/studio/create.py +96 -0
  59. lightning_sdk/cli/studio/delete.py +49 -0
  60. lightning_sdk/cli/studio/list.py +85 -0
  61. lightning_sdk/cli/studio/ssh.py +64 -0
  62. lightning_sdk/cli/studio/start.py +115 -0
  63. lightning_sdk/cli/studio/stop.py +45 -0
  64. lightning_sdk/cli/studio/switch.py +66 -0
  65. lightning_sdk/cli/utils/__init__.py +7 -0
  66. lightning_sdk/cli/utils/cloud_account_map.py +10 -0
  67. lightning_sdk/cli/utils/get_base_studio.py +24 -0
  68. lightning_sdk/cli/utils/handle_machine_and_gpus_args.py +69 -0
  69. lightning_sdk/cli/utils/logging.py +122 -0
  70. lightning_sdk/cli/utils/owner_selection.py +110 -0
  71. lightning_sdk/cli/utils/resolve.py +28 -0
  72. lightning_sdk/cli/utils/richt_print.py +35 -0
  73. lightning_sdk/cli/utils/save_to_config.py +27 -0
  74. lightning_sdk/cli/utils/ssh_connection.py +59 -0
  75. lightning_sdk/cli/utils/studio_selection.py +113 -0
  76. lightning_sdk/cli/utils/teamspace_selection.py +125 -0
  77. lightning_sdk/cli/vm/__init__.py +20 -0
  78. lightning_sdk/cli/vm/create.py +33 -0
  79. lightning_sdk/cli/vm/delete.py +25 -0
  80. lightning_sdk/cli/vm/list.py +30 -0
  81. lightning_sdk/cli/vm/ssh.py +31 -0
  82. lightning_sdk/cli/vm/start.py +60 -0
  83. lightning_sdk/cli/vm/stop.py +25 -0
  84. lightning_sdk/cli/vm/switch.py +38 -0
  85. lightning_sdk/constants.py +1 -0
  86. lightning_sdk/deployment/__init__.py +2 -0
  87. lightning_sdk/deployment/deployment.py +17 -2
  88. lightning_sdk/helpers.py +56 -37
  89. lightning_sdk/job/base.py +21 -6
  90. lightning_sdk/job/job.py +13 -0
  91. lightning_sdk/job/v1.py +11 -0
  92. lightning_sdk/job/v2.py +12 -0
  93. lightning_sdk/lightning_cloud/login.py +320 -10
  94. lightning_sdk/lightning_cloud/openapi/__init__.py +113 -3
  95. lightning_sdk/lightning_cloud/openapi/api/__init__.py +3 -0
  96. lightning_sdk/lightning_cloud/openapi/api/assistants_service_api.py +713 -75
  97. lightning_sdk/lightning_cloud/openapi/api/auth_service_api.py +376 -0
  98. lightning_sdk/lightning_cloud/openapi/api/billing_service_api.py +191 -1
  99. lightning_sdk/lightning_cloud/openapi/api/cloud_space_environment_template_service_api.py +5 -1
  100. lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +420 -0
  101. lightning_sdk/lightning_cloud/openapi/api/cloudy_service_api.py +0 -97
  102. lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +420 -0
  103. lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +101 -0
  104. lightning_sdk/lightning_cloud/openapi/api/incidents_service_api.py +1058 -0
  105. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +121 -0
  106. lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +1742 -94
  107. lightning_sdk/lightning_cloud/openapi/api/markets_service_api.py +145 -0
  108. lightning_sdk/lightning_cloud/openapi/api/models_store_api.py +4 -4
  109. lightning_sdk/lightning_cloud/openapi/api/product_license_service_api.py +108 -108
  110. lightning_sdk/lightning_cloud/openapi/api/projects_service_api.py +105 -0
  111. lightning_sdk/lightning_cloud/openapi/api/schedules_service_api.py +347 -0
  112. lightning_sdk/lightning_cloud/openapi/api/sdk_command_history_service_api.py +141 -0
  113. lightning_sdk/lightning_cloud/openapi/api/storage_service_api.py +761 -1
  114. lightning_sdk/lightning_cloud/openapi/configuration.py +3 -19
  115. lightning_sdk/lightning_cloud/openapi/models/__init__.py +110 -3
  116. lightning_sdk/lightning_cloud/openapi/models/assistant_id_conversations_body.py +15 -15
  117. lightning_sdk/lightning_cloud/openapi/models/cloudspace_id_visibility_body.py +27 -1
  118. lightning_sdk/lightning_cloud/openapi/models/cluster_id_kubernetestemplates_body.py +201 -0
  119. lightning_sdk/lightning_cloud/openapi/models/cluster_id_metrics_body.py +131 -1
  120. lightning_sdk/lightning_cloud/openapi/models/create.py +27 -1
  121. lightning_sdk/lightning_cloud/openapi/models/create_machine_request_represents_the_request_to_create_a_machine.py +461 -0
  122. lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +27 -1
  123. lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +105 -1
  124. lightning_sdk/lightning_cloud/openapi/models/externalv1_user_status.py +27 -1
  125. lightning_sdk/lightning_cloud/openapi/models/id_codeconfig_body.py +3 -81
  126. lightning_sdk/lightning_cloud/openapi/models/id_fork_body1.py +27 -1
  127. lightning_sdk/lightning_cloud/openapi/models/id_render_body.py +123 -0
  128. lightning_sdk/lightning_cloud/openapi/models/id_sleepconfig_body.py +175 -0
  129. lightning_sdk/lightning_cloud/openapi/models/id_transfer_body.py +53 -1
  130. lightning_sdk/lightning_cloud/openapi/models/incident_id_messages_body.py +123 -0
  131. lightning_sdk/lightning_cloud/openapi/models/incidents_id_body.py +279 -0
  132. lightning_sdk/lightning_cloud/openapi/models/job_id_reportroutingtelemetry_body.py +123 -0
  133. lightning_sdk/lightning_cloud/openapi/models/kubernetestemplates_id_body.py +201 -0
  134. lightning_sdk/lightning_cloud/openapi/models/license_key_validate_body.py +123 -0
  135. lightning_sdk/lightning_cloud/openapi/models/message_id_actions_body.py +201 -0
  136. lightning_sdk/lightning_cloud/openapi/models/messages_message_id_body.py +123 -0
  137. lightning_sdk/lightning_cloud/openapi/models/metricsstream_create_body.py +27 -1
  138. lightning_sdk/lightning_cloud/openapi/models/models_model_id_body.py +109 -31
  139. lightning_sdk/lightning_cloud/openapi/models/models_model_id_body1.py +149 -0
  140. lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +53 -1
  141. lightning_sdk/lightning_cloud/openapi/models/project_id_storage_body.py +27 -1
  142. lightning_sdk/lightning_cloud/openapi/models/project_id_storagetransfers_body.py +175 -0
  143. lightning_sdk/lightning_cloud/openapi/models/project_tab_management_messages.py +123 -0
  144. lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +79 -1
  145. lightning_sdk/lightning_cloud/openapi/models/storage_complete_body.py +41 -15
  146. lightning_sdk/lightning_cloud/openapi/models/storagetransfers_validate_body.py +149 -0
  147. lightning_sdk/lightning_cloud/openapi/models/update1.py +27 -1
  148. lightning_sdk/lightning_cloud/openapi/models/uploads_upload_id_body1.py +27 -1
  149. lightning_sdk/lightning_cloud/openapi/models/user_id_affiliatelinks_body.py +107 -3
  150. lightning_sdk/lightning_cloud/openapi/models/v1_abort_storage_transfer_response.py +97 -0
  151. lightning_sdk/lightning_cloud/openapi/models/v1_aggregated_pod_metrics.py +799 -0
  152. lightning_sdk/lightning_cloud/openapi/models/v1_ai_pod_v1.py +53 -1
  153. lightning_sdk/lightning_cloud/openapi/models/v1_assistant_session_daily_aggregated.py +27 -1
  154. lightning_sdk/lightning_cloud/openapi/models/v1_billing_tier.py +0 -1
  155. lightning_sdk/lightning_cloud/openapi/models/v1_cancel_running_cloud_space_instance_transfer_response.py +97 -0
  156. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_provider.py +2 -0
  157. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +27 -1
  158. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_specialized_view.py +1 -0
  159. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_transfer_metadata.py +147 -17
  160. lightning_sdk/lightning_cloud/openapi/models/v1_cloudflare_v1.py +3 -29
  161. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_accelerator.py +53 -1
  162. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_capacity_reservation.py +27 -1
  163. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_metrics.py +1527 -0
  164. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_security_options.py +27 -1
  165. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +53 -1
  166. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_type.py +1 -0
  167. lightning_sdk/lightning_cloud/openapi/models/v1_container_metrics.py +21 -21
  168. lightning_sdk/lightning_cloud/openapi/models/v1_create_incident_request.py +305 -0
  169. lightning_sdk/lightning_cloud/openapi/models/v1_create_license_request.py +175 -0
  170. lightning_sdk/lightning_cloud/openapi/models/v1_create_machine_response.py +123 -0
  171. lightning_sdk/lightning_cloud/openapi/models/v1_create_model_metrics_response.py +97 -0
  172. lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +79 -1
  173. lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_request.py +253 -0
  174. lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_response.py +97 -0
  175. lightning_sdk/lightning_cloud/openapi/models/v1_daily_model_metrics.py +149 -0
  176. lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +53 -1
  177. lightning_sdk/lightning_cloud/openapi/models/v1_delete_incident_message_response.py +97 -0
  178. lightning_sdk/lightning_cloud/openapi/models/v1_delete_incident_response.py +97 -0
  179. lightning_sdk/lightning_cloud/openapi/models/v1_delete_kubernetes_template_response.py +97 -0
  180. lightning_sdk/lightning_cloud/openapi/models/v1_delete_license_response.py +97 -0
  181. lightning_sdk/lightning_cloud/openapi/models/v1_delete_machine_response.py +97 -0
  182. lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +27 -1
  183. lightning_sdk/lightning_cloud/openapi/models/v1_external_cluster_spec.py +53 -1
  184. lightning_sdk/lightning_cloud/openapi/models/v1_external_search_user.py +27 -1
  185. lightning_sdk/lightning_cloud/openapi/models/v1_filestore_data_connection.py +27 -1
  186. lightning_sdk/lightning_cloud/openapi/models/v1_filesystem_metric.py +201 -0
  187. lightning_sdk/lightning_cloud/openapi/models/v1_firewall_rule.py +175 -0
  188. lightning_sdk/lightning_cloud/openapi/models/v1_get_cloud_space_required_balance_status_response.py +149 -0
  189. lightning_sdk/lightning_cloud/openapi/models/v1_get_cloud_space_transfer_estimate_response.py +149 -0
  190. lightning_sdk/lightning_cloud/openapi/models/v1_get_latest_model_metrics_response.py +123 -0
  191. lightning_sdk/lightning_cloud/openapi/models/v1_get_machine_response.py +123 -0
  192. lightning_sdk/lightning_cloud/openapi/models/v1_get_market_pricing_response.py +201 -0
  193. lightning_sdk/lightning_cloud/openapi/models/v1_get_model_metrics_response.py +123 -0
  194. lightning_sdk/lightning_cloud/openapi/models/v1_get_temp_bucket_credentials_response.py +201 -0
  195. lightning_sdk/lightning_cloud/openapi/models/v1_get_user_response.py +41 -15
  196. lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +27 -1
  197. lightning_sdk/lightning_cloud/openapi/models/v1_group_node_metrics.py +1215 -0
  198. lightning_sdk/lightning_cloud/openapi/models/v1_group_pod_metrics.py +1241 -0
  199. lightning_sdk/lightning_cloud/openapi/models/v1_guest_login_request.py +177 -0
  200. lightning_sdk/lightning_cloud/openapi/models/v1_guest_login_response.py +149 -0
  201. lightning_sdk/lightning_cloud/openapi/models/v1_guest_user.py +201 -0
  202. lightning_sdk/lightning_cloud/openapi/models/v1_incident.py +565 -0
  203. lightning_sdk/lightning_cloud/openapi/models/v1_incident_detail.py +149 -0
  204. lightning_sdk/lightning_cloud/openapi/models/v1_incident_event.py +591 -0
  205. lightning_sdk/lightning_cloud/openapi/models/v1_incident_message.py +253 -0
  206. lightning_sdk/lightning_cloud/openapi/models/v1_incident_severity.py +105 -0
  207. lightning_sdk/lightning_cloud/openapi/models/v1_incident_type.py +108 -0
  208. lightning_sdk/lightning_cloud/openapi/models/v1_job.py +53 -1
  209. lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +27 -1
  210. lightning_sdk/lightning_cloud/openapi/models/v1_k8s_incident_indexes.py +149 -0
  211. lightning_sdk/lightning_cloud/openapi/models/v1_kai_scheduler_queue_metrics.py +627 -0
  212. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_aws_config.py +279 -0
  213. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_settings_v1.py +253 -0
  214. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_v1.py +107 -3
  215. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_template.py +357 -0
  216. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_template_property.py +227 -0
  217. lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py +29 -3
  218. lightning_sdk/lightning_cloud/openapi/models/v1_license.py +227 -0
  219. lightning_sdk/lightning_cloud/openapi/models/v1_lightning_elastic_cluster_v1.py +97 -0
  220. lightning_sdk/lightning_cloud/openapi/models/v1_list_aggregated_pod_metrics_response.py +123 -0
  221. lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_metric_timestamps_response.py +123 -0
  222. lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_metrics_response.py +123 -0
  223. lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_namespace_metrics_response.py +123 -0
  224. lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_namespace_user_metrics_response.py +123 -0
  225. lightning_sdk/lightning_cloud/openapi/models/v1_list_conversation_message_actions_response.py +123 -0
  226. lightning_sdk/lightning_cloud/openapi/models/v1_list_filesystem_metrics_response.py +123 -0
  227. lightning_sdk/lightning_cloud/openapi/models/v1_list_group_pod_metrics_response.py +123 -0
  228. lightning_sdk/lightning_cloud/openapi/models/v1_list_incident_events_response.py +123 -0
  229. lightning_sdk/lightning_cloud/openapi/models/v1_list_incident_messages_response.py +149 -0
  230. lightning_sdk/lightning_cloud/openapi/models/v1_list_incidents_response.py +149 -0
  231. lightning_sdk/lightning_cloud/openapi/models/v1_list_kai_scheduler_queues_metrics_response.py +123 -0
  232. lightning_sdk/lightning_cloud/openapi/models/v1_list_kubernetes_templates_response.py +123 -0
  233. lightning_sdk/lightning_cloud/openapi/models/{v1_list_product_licenses_response.py → v1_list_license_response.py} +16 -16
  234. lightning_sdk/lightning_cloud/openapi/models/v1_list_machines_response.py +149 -0
  235. lightning_sdk/lightning_cloud/openapi/models/v1_list_platform_notifications_response.py +123 -0
  236. lightning_sdk/lightning_cloud/openapi/models/v1_list_schedule_runs_response.py +123 -0
  237. lightning_sdk/lightning_cloud/openapi/models/v1_list_storage_transfers_response.py +123 -0
  238. lightning_sdk/lightning_cloud/openapi/models/v1_lustre_data_connection.py +149 -0
  239. lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +617 -0
  240. lightning_sdk/lightning_cloud/openapi/models/v1_machine_direct_v1.py +123 -0
  241. lightning_sdk/lightning_cloud/openapi/models/v1_magic_link_login_request.py +1 -27
  242. lightning_sdk/lightning_cloud/openapi/models/v1_magic_link_login_response.py +27 -1
  243. lightning_sdk/lightning_cloud/openapi/models/v1_managed_model.py +29 -3
  244. lightning_sdk/lightning_cloud/openapi/models/v1_market_price.py +149 -0
  245. lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +53 -1
  246. lightning_sdk/lightning_cloud/openapi/models/v1_message_action.py +279 -0
  247. lightning_sdk/lightning_cloud/openapi/models/v1_metrics_stream.py +27 -1
  248. lightning_sdk/lightning_cloud/openapi/models/v1_model_metrics.py +175 -0
  249. lightning_sdk/lightning_cloud/openapi/models/v1_namespace_metrics.py +591 -0
  250. lightning_sdk/lightning_cloud/openapi/models/v1_namespace_user_metrics.py +435 -0
  251. lightning_sdk/lightning_cloud/openapi/models/v1_nebius_direct_v1.py +29 -3
  252. lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +361 -23
  253. lightning_sdk/lightning_cloud/openapi/models/v1_notification_type.py +1 -0
  254. lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +53 -1
  255. lightning_sdk/lightning_cloud/openapi/models/v1_pause_storage_transfer_response.py +97 -0
  256. lightning_sdk/lightning_cloud/openapi/models/v1_platform_notification.py +279 -0
  257. lightning_sdk/lightning_cloud/openapi/models/v1_pod_metrics.py +335 -23
  258. lightning_sdk/lightning_cloud/openapi/models/v1_project.py +27 -1
  259. lightning_sdk/lightning_cloud/openapi/models/v1_project_cluster_binding.py +27 -1
  260. lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +53 -1
  261. lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +53 -1
  262. lightning_sdk/lightning_cloud/openapi/models/v1_project_tab.py +149 -0
  263. lightning_sdk/lightning_cloud/openapi/models/{v1_product_license_check_response.py → v1_purchase_annual_upsell_request.py} +23 -23
  264. lightning_sdk/lightning_cloud/openapi/models/v1_purchase_annual_upsell_response.py +123 -0
  265. lightning_sdk/lightning_cloud/openapi/models/v1_quote_annual_upsell_response.py +227 -0
  266. lightning_sdk/lightning_cloud/openapi/models/v1_render_kubernetes_template_response.py +123 -0
  267. lightning_sdk/lightning_cloud/openapi/models/v1_report_deployment_routing_telemetry_response.py +97 -0
  268. lightning_sdk/lightning_cloud/openapi/models/v1_required_balance_reason.py +107 -0
  269. lightning_sdk/lightning_cloud/openapi/models/v1_reset_api_key_request.py +97 -0
  270. lightning_sdk/lightning_cloud/openapi/models/v1_reset_api_key_response.py +123 -0
  271. lightning_sdk/lightning_cloud/openapi/models/v1_resource_visibility.py +1 -27
  272. lightning_sdk/lightning_cloud/openapi/models/v1_resume_storage_transfer_response.py +97 -0
  273. lightning_sdk/lightning_cloud/openapi/models/v1_routing_telemetry.py +79 -1
  274. lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
  275. lightning_sdk/lightning_cloud/openapi/models/v1_schedule_run.py +357 -0
  276. lightning_sdk/lightning_cloud/openapi/models/v1_sdk_command_history_severity.py +104 -0
  277. lightning_sdk/lightning_cloud/openapi/models/v1_sdk_command_history_type.py +104 -0
  278. lightning_sdk/lightning_cloud/openapi/models/v1_secret_type.py +1 -0
  279. lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_type.py +1 -0
  280. lightning_sdk/lightning_cloud/openapi/models/v1_slack_notifier.py +201 -0
  281. lightning_sdk/lightning_cloud/openapi/models/v1_slack_notifier_type.py +105 -0
  282. lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset.py +133 -3
  283. lightning_sdk/lightning_cloud/openapi/models/v1_storage_transfer.py +435 -0
  284. lightning_sdk/lightning_cloud/openapi/models/v1_storage_transfer_status.py +108 -0
  285. lightning_sdk/lightning_cloud/openapi/models/v1_token_login_request.py +123 -0
  286. lightning_sdk/lightning_cloud/openapi/models/v1_token_login_response.py +123 -0
  287. lightning_sdk/lightning_cloud/openapi/models/v1_token_owner_type.py +104 -0
  288. lightning_sdk/lightning_cloud/openapi/models/v1_update_cloud_space_instance_config_request.py +3 -81
  289. lightning_sdk/lightning_cloud/openapi/models/v1_update_project_tab_order_response.py +123 -0
  290. lightning_sdk/lightning_cloud/openapi/models/v1_update_user_request.py +41 -15
  291. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +444 -600
  292. lightning_sdk/lightning_cloud/openapi/models/v1_validate_license_response.py +123 -0
  293. lightning_sdk/lightning_cloud/openapi/models/v1_validate_storage_transfer_response.py +123 -0
  294. lightning_sdk/lightning_cloud/openapi/models/v1_voltage_park_direct_v1.py +29 -3
  295. lightning_sdk/lightning_cloud/rest_client.py +48 -45
  296. lightning_sdk/lightning_cloud/utils/data_connection.py +51 -1
  297. lightning_sdk/llm/llm.py +175 -56
  298. lightning_sdk/llm/public_assistants.py +44 -7
  299. lightning_sdk/machine.py +21 -2
  300. lightning_sdk/mmt/base.py +7 -0
  301. lightning_sdk/mmt/mmt.py +11 -3
  302. lightning_sdk/mmt/v1.py +3 -1
  303. lightning_sdk/mmt/v2.py +4 -0
  304. lightning_sdk/owner.py +2 -1
  305. lightning_sdk/pipeline/steps.py +6 -0
  306. lightning_sdk/plugin.py +6 -1
  307. lightning_sdk/studio.py +294 -53
  308. lightning_sdk/teamspace.py +167 -7
  309. lightning_sdk/user.py +19 -1
  310. lightning_sdk/utils/config.py +179 -0
  311. lightning_sdk/utils/license.py +13 -0
  312. lightning_sdk/utils/logging.py +79 -0
  313. lightning_sdk/utils/names.py +1179 -0
  314. lightning_sdk/utils/progress.py +283 -0
  315. lightning_sdk/utils/resolve.py +82 -7
  316. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/METADATA +2 -1
  317. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/RECORD +328 -169
  318. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/entry_points.txt +1 -0
  319. lightning_sdk/lightning_cloud/openapi/models/v1_product_license.py +0 -435
  320. lightning_sdk/services/license.py +0 -363
  321. /lightning_sdk/cli/{deploy → legacy}/__init__.py +0 -0
  322. /lightning_sdk/cli/{ai_hub.py → legacy/ai_hub.py} +0 -0
  323. /lightning_sdk/cli/{docker_cli.py → legacy/docker_cli.py} +0 -0
  324. /lightning_sdk/cli/{exceptions.py → legacy/exceptions.py} +0 -0
  325. /lightning_sdk/cli/{run.py → legacy/run.py} +0 -0
  326. /lightning_sdk/cli/{studios_menu.py → legacy/studios_menu.py} +0 -0
  327. /lightning_sdk/cli/{coloring.py → utils/coloring.py} +0 -0
  328. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/LICENSE +0 -0
  329. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/WHEEL +0 -0
  330. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,96 @@
1
+ """Studio start command."""
2
+
3
+ from typing import Optional
4
+
5
+ import click
6
+
7
+ from lightning_sdk.cli.utils.get_base_studio import get_base_studio_id
8
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
9
+ from lightning_sdk.cli.utils.save_to_config import save_teamspace_to_config
10
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
11
+ from lightning_sdk.lightning_cloud.openapi.rest import ApiException
12
+ from lightning_sdk.machine import CloudProvider
13
+ from lightning_sdk.studio import VM, Studio
14
+
15
+
16
+ @click.command("create")
17
+ @click.option("--name", help="The name of the studio to create. If not provided, a random name will be generated.")
18
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
19
+ @click.option(
20
+ "--cloud-provider",
21
+ help="The cloud provider to start the studio on. Defaults to teamspace default.",
22
+ type=click.Choice(m.name for m in list(CloudProvider)),
23
+ )
24
+ @click.option(
25
+ "--cloud-account",
26
+ help="The cloud account to create the studio on. Defaults to teamspace default.",
27
+ type=click.STRING,
28
+ )
29
+ @click.option(
30
+ "--studio-type",
31
+ help="The base studio template name to use for creating the studio. "
32
+ "Must be lowercase and hyphenated (use '-' instead of spaces). "
33
+ "Run 'lightning base-studio list' to see all available templates. "
34
+ "Defaults to the first available template.",
35
+ type=click.STRING,
36
+ )
37
+ def create_studio(
38
+ name: Optional[str] = None,
39
+ teamspace: Optional[str] = None,
40
+ cloud_provider: Optional[str] = None,
41
+ cloud_account: Optional[str] = None,
42
+ studio_type: Optional[str] = None,
43
+ ) -> None:
44
+ """Create a new Studio.
45
+
46
+ Example:
47
+ lightning studio create
48
+ """
49
+ create_impl(
50
+ name=name,
51
+ teamspace=teamspace,
52
+ cloud_provider=cloud_provider,
53
+ cloud_account=cloud_account,
54
+ vm=False,
55
+ studio_type=studio_type,
56
+ )
57
+
58
+
59
+ def create_impl(
60
+ name: Optional[str],
61
+ teamspace: Optional[str],
62
+ cloud_provider: Optional[str],
63
+ cloud_account: Optional[str],
64
+ vm: bool,
65
+ studio_type: Optional[str],
66
+ ) -> None:
67
+ menu = TeamspacesMenu()
68
+
69
+ resolved_teamspace = menu(teamspace)
70
+ save_teamspace_to_config(resolved_teamspace, overwrite=False)
71
+
72
+ if cloud_provider is not None:
73
+ cloud_provider = CloudProvider(cloud_provider)
74
+
75
+ create_cls = VM if vm else Studio
76
+ cls_name = create_cls.__qualname__
77
+
78
+ # check for available base studios
79
+ template_id = get_base_studio_id(studio_type)
80
+
81
+ try:
82
+ create_cls = VM if vm else Studio
83
+ studio = create_cls(
84
+ name=name,
85
+ teamspace=resolved_teamspace,
86
+ create_ok=True,
87
+ cloud_provider=cloud_provider,
88
+ cloud_account=cloud_account,
89
+ studio_type=template_id,
90
+ )
91
+ except (RuntimeError, ValueError, ApiException):
92
+ if name:
93
+ raise ValueError(f"Could not create {cls_name}: '{name}'. Does the {cls_name} exist?") from None
94
+ raise ValueError(f"Could not create {cls_name}: '{name}'. Please provide a {cls_name} name") from None
95
+
96
+ click.echo(f"{cls_name} {studio_name_link(studio)} created successfully")
@@ -0,0 +1,49 @@
1
+ """Studio delete command."""
2
+
3
+ from typing import Optional
4
+
5
+ import click
6
+
7
+ from lightning_sdk.cli.utils.studio_selection import StudiosMenu
8
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
9
+
10
+
11
+ @click.command("delete")
12
+ @click.option(
13
+ "--name",
14
+ help=(
15
+ "The name of the studio to delete. "
16
+ "If not provided, will try to infer from environment, "
17
+ "use the default value from the config or prompt for interactive selection."
18
+ ),
19
+ )
20
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
21
+ def delete_studio(name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
22
+ """Delete a Studio.
23
+
24
+ Example:
25
+ lightning studio delete --name my-studio
26
+
27
+ """
28
+ return delete_impl(name=name, teamspace=teamspace, vm=False)
29
+
30
+
31
+ def delete_impl(name: Optional[str], teamspace: Optional[str], vm: bool) -> None:
32
+ menu = TeamspacesMenu()
33
+ resolved_teamspace = menu(teamspace=teamspace)
34
+
35
+ menu = StudiosMenu(resolved_teamspace, vm=vm)
36
+ studio = menu(studio=name)
37
+
38
+ studio_name = f"{studio.teamspace.owner.name}/{studio.teamspace.name}/{studio.name}"
39
+ confirmed = click.confirm(
40
+ f"Are you sure you want to delete {studio._cls_name} '{studio_name}'?",
41
+ abort=True,
42
+ )
43
+ if not confirmed:
44
+ click.echo(f"{studio._cls_name} deletion cancelled")
45
+ return
46
+
47
+ studio.delete()
48
+
49
+ click.echo(f"{studio._cls_name} '{studio.name}' deleted successfully")
@@ -0,0 +1,85 @@
1
+ """Studio list command."""
2
+
3
+ from typing import Callable, Optional
4
+
5
+ import click
6
+ from rich.table import Table
7
+
8
+ from lightning_sdk.cli.utils.cloud_account_map import cloud_account_to_display_name
9
+ from lightning_sdk.cli.utils.richt_print import rich_to_str, studio_name_link
10
+ from lightning_sdk.cli.utils.save_to_config import save_teamspace_to_config
11
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
12
+ from lightning_sdk.studio import Studio
13
+ from lightning_sdk.utils.resolve import _get_authed_user, prevent_refetch_studio
14
+
15
+
16
+ @click.command("list")
17
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
18
+ @click.option(
19
+ "--all",
20
+ is_flag=True,
21
+ flag_value=True,
22
+ default=False,
23
+ help="List all studios, not just the ones belonging to the authed user",
24
+ )
25
+ @click.option(
26
+ "--sort-by",
27
+ default=None,
28
+ type=click.Choice(["name", "teamspace", "status", "machine", "cloud-account"], case_sensitive=False),
29
+ help="the attribute to sort the studios by.",
30
+ )
31
+ def list_studios(teamspace: Optional[str] = None, all: bool = False, sort_by: Optional[str] = None) -> None: # noqa: A002
32
+ """List Studios in a teamspace.
33
+
34
+ Example:
35
+ lightning studio list --teamspace owner/teamspace
36
+
37
+ """
38
+ return list_impl(teamspace=teamspace, all=all, sort_by=sort_by, vm=False)
39
+
40
+
41
+ def list_impl(teamspace: Optional[str], all: bool, sort_by: Optional[str], vm: bool) -> None: # noqa: A002
42
+ menu = TeamspacesMenu()
43
+ teamspace_resolved = menu(teamspace=teamspace)
44
+ save_teamspace_to_config(teamspace_resolved, overwrite=False)
45
+
46
+ user = _get_authed_user()
47
+
48
+ studios = teamspace_resolved.vms if vm else teamspace_resolved.studios
49
+
50
+ table = Table(
51
+ pad_edge=True,
52
+ )
53
+ table.add_column("Name")
54
+ table.add_column("Teamspace")
55
+ table.add_column("Status")
56
+ table.add_column("Machine")
57
+ table.add_column("Cloud account")
58
+
59
+ for studio in sorted(
60
+ filter(lambda s: all or s._studio.user_id == user.id, studios), key=_sort_studios_key(sort_by)
61
+ ):
62
+ with prevent_refetch_studio(studio):
63
+ table.add_row(
64
+ # cannot convert to ascii here, as the final rich table has to be converted to ascii
65
+ # otherwise the lack of support for linking in some terminals causes formatting issues.
66
+ studio_name_link(studio, to_ascii=False),
67
+ f"{studio.teamspace.owner.name}/{studio.teamspace.name}",
68
+ str(studio.status),
69
+ str(studio.machine) if studio.machine is not None else None, # when None the cell is empty
70
+ str(cloud_account_to_display_name(studio.cloud_account, studio.teamspace.id)),
71
+ )
72
+
73
+ click.echo(rich_to_str(table), color=True)
74
+
75
+
76
+ def _sort_studios_key(sort_by: str) -> Callable[[Studio], str]:
77
+ """Return a key function to sort studios by a given attribute."""
78
+ sort_key_map = {
79
+ "name": lambda s: str(s.name or ""),
80
+ "teamspace": lambda s: str(s.teamspace.name or ""),
81
+ "status": lambda s: str(s.status or ""),
82
+ "machine": lambda s: str(s.machine or ""),
83
+ "cloud-account": lambda s: str(cloud_account_to_display_name(s.cloud_account or "", s.teamspace.id)),
84
+ }
85
+ return sort_key_map.get(sort_by, lambda s: s.name)
@@ -0,0 +1,64 @@
1
+ """Studio SSH command."""
2
+
3
+ import subprocess
4
+ from typing import List, Optional
5
+
6
+ import click
7
+
8
+ from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
9
+ from lightning_sdk.cli.utils.ssh_connection import configure_ssh_internal
10
+ from lightning_sdk.cli.utils.studio_selection import StudiosMenu
11
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
12
+
13
+
14
+ @click.command("ssh")
15
+ @click.option(
16
+ "--name",
17
+ help=(
18
+ "The name of the studio to ssh into. "
19
+ "If not provided, will try to infer from environment, "
20
+ "use the default value from the config or prompt for interactive selection."
21
+ ),
22
+ )
23
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)", type=click.STRING)
24
+ @click.option(
25
+ "--option",
26
+ "-o",
27
+ help="Additional options to pass to the SSH command. Can be specified multiple times.",
28
+ multiple=True,
29
+ type=click.STRING,
30
+ )
31
+ def ssh_studio(name: Optional[str] = None, teamspace: Optional[str] = None, option: Optional[List[str]] = None) -> None:
32
+ """SSH into a Studio.
33
+
34
+ Example:
35
+ lightning studio ssh --name my-studio
36
+ """
37
+ return ssh_impl(name=name, teamspace=teamspace, option=option, vm=False)
38
+
39
+
40
+ def ssh_impl(name: Optional[str], teamspace: Optional[str], option: Optional[List[str]], vm: bool) -> None:
41
+ ssh_private_key_path = configure_ssh_internal()
42
+
43
+ menu = TeamspacesMenu()
44
+ resolved_teamspace = menu(teamspace=teamspace)
45
+
46
+ menu = StudiosMenu(resolved_teamspace, vm=vm)
47
+ studio = menu(
48
+ studio=name,
49
+ )
50
+ save_studio_to_config(studio)
51
+
52
+ ssh_options = " -o " + " -o ".join(option) if option else ""
53
+ ssh_command = f"ssh -i {ssh_private_key_path}{ssh_options} s_{studio._studio.id}@ssh.lightning.ai"
54
+
55
+ try:
56
+ subprocess.run(ssh_command.split())
57
+ except Exception:
58
+ # redownload the keys to be sure they are up to date
59
+ ssh_private_key_path = configure_ssh_internal(force_download=True)
60
+ try:
61
+ subprocess.run(ssh_command.split())
62
+ except Exception:
63
+ # TODO: make this a generic CLI error
64
+ raise RuntimeError("Failed to establish SSH connection") from None
@@ -0,0 +1,115 @@
1
+ """Studio start command."""
2
+
3
+ from typing import Optional
4
+
5
+ import click
6
+
7
+ from lightning_sdk.cli.utils.handle_machine_and_gpus_args import handle_machine_and_gpus_args
8
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
9
+ from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
10
+ from lightning_sdk.cli.utils.studio_selection import StudiosMenu
11
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
12
+ from lightning_sdk.machine import CloudProvider, Machine
13
+ from lightning_sdk.studio import VM, Studio
14
+
15
+
16
+ @click.command("start")
17
+ @click.option(
18
+ "--name",
19
+ help=(
20
+ "The name of the studio to start. "
21
+ "If not provided, will try to infer from environment, "
22
+ "use the default value from the config or prompt for interactive selection."
23
+ ),
24
+ )
25
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
26
+ @click.option("--create", is_flag=True, help="Create the studio if it doesn't exist")
27
+ @click.option(
28
+ "--machine",
29
+ help="The machine type to start the studio on. Defaults to CPU-4",
30
+ type=click.Choice(m.name for m in Machine.__dict__.values() if isinstance(m, Machine) and m._include_in_cli),
31
+ )
32
+ @click.option("--interruptible", is_flag=True, help="Start the studio on an interruptible instance.")
33
+ @click.option(
34
+ "--cloud-provider",
35
+ help=(
36
+ "The cloud provider to start the studio on. Defaults to teamspace default. Only used if --create is specified."
37
+ ),
38
+ type=click.Choice(m.name for m in list(CloudProvider)),
39
+ )
40
+ @click.option(
41
+ "--cloud-account",
42
+ help="The cloud account to start the studio on. Defaults to teamspace default. Only used if --create is specified.",
43
+ type=click.STRING,
44
+ )
45
+ @click.option(
46
+ "--gpus",
47
+ help="The number and type of GPUs to start the studio on (format: TYPE:COUNT, e.g. L4:4)",
48
+ type=click.STRING,
49
+ )
50
+ def start_studio(
51
+ name: Optional[str] = None,
52
+ teamspace: Optional[str] = None,
53
+ create: bool = False,
54
+ machine: str = "CPU",
55
+ gpus: Optional[str] = None,
56
+ interruptible: bool = False,
57
+ cloud_provider: Optional[str] = None,
58
+ cloud_account: Optional[str] = None,
59
+ ) -> None:
60
+ """Start a Studio.
61
+
62
+ Example:
63
+ lightning studio start --name my-studio
64
+
65
+ """
66
+ return start_impl(
67
+ name=name,
68
+ teamspace=teamspace,
69
+ create=create,
70
+ machine=machine,
71
+ gpus=gpus,
72
+ interruptible=interruptible,
73
+ cloud_provider=cloud_provider,
74
+ cloud_account=cloud_account,
75
+ vm=False,
76
+ )
77
+
78
+
79
+ def start_impl(
80
+ name: Optional[str],
81
+ teamspace: Optional[str],
82
+ create: bool,
83
+ machine: str,
84
+ gpus: Optional[str],
85
+ interruptible: bool,
86
+ cloud_provider: Optional[str],
87
+ cloud_account: Optional[str],
88
+ vm: bool,
89
+ ) -> None:
90
+ menu = TeamspacesMenu()
91
+ resolved_teamspace = menu(teamspace=teamspace)
92
+
93
+ if cloud_provider is not None:
94
+ cloud_provider = CloudProvider(cloud_provider)
95
+
96
+ if not create:
97
+ menu = StudiosMenu(resolved_teamspace, vm=vm)
98
+ studio = menu(studio=name)
99
+ else:
100
+ create_cls = VM if vm else Studio
101
+ studio = create_cls(
102
+ name=name,
103
+ teamspace=resolved_teamspace,
104
+ create_ok=create,
105
+ cloud_provider=cloud_provider,
106
+ cloud_account=cloud_account,
107
+ )
108
+
109
+ machine = handle_machine_and_gpus_args(machine, gpus)
110
+
111
+ save_studio_to_config(studio)
112
+
113
+ Studio.show_progress = True
114
+ studio.start(machine, interruptible=interruptible)
115
+ click.echo(f"Studio {studio_name_link(studio)} started successfully")
@@ -0,0 +1,45 @@
1
+ """Studio stop command."""
2
+
3
+ from typing import Optional
4
+
5
+ import click
6
+
7
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
8
+ from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
9
+ from lightning_sdk.cli.utils.studio_selection import StudiosMenu
10
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
11
+
12
+
13
+ @click.command("stop")
14
+ @click.option(
15
+ "--name",
16
+ help=(
17
+ "The name of the studio to stop. "
18
+ "If not provided, will try to infer from environment, "
19
+ "use the default value from the config or prompt for interactive selection."
20
+ ),
21
+ )
22
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
23
+ def stop_studio(name: Optional[str] = None, teamspace: Optional[str] = None) -> None:
24
+ """Stop a Studio.
25
+
26
+ Example:
27
+ lightning studio stop --name my-studio
28
+
29
+ """
30
+ return stop_impl(name=name, teamspace=teamspace, vm=False)
31
+
32
+
33
+ def stop_impl(name: Optional[str], teamspace: Optional[str], vm: bool) -> None:
34
+ # missing studio_name and teamspace are handled by the studio class
35
+ menu = TeamspacesMenu()
36
+ resolved_teamspace = menu(teamspace=teamspace)
37
+
38
+ menu = StudiosMenu(resolved_teamspace, vm=vm)
39
+ studio = menu(studio=name)
40
+
41
+ studio.stop()
42
+
43
+ save_studio_to_config(studio)
44
+
45
+ click.echo(f"{studio._cls_name} {studio_name_link(studio)} stopped successfully")
@@ -0,0 +1,66 @@
1
+ """Studio switch command."""
2
+
3
+ from typing import Optional
4
+
5
+ import click
6
+
7
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
8
+ from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
9
+ from lightning_sdk.cli.utils.studio_selection import StudiosMenu
10
+ from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
11
+ from lightning_sdk.machine import Machine
12
+
13
+
14
+ @click.command("switch")
15
+ @click.option(
16
+ "--name",
17
+ help=(
18
+ "The name of the studio to switch to a different machine. "
19
+ "If not provided, will try to infer from environment, "
20
+ "use the default value from the config or prompt for interactive selection."
21
+ ),
22
+ )
23
+ @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
24
+ @click.option(
25
+ "--machine",
26
+ help="The machine type to switch the studio to.",
27
+ type=click.Choice(m.name for m in Machine.__dict__.values() if isinstance(m, Machine)),
28
+ )
29
+ @click.option("--interruptible", is_flag=True, help="Switch the studio to an interruptible instance.")
30
+ def switch_studio(
31
+ name: Optional[str] = None,
32
+ teamspace: Optional[str] = None,
33
+ machine: Optional[str] = None,
34
+ interruptible: bool = False,
35
+ ) -> None:
36
+ """Switch a Studio to a different machine type."""
37
+ return switch_impl(
38
+ name=name,
39
+ teamspace=teamspace,
40
+ machine=machine,
41
+ interruptible=interruptible,
42
+ vm=False,
43
+ )
44
+
45
+
46
+ def switch_impl(
47
+ name: Optional[str],
48
+ teamspace: Optional[str],
49
+ machine: Optional[str],
50
+ interruptible: bool,
51
+ vm: bool,
52
+ ) -> None:
53
+ menu = TeamspacesMenu()
54
+ resolved_teamspace = menu(teamspace=teamspace)
55
+
56
+ menu = StudiosMenu(resolved_teamspace, vm=vm)
57
+ studio = menu(studio=name)
58
+
59
+ resolved_machine = Machine.from_str(machine)
60
+
61
+ studio.__class__.show_progress = True
62
+ studio.switch_machine(resolved_machine, interruptible=interruptible)
63
+
64
+ save_studio_to_config(studio)
65
+
66
+ click.echo(f"{studio._cls_name} {studio_name_link(studio)} switched to machine '{resolved_machine}' successfully")
@@ -0,0 +1,7 @@
1
+ from lightning_sdk.cli.utils.coloring import CustomHelpFormatter
2
+ from lightning_sdk.cli.utils.richt_print import rich_to_str
3
+
4
+ __all__ = [
5
+ "CustomHelpFormatter",
6
+ "rich_to_str",
7
+ ]
@@ -0,0 +1,10 @@
1
+ from lightning_sdk.api.cloud_account_api import CloudAccountApi
2
+
3
+
4
+ def cloud_account_to_display_name(cloud_account: str, teamspace_id: str) -> str:
5
+ api = CloudAccountApi()
6
+ cloud_accounts = api.list_global_cloud_accounts(teamspace_id=teamspace_id)
7
+ for global_cloud_account in cloud_accounts:
8
+ if global_cloud_account.id == cloud_account:
9
+ return "Lightning AI"
10
+ return cloud_account
@@ -0,0 +1,24 @@
1
+ from typing import Optional
2
+
3
+ from lightning_sdk.base_studio import BaseStudio
4
+
5
+
6
+ def get_base_studio_id(studio_type: Optional[str]) -> Optional[str]:
7
+ base_studios = BaseStudio()
8
+ base_studios = base_studios.list()
9
+ template_id = None
10
+
11
+ if base_studios and len(base_studios):
12
+ # if not specified by user, use the first existing template studio
13
+ template_id = base_studios[0].id
14
+ # else, try to match the provided studio_type to base studio name
15
+ if studio_type:
16
+ normalized_studio_type = studio_type.lower().replace(" ", "-")
17
+ match = next(
18
+ (s for s in base_studios if s.name.lower().replace(" ", "-") == normalized_studio_type),
19
+ None,
20
+ )
21
+ if match:
22
+ template_id = match.id
23
+
24
+ return template_id
@@ -0,0 +1,69 @@
1
+ from typing import Dict, Optional, Set
2
+
3
+ import click
4
+
5
+ from lightning_sdk.machine import DEFAULT_MACHINE, Machine
6
+
7
+
8
+ def _split_gpus_spec(gpus: str) -> tuple[str, int]:
9
+ machine_name, machine_val = gpus.split(":", 1)
10
+ machine_name = machine_name.strip()
11
+ machine_val = machine_val.strip()
12
+
13
+ if not machine_val.isdigit() or int(machine_val) <= 0:
14
+ raise ValueError(f"Invalid GPU count '{machine_val}'. Must be a positive integer.")
15
+
16
+ machine_num = int(machine_val)
17
+ return machine_name, machine_num
18
+
19
+
20
+ def _construct_available_gpus(machine_options: Dict[str, str]) -> Set[str]:
21
+ # returns available gpus:count
22
+ available_gpus = set()
23
+ for v in machine_options.values():
24
+ if "_X_" in v:
25
+ gpu_type_num = v.replace("_X_", ":")
26
+ available_gpus.add(gpu_type_num)
27
+ else:
28
+ available_gpus.add(v)
29
+ return available_gpus
30
+
31
+
32
+ def _get_machine_from_gpus(gpus: str) -> Machine:
33
+ machine_name = gpus
34
+ machine_num = 1
35
+
36
+ if ":" in gpus:
37
+ machine_name, machine_num = _split_gpus_spec(gpus)
38
+
39
+ machine_options = {
40
+ m.name.lower(): m.name for m in Machine.__dict__.values() if isinstance(m, Machine) and m._include_in_cli
41
+ }
42
+
43
+ if machine_num == 1:
44
+ # e.g. gpus=L4 or gpus=L4:1
45
+ gpu_key = machine_name.lower()
46
+ try:
47
+ return machine_options[gpu_key]
48
+ except KeyError:
49
+ available = ", ".join(_construct_available_gpus(machine_options))
50
+ raise ValueError(f"Invalid GPU type '{machine_name}'. Available options: {available}") from None
51
+
52
+ # Else: e.g. gpus=L4:4
53
+ gpu_key = f"{machine_name.lower()}_x_{machine_num}"
54
+ try:
55
+ return machine_options[gpu_key]
56
+ except KeyError:
57
+ available = ", ".join(_construct_available_gpus(machine_options))
58
+ raise ValueError(f"Invalid GPU configuration '{gpus}'. Available options: {available}") from None
59
+
60
+
61
+ def handle_machine_and_gpus_args(machine: Optional[str], gpus: Optional[str]) -> str:
62
+ if machine and gpus:
63
+ raise click.UsageError("Options --machine and --gpus are mutually exclusive. Provide only one.")
64
+ elif gpus:
65
+ machine = _get_machine_from_gpus(gpus.strip())
66
+ elif not machine:
67
+ machine = DEFAULT_MACHINE
68
+
69
+ return machine