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.
- lightning_sdk/__init__.py +13 -7
- lightning_sdk/__version__.py +3 -0
- lightning_sdk/agents.py +2 -1
- lightning_sdk/ai_hub.py +2 -1
- lightning_sdk/api/__init__.py +2 -0
- lightning_sdk/api/base_studio_api.py +13 -9
- lightning_sdk/api/cloud_account_api.py +31 -10
- lightning_sdk/api/deployment_api.py +27 -1
- lightning_sdk/api/job_api.py +16 -12
- lightning_sdk/api/license_api.py +26 -59
- lightning_sdk/api/llm_api.py +25 -2
- lightning_sdk/api/mmt_api.py +5 -2
- lightning_sdk/api/studio_api.py +252 -55
- lightning_sdk/api/teamspace_api.py +106 -30
- lightning_sdk/api/user_api.py +56 -2
- lightning_sdk/api/utils.py +108 -18
- lightning_sdk/base_studio.py +51 -27
- lightning_sdk/cli/__init__.py +1 -0
- lightning_sdk/cli/base_studio/__init__.py +10 -0
- lightning_sdk/cli/base_studio/list.py +43 -0
- lightning_sdk/cli/config/__init__.py +14 -0
- lightning_sdk/cli/config/get.py +57 -0
- lightning_sdk/cli/config/set.py +92 -0
- lightning_sdk/cli/config/show.py +9 -0
- lightning_sdk/cli/entrypoint.py +71 -71
- lightning_sdk/cli/groups.py +56 -0
- lightning_sdk/cli/job/__init__.py +7 -0
- lightning_sdk/cli/{clusters_menu.py → legacy/clusters_menu.py} +9 -6
- lightning_sdk/cli/{configure.py → legacy/configure.py} +2 -2
- lightning_sdk/cli/{connect.py → legacy/connect.py} +2 -2
- lightning_sdk/cli/{create.py → legacy/create.py} +12 -14
- lightning_sdk/cli/{delete.py → legacy/delete.py} +5 -5
- lightning_sdk/cli/legacy/deploy/__init__.py +0 -0
- lightning_sdk/cli/{deploy → legacy/deploy}/_auth.py +5 -6
- lightning_sdk/cli/{deploy → legacy/deploy}/devbox.py +8 -2
- lightning_sdk/cli/{deploy → legacy/deploy}/serve.py +19 -8
- lightning_sdk/cli/{download.py → legacy/download.py} +14 -15
- lightning_sdk/cli/legacy/entrypoint.py +110 -0
- lightning_sdk/cli/{generate.py → legacy/generate.py} +1 -1
- lightning_sdk/cli/{inspection.py → legacy/inspection.py} +1 -1
- lightning_sdk/cli/{job_and_mmt_action.py → legacy/job_and_mmt_action.py} +6 -6
- lightning_sdk/cli/{jobs_menu.py → legacy/jobs_menu.py} +1 -1
- lightning_sdk/cli/{list.py → legacy/list.py} +12 -13
- lightning_sdk/cli/{mmts_menu.py → legacy/mmts_menu.py} +1 -1
- lightning_sdk/cli/{open.py → legacy/open.py} +4 -4
- lightning_sdk/cli/{start.py → legacy/start.py} +1 -0
- lightning_sdk/cli/{stop.py → legacy/stop.py} +1 -1
- lightning_sdk/cli/{switch.py → legacy/switch.py} +1 -0
- lightning_sdk/cli/{teamspace_menu.py → legacy/teamspace_menu.py} +1 -1
- lightning_sdk/cli/{upload.py → legacy/upload.py} +7 -8
- lightning_sdk/cli/license/__init__.py +14 -0
- lightning_sdk/cli/license/get.py +15 -0
- lightning_sdk/cli/license/list.py +45 -0
- lightning_sdk/cli/license/set.py +13 -0
- lightning_sdk/cli/mmt/__init__.py +7 -0
- lightning_sdk/cli/studio/__init__.py +24 -0
- lightning_sdk/cli/studio/connect.py +139 -0
- lightning_sdk/cli/studio/create.py +96 -0
- lightning_sdk/cli/studio/delete.py +49 -0
- lightning_sdk/cli/studio/list.py +85 -0
- lightning_sdk/cli/studio/ssh.py +64 -0
- lightning_sdk/cli/studio/start.py +115 -0
- lightning_sdk/cli/studio/stop.py +45 -0
- lightning_sdk/cli/studio/switch.py +66 -0
- lightning_sdk/cli/utils/__init__.py +7 -0
- lightning_sdk/cli/utils/cloud_account_map.py +10 -0
- lightning_sdk/cli/utils/get_base_studio.py +24 -0
- lightning_sdk/cli/utils/handle_machine_and_gpus_args.py +69 -0
- lightning_sdk/cli/utils/logging.py +122 -0
- lightning_sdk/cli/utils/owner_selection.py +110 -0
- lightning_sdk/cli/utils/resolve.py +28 -0
- lightning_sdk/cli/utils/richt_print.py +35 -0
- lightning_sdk/cli/utils/save_to_config.py +27 -0
- lightning_sdk/cli/utils/ssh_connection.py +59 -0
- lightning_sdk/cli/utils/studio_selection.py +113 -0
- lightning_sdk/cli/utils/teamspace_selection.py +125 -0
- lightning_sdk/cli/vm/__init__.py +20 -0
- lightning_sdk/cli/vm/create.py +33 -0
- lightning_sdk/cli/vm/delete.py +25 -0
- lightning_sdk/cli/vm/list.py +30 -0
- lightning_sdk/cli/vm/ssh.py +31 -0
- lightning_sdk/cli/vm/start.py +60 -0
- lightning_sdk/cli/vm/stop.py +25 -0
- lightning_sdk/cli/vm/switch.py +38 -0
- lightning_sdk/constants.py +1 -0
- lightning_sdk/deployment/__init__.py +2 -0
- lightning_sdk/deployment/deployment.py +17 -2
- lightning_sdk/helpers.py +56 -37
- lightning_sdk/job/base.py +21 -6
- lightning_sdk/job/job.py +13 -0
- lightning_sdk/job/v1.py +11 -0
- lightning_sdk/job/v2.py +12 -0
- lightning_sdk/lightning_cloud/login.py +320 -10
- lightning_sdk/lightning_cloud/openapi/__init__.py +113 -3
- lightning_sdk/lightning_cloud/openapi/api/__init__.py +3 -0
- lightning_sdk/lightning_cloud/openapi/api/assistants_service_api.py +713 -75
- lightning_sdk/lightning_cloud/openapi/api/auth_service_api.py +376 -0
- lightning_sdk/lightning_cloud/openapi/api/billing_service_api.py +191 -1
- lightning_sdk/lightning_cloud/openapi/api/cloud_space_environment_template_service_api.py +5 -1
- lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +420 -0
- lightning_sdk/lightning_cloud/openapi/api/cloudy_service_api.py +0 -97
- lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +420 -0
- lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +101 -0
- lightning_sdk/lightning_cloud/openapi/api/incidents_service_api.py +1058 -0
- lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +121 -0
- lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +1742 -94
- lightning_sdk/lightning_cloud/openapi/api/markets_service_api.py +145 -0
- lightning_sdk/lightning_cloud/openapi/api/models_store_api.py +4 -4
- lightning_sdk/lightning_cloud/openapi/api/product_license_service_api.py +108 -108
- lightning_sdk/lightning_cloud/openapi/api/projects_service_api.py +105 -0
- lightning_sdk/lightning_cloud/openapi/api/schedules_service_api.py +347 -0
- lightning_sdk/lightning_cloud/openapi/api/sdk_command_history_service_api.py +141 -0
- lightning_sdk/lightning_cloud/openapi/api/storage_service_api.py +761 -1
- lightning_sdk/lightning_cloud/openapi/configuration.py +3 -19
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +110 -3
- lightning_sdk/lightning_cloud/openapi/models/assistant_id_conversations_body.py +15 -15
- lightning_sdk/lightning_cloud/openapi/models/cloudspace_id_visibility_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/cluster_id_kubernetestemplates_body.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/cluster_id_metrics_body.py +131 -1
- lightning_sdk/lightning_cloud/openapi/models/create.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/create_machine_request_represents_the_request_to_create_a_machine.py +461 -0
- lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +105 -1
- lightning_sdk/lightning_cloud/openapi/models/externalv1_user_status.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/id_codeconfig_body.py +3 -81
- lightning_sdk/lightning_cloud/openapi/models/id_fork_body1.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/id_render_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/id_sleepconfig_body.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/id_transfer_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/incident_id_messages_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/incidents_id_body.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/job_id_reportroutingtelemetry_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/kubernetestemplates_id_body.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/license_key_validate_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/message_id_actions_body.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/messages_message_id_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/metricsstream_create_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/models_model_id_body.py +109 -31
- lightning_sdk/lightning_cloud/openapi/models/models_model_id_body1.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/project_id_storage_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/project_id_storagetransfers_body.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/project_tab_management_messages.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/storage_complete_body.py +41 -15
- lightning_sdk/lightning_cloud/openapi/models/storagetransfers_validate_body.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/update1.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/uploads_upload_id_body1.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/user_id_affiliatelinks_body.py +107 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_abort_storage_transfer_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_aggregated_pod_metrics.py +799 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_ai_pod_v1.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_assistant_session_daily_aggregated.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_billing_tier.py +0 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cancel_running_cloud_space_instance_transfer_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_provider.py +2 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_specialized_view.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_transfer_metadata.py +147 -17
- lightning_sdk/lightning_cloud/openapi/models/v1_cloudflare_v1.py +3 -29
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_accelerator.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_capacity_reservation.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_metrics.py +1527 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_security_options.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cluster_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_container_metrics.py +21 -21
- lightning_sdk/lightning_cloud/openapi/models/v1_create_incident_request.py +305 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_license_request.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_machine_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_model_metrics_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +79 -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_daily_model_metrics.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +53 -1
- 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_delete_kubernetes_template_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_license_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_machine_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_external_cluster_spec.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_external_search_user.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_filestore_data_connection.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_filesystem_metric.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_firewall_rule.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_cloud_space_required_balance_status_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_cloud_space_transfer_estimate_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_latest_model_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_machine_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_market_pricing_response.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_model_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_temp_bucket_credentials_response.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_user_response.py +41 -15
- lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_group_node_metrics.py +1215 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_group_pod_metrics.py +1241 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_guest_login_request.py +177 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_guest_login_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_guest_user.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident.py +565 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_detail.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_event.py +591 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_message.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_severity.py +105 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_incident_type.py +108 -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_k8s_incident_indexes.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kai_scheduler_queue_metrics.py +627 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_aws_config.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_settings_v1.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_v1.py +107 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_template.py +357 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_template_property.py +227 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_lambda_labs_direct_v1.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_license.py +227 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_lightning_elastic_cluster_v1.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_aggregated_pod_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_metric_timestamps_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_namespace_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_namespace_user_metrics_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_conversation_message_actions_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_filesystem_metrics_response.py +123 -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_events_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_list_kubernetes_templates_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/{v1_list_product_licenses_response.py → v1_list_license_response.py} +16 -16
- lightning_sdk/lightning_cloud/openapi/models/v1_list_machines_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_platform_notifications_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_schedule_runs_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_storage_transfers_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_lustre_data_connection.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +617 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_machine_direct_v1.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_magic_link_login_request.py +1 -27
- lightning_sdk/lightning_cloud/openapi/models/v1_magic_link_login_response.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_managed_model.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_market_price.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_message_action.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_metrics_stream.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_model_metrics.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_namespace_metrics.py +591 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_namespace_user_metrics.py +435 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_nebius_direct_v1.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +361 -23
- lightning_sdk/lightning_cloud/openapi/models/v1_notification_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_pause_storage_transfer_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_platform_notification.py +279 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_pod_metrics.py +335 -23
- lightning_sdk/lightning_cloud/openapi/models/v1_project.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_cluster_binding.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_project_tab.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/{v1_product_license_check_response.py → v1_purchase_annual_upsell_request.py} +23 -23
- lightning_sdk/lightning_cloud/openapi/models/v1_purchase_annual_upsell_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_quote_annual_upsell_response.py +227 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_render_kubernetes_template_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_report_deployment_routing_telemetry_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_required_balance_reason.py +107 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_reset_api_key_request.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_reset_api_key_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_resource_visibility.py +1 -27
- lightning_sdk/lightning_cloud/openapi/models/v1_resume_storage_transfer_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_routing_telemetry.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_schedule_run.py +357 -0
- 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_secret_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_server_alert_type.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_slack_notifier.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_slack_notifier_type.py +105 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset.py +133 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_storage_transfer.py +435 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_storage_transfer_status.py +108 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_token_login_request.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_token_login_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_token_owner_type.py +104 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_update_cloud_space_instance_config_request.py +3 -81
- lightning_sdk/lightning_cloud/openapi/models/v1_update_project_tab_order_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_update_user_request.py +41 -15
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +444 -600
- lightning_sdk/lightning_cloud/openapi/models/v1_validate_license_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_validate_storage_transfer_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_voltage_park_direct_v1.py +29 -3
- lightning_sdk/lightning_cloud/rest_client.py +48 -45
- lightning_sdk/lightning_cloud/utils/data_connection.py +51 -1
- lightning_sdk/llm/llm.py +175 -56
- lightning_sdk/llm/public_assistants.py +44 -7
- lightning_sdk/machine.py +21 -2
- lightning_sdk/mmt/base.py +7 -0
- lightning_sdk/mmt/mmt.py +11 -3
- lightning_sdk/mmt/v1.py +3 -1
- lightning_sdk/mmt/v2.py +4 -0
- lightning_sdk/owner.py +2 -1
- lightning_sdk/pipeline/steps.py +6 -0
- lightning_sdk/plugin.py +6 -1
- lightning_sdk/studio.py +294 -53
- lightning_sdk/teamspace.py +167 -7
- lightning_sdk/user.py +19 -1
- lightning_sdk/utils/config.py +179 -0
- lightning_sdk/utils/license.py +13 -0
- lightning_sdk/utils/logging.py +79 -0
- lightning_sdk/utils/names.py +1179 -0
- lightning_sdk/utils/progress.py +283 -0
- lightning_sdk/utils/resolve.py +82 -7
- {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/METADATA +2 -1
- {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/RECORD +328 -169
- {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/entry_points.txt +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_product_license.py +0 -435
- lightning_sdk/services/license.py +0 -363
- /lightning_sdk/cli/{deploy → legacy}/__init__.py +0 -0
- /lightning_sdk/cli/{ai_hub.py → legacy/ai_hub.py} +0 -0
- /lightning_sdk/cli/{docker_cli.py → legacy/docker_cli.py} +0 -0
- /lightning_sdk/cli/{exceptions.py → legacy/exceptions.py} +0 -0
- /lightning_sdk/cli/{run.py → legacy/run.py} +0 -0
- /lightning_sdk/cli/{studios_menu.py → legacy/studios_menu.py} +0 -0
- /lightning_sdk/cli/{coloring.py → utils/coloring.py} +0 -0
- {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/LICENSE +0 -0
- {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/WHEEL +0 -0
- {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.11.5.dist-info}/top_level.txt +0 -0
lightning_sdk/api/user_api.py
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import re
|
|
2
|
+
from typing import Dict, List, Optional, Union
|
|
2
3
|
|
|
3
4
|
from lightning_sdk.lightning_cloud.login import Auth
|
|
4
5
|
from lightning_sdk.lightning_cloud.openapi import (
|
|
6
|
+
SecretsIdBody1,
|
|
5
7
|
V1CloudSpace,
|
|
8
|
+
V1CreateUserSecretRequest,
|
|
6
9
|
V1GetUserResponse,
|
|
7
10
|
V1ListCloudSpacesResponse,
|
|
8
11
|
V1Membership,
|
|
9
12
|
V1Organization,
|
|
10
13
|
V1SearchUser,
|
|
14
|
+
V1Secret,
|
|
11
15
|
V1UserFeatures,
|
|
12
16
|
)
|
|
17
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_secret_type import V1SecretType
|
|
13
18
|
from lightning_sdk.lightning_cloud.rest_client import LightningClient
|
|
14
19
|
|
|
15
20
|
|
|
@@ -56,8 +61,14 @@ class UserApi:
|
|
|
56
61
|
def _get_all_teamspace_memberships(
|
|
57
62
|
self,
|
|
58
63
|
user_id: str, # todo: this is unused, but still required
|
|
64
|
+
org_id: Optional[str] = None,
|
|
59
65
|
) -> List[V1Membership]:
|
|
60
|
-
|
|
66
|
+
kwargs: Dict[str, Union[bool, str]] = {"filter_by_user_id": True}
|
|
67
|
+
|
|
68
|
+
if org_id is not None:
|
|
69
|
+
kwargs["organization_id"] = org_id
|
|
70
|
+
|
|
71
|
+
return self._client.projects_service_list_memberships(**kwargs).memberships
|
|
61
72
|
|
|
62
73
|
def _get_authed_user_name(self) -> str:
|
|
63
74
|
"""Gets the currently logged-in user."""
|
|
@@ -69,3 +80,46 @@ class UserApi:
|
|
|
69
80
|
def _get_feature_flags(self) -> V1UserFeatures:
|
|
70
81
|
resp: V1GetUserResponse = self._client.auth_service_get_user()
|
|
71
82
|
return resp.features
|
|
83
|
+
|
|
84
|
+
def get_secrets(self) -> Dict[str, str]:
|
|
85
|
+
"""Get all secrets for the current user."""
|
|
86
|
+
secrets = self._get_secrets()
|
|
87
|
+
# this returns encrypted values for security. It doesn't make sense to show them,
|
|
88
|
+
# so we just return a placeholder
|
|
89
|
+
# not a security issue to replace in the client as we get the encrypted values from the server.
|
|
90
|
+
return {secret.name: "***REDACTED***" for secret in secrets if secret.type == V1SecretType.UNSPECIFIED}
|
|
91
|
+
|
|
92
|
+
def set_secret(self, key: str, value: str) -> None:
|
|
93
|
+
"""Set a secret for the current user.
|
|
94
|
+
|
|
95
|
+
This will replace the existing secret if it exists and create a new one if it doesn't.
|
|
96
|
+
"""
|
|
97
|
+
secrets = self._get_secrets()
|
|
98
|
+
for secret in secrets:
|
|
99
|
+
if secret.name == key:
|
|
100
|
+
return self._update_secret(secret.id, value)
|
|
101
|
+
return self._create_secret(key, value)
|
|
102
|
+
|
|
103
|
+
def _get_secrets(self) -> List[V1Secret]:
|
|
104
|
+
return self._client.secret_service_list_user_secrets().secrets
|
|
105
|
+
|
|
106
|
+
def _update_secret(self, secret_id: str, value: str) -> None:
|
|
107
|
+
self._client.secret_service_update_user_secret(
|
|
108
|
+
body=SecretsIdBody1(value=value),
|
|
109
|
+
id=secret_id,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def _create_secret(
|
|
113
|
+
self,
|
|
114
|
+
key: str,
|
|
115
|
+
value: str,
|
|
116
|
+
) -> None:
|
|
117
|
+
self._client.secret_service_create_user_secret(body=V1CreateUserSecretRequest(name=key, value=value))
|
|
118
|
+
|
|
119
|
+
def verify_secret_name(self, name: str) -> bool:
|
|
120
|
+
"""Verify if a secret name is valid.
|
|
121
|
+
|
|
122
|
+
A valid secret name starts with a letter or underscore, followed by letters, digits, or underscores.
|
|
123
|
+
"""
|
|
124
|
+
pattern = r"^[A-Za-z_][A-Za-z0-9_]*$"
|
|
125
|
+
return re.match(pattern, name) is not None
|
lightning_sdk/api/utils.py
CHANGED
|
@@ -6,7 +6,7 @@ import re
|
|
|
6
6
|
from concurrent.futures import ThreadPoolExecutor
|
|
7
7
|
from functools import partial
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
9
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, TypedDict, Union
|
|
10
10
|
|
|
11
11
|
import backoff
|
|
12
12
|
import requests
|
|
@@ -19,6 +19,7 @@ from lightning_sdk.lightning_cloud.openapi import (
|
|
|
19
19
|
ModelsStoreApi,
|
|
20
20
|
ProjectIdStorageBody,
|
|
21
21
|
StorageCompleteBody,
|
|
22
|
+
StorageServiceApi,
|
|
22
23
|
UploadIdCompleteBody,
|
|
23
24
|
UploadIdPartsBody,
|
|
24
25
|
V1CompletedPart,
|
|
@@ -367,38 +368,40 @@ _DOWNLOAD_REQUEST_CHUNK_SIZE = 10 * _BYTES_PER_MB
|
|
|
367
368
|
_DOWNLOAD_MIN_CHUNK_SIZE = 100 * _BYTES_PER_KB
|
|
368
369
|
|
|
369
370
|
|
|
371
|
+
class _RefreshResponse(TypedDict):
|
|
372
|
+
url: str
|
|
373
|
+
size: int
|
|
374
|
+
|
|
375
|
+
|
|
370
376
|
class _FileDownloader:
|
|
371
377
|
def __init__(
|
|
372
378
|
self,
|
|
373
|
-
client: LightningClient,
|
|
374
|
-
model_id: str,
|
|
375
|
-
version: str,
|
|
376
379
|
teamspace_id: str,
|
|
377
380
|
remote_path: str,
|
|
378
381
|
file_path: str,
|
|
379
382
|
executor: ThreadPoolExecutor,
|
|
380
383
|
num_workers: int = 20,
|
|
381
384
|
progress_bar: Optional[tqdm] = None,
|
|
385
|
+
url: Optional[str] = None,
|
|
386
|
+
size: Optional[int] = None,
|
|
387
|
+
refresh_fn: Optional[Callable[[], _RefreshResponse]] = None,
|
|
382
388
|
) -> None:
|
|
383
|
-
self.api = ModelsStoreApi(client.api_client)
|
|
384
|
-
self.model_id = model_id
|
|
385
|
-
self.version = version
|
|
386
389
|
self.teamspace_id = teamspace_id
|
|
387
390
|
self.local_path = file_path
|
|
388
391
|
self.remote_path = remote_path
|
|
389
392
|
self.progress_bar = progress_bar
|
|
390
393
|
self.num_workers = num_workers
|
|
391
|
-
self._url =
|
|
392
|
-
self._size =
|
|
394
|
+
self._url = url
|
|
395
|
+
self._size = size
|
|
393
396
|
self.executor = executor
|
|
397
|
+
self.refresh_fn = refresh_fn
|
|
394
398
|
|
|
395
399
|
@backoff.on_exception(backoff.expo, ApiException, max_tries=10)
|
|
396
400
|
def refresh(self) -> None:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
self._size = int(response.size)
|
|
401
|
+
if self.refresh_fn is not None:
|
|
402
|
+
response = self.refresh_fn()
|
|
403
|
+
self._url = response["url"]
|
|
404
|
+
self._size = response["size"]
|
|
402
405
|
|
|
403
406
|
@property
|
|
404
407
|
def url(self) -> str:
|
|
@@ -413,6 +416,11 @@ class _FileDownloader:
|
|
|
413
416
|
return
|
|
414
417
|
self.progress_bar.update(n)
|
|
415
418
|
|
|
419
|
+
def update_filename(self, desc: str) -> None:
|
|
420
|
+
if self.progress_bar is None:
|
|
421
|
+
return
|
|
422
|
+
self.progress_bar.set_description(f"{(desc[:72] + '...') if len(desc) > 75 else desc:<75.75}")
|
|
423
|
+
|
|
416
424
|
@backoff.on_exception(backoff.expo, (requests.exceptions.HTTPError), max_tries=10)
|
|
417
425
|
def _download_chunk(self, filename: str, start_end: Tuple[int]) -> None:
|
|
418
426
|
start, end = start_end
|
|
@@ -447,6 +455,8 @@ class _FileDownloader:
|
|
|
447
455
|
f.write(b"\x00" * remaining_size)
|
|
448
456
|
|
|
449
457
|
def _multipart_download(self, filename: str, num_workers: int) -> None:
|
|
458
|
+
self.update_filename(f"Downloading {self.remote_path}")
|
|
459
|
+
|
|
450
460
|
num_chunks = num_workers
|
|
451
461
|
chunk_size = math.ceil(self.size / num_chunks)
|
|
452
462
|
|
|
@@ -464,7 +474,8 @@ class _FileDownloader:
|
|
|
464
474
|
concurrent.futures.wait(futures)
|
|
465
475
|
|
|
466
476
|
def download(self) -> None:
|
|
467
|
-
self.
|
|
477
|
+
if self.url is None:
|
|
478
|
+
self.refresh()
|
|
468
479
|
|
|
469
480
|
tmp_filename = f"{self.local_path}.download"
|
|
470
481
|
|
|
@@ -539,6 +550,15 @@ def _download_model_files(
|
|
|
539
550
|
mininterval=1,
|
|
540
551
|
)
|
|
541
552
|
|
|
553
|
+
def refresh_fn(filename: str) -> _RefreshResponse:
|
|
554
|
+
resp = api.models_store_get_model_file_url(
|
|
555
|
+
project_id=response.project_id,
|
|
556
|
+
model_id=response.model_id,
|
|
557
|
+
version=response.version,
|
|
558
|
+
filepath=filename,
|
|
559
|
+
)
|
|
560
|
+
return {"url": resp.url, "size": int(resp.size)}
|
|
561
|
+
|
|
542
562
|
with ThreadPoolExecutor(max_workers=min(num_workers, len(response.filepaths))) as file_executor, ThreadPoolExecutor(
|
|
543
563
|
max_workers=num_workers
|
|
544
564
|
) as part_executor:
|
|
@@ -549,15 +569,13 @@ def _download_model_files(
|
|
|
549
569
|
local_file.parent.mkdir(parents=True, exist_ok=True)
|
|
550
570
|
|
|
551
571
|
file_downloader = _FileDownloader(
|
|
552
|
-
client=client,
|
|
553
|
-
model_id=response.model_id,
|
|
554
|
-
version=response.version,
|
|
555
572
|
teamspace_id=response.project_id,
|
|
556
573
|
remote_path=filepath,
|
|
557
574
|
file_path=str(local_file),
|
|
558
575
|
num_workers=num_workers,
|
|
559
576
|
progress_bar=pbar,
|
|
560
577
|
executor=part_executor,
|
|
578
|
+
refresh_fn=lambda f=filepath: refresh_fn(f),
|
|
561
579
|
)
|
|
562
580
|
|
|
563
581
|
futures.append(file_executor.submit(file_downloader.download))
|
|
@@ -568,6 +586,78 @@ def _download_model_files(
|
|
|
568
586
|
return response.filepaths
|
|
569
587
|
|
|
570
588
|
|
|
589
|
+
def _download_teamspace_files(
|
|
590
|
+
client: LightningClient,
|
|
591
|
+
teamspace_id: str,
|
|
592
|
+
cluster_id: str,
|
|
593
|
+
prefix: str,
|
|
594
|
+
download_dir: Path,
|
|
595
|
+
progress_bar: bool,
|
|
596
|
+
num_workers: int = os.cpu_count() * 4,
|
|
597
|
+
) -> None:
|
|
598
|
+
api = StorageServiceApi(client.api_client)
|
|
599
|
+
response = None
|
|
600
|
+
|
|
601
|
+
pbar = None
|
|
602
|
+
if progress_bar:
|
|
603
|
+
pbar = tqdm(
|
|
604
|
+
desc="Downloading files",
|
|
605
|
+
unit="B",
|
|
606
|
+
unit_scale=True,
|
|
607
|
+
unit_divisor=1000,
|
|
608
|
+
position=-1,
|
|
609
|
+
mininterval=1,
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
def refresh_fn(filename: str) -> _RefreshResponse:
|
|
613
|
+
resp = api.storage_service_list_project_artifacts(
|
|
614
|
+
project_id=teamspace_id,
|
|
615
|
+
cluster_id=cluster_id,
|
|
616
|
+
page_token="",
|
|
617
|
+
include_download_url=True,
|
|
618
|
+
prefix=prefix + filename,
|
|
619
|
+
page_size=1,
|
|
620
|
+
)
|
|
621
|
+
return {"url": resp.artifacts[0].url, "size": int(resp.artifacts[0].size_bytes)}
|
|
622
|
+
|
|
623
|
+
with ThreadPoolExecutor(max_workers=num_workers) as file_executor, ThreadPoolExecutor(
|
|
624
|
+
max_workers=num_workers
|
|
625
|
+
) as part_executor:
|
|
626
|
+
while response is None or (response is not None and response.next_page_token != ""):
|
|
627
|
+
response = api.storage_service_list_project_artifacts(
|
|
628
|
+
project_id=teamspace_id,
|
|
629
|
+
cluster_id=cluster_id,
|
|
630
|
+
page_token=response.next_page_token if response is not None else "",
|
|
631
|
+
include_download_url=True,
|
|
632
|
+
prefix=prefix,
|
|
633
|
+
page_size=1000,
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
page_futures = []
|
|
637
|
+
for file in response.artifacts:
|
|
638
|
+
local_file = download_dir / file.filename
|
|
639
|
+
local_file.parent.mkdir(parents=True, exist_ok=True)
|
|
640
|
+
|
|
641
|
+
file_downloader = _FileDownloader(
|
|
642
|
+
teamspace_id=teamspace_id,
|
|
643
|
+
remote_path=file.filename,
|
|
644
|
+
file_path=str(local_file),
|
|
645
|
+
num_workers=num_workers,
|
|
646
|
+
progress_bar=pbar,
|
|
647
|
+
executor=part_executor,
|
|
648
|
+
url=file.url,
|
|
649
|
+
size=int(file.size_bytes),
|
|
650
|
+
refresh_fn=lambda f=file: refresh_fn(f.filename),
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
page_futures.append(file_executor.submit(file_downloader.download))
|
|
654
|
+
|
|
655
|
+
if page_futures:
|
|
656
|
+
concurrent.futures.wait(page_futures)
|
|
657
|
+
|
|
658
|
+
pbar.set_description("Download complete")
|
|
659
|
+
|
|
660
|
+
|
|
571
661
|
def _create_app(
|
|
572
662
|
client: CloudSpaceServiceApi,
|
|
573
663
|
studio_id: str,
|
lightning_sdk/base_studio.py
CHANGED
|
@@ -3,11 +3,11 @@ from typing import List, Optional, Union
|
|
|
3
3
|
|
|
4
4
|
from lightning_sdk.api.base_studio_api import BaseStudioApi
|
|
5
5
|
from lightning_sdk.api.user_api import UserApi
|
|
6
|
-
from lightning_sdk.lightning_cloud import login
|
|
7
6
|
from lightning_sdk.lightning_cloud.openapi.models.v1_cloud_space_environment_type import V1CloudSpaceEnvironmentType
|
|
8
7
|
from lightning_sdk.organization import Organization
|
|
8
|
+
from lightning_sdk.teamspace import Teamspace
|
|
9
9
|
from lightning_sdk.user import User
|
|
10
|
-
from lightning_sdk.utils.resolve import
|
|
10
|
+
from lightning_sdk.utils.resolve import _resolve_teamspace
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@dataclass
|
|
@@ -16,12 +16,15 @@ class BaseStudioInfo:
|
|
|
16
16
|
name: str
|
|
17
17
|
managed_id: str
|
|
18
18
|
description: str
|
|
19
|
+
creator: str
|
|
20
|
+
enabled: bool
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
class BaseStudio:
|
|
22
24
|
def __init__(
|
|
23
25
|
self,
|
|
24
26
|
name: Optional[str] = None,
|
|
27
|
+
teamspace: Optional[Union[str, Teamspace]] = None,
|
|
25
28
|
org: Optional[Union[str, Organization]] = None,
|
|
26
29
|
user: Optional[Union[str, User]] = None,
|
|
27
30
|
) -> None:
|
|
@@ -36,26 +39,35 @@ class BaseStudio:
|
|
|
36
39
|
Raises:
|
|
37
40
|
ConnectionError: If there is an issue with the authentication process.
|
|
38
41
|
"""
|
|
39
|
-
self.
|
|
40
|
-
self._user = None
|
|
42
|
+
self._teamspace = None
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
self._user = User(name=UserApi()._get_user_by_id(self._auth.user_id).username)
|
|
46
|
-
except ConnectionError as e:
|
|
47
|
-
raise e
|
|
44
|
+
_teamspace = _resolve_teamspace(teamspace=teamspace, org=org, user=user)
|
|
45
|
+
if _teamspace is None:
|
|
46
|
+
raise ValueError("Couldn't resolve teamspace from the provided name, org, or user")
|
|
48
47
|
|
|
49
|
-
self.
|
|
50
|
-
|
|
48
|
+
self._teamspace = _teamspace
|
|
49
|
+
|
|
50
|
+
# self._auth = login.Auth()
|
|
51
|
+
# self._user = None
|
|
52
|
+
|
|
53
|
+
# try:
|
|
54
|
+
# self._auth.authenticate()
|
|
55
|
+
# if user is None:
|
|
56
|
+
# self._user = User(name=UserApi()._get_user_by_id(self._auth.user_id).username)
|
|
57
|
+
# except ConnectionError as e:
|
|
58
|
+
# raise e
|
|
59
|
+
|
|
60
|
+
# self._user = _resolve_user(self._user or user)
|
|
61
|
+
# self._org = _resolve_org(org)
|
|
51
62
|
|
|
52
63
|
self._base_studio_api = BaseStudioApi()
|
|
53
64
|
|
|
54
65
|
if name is not None:
|
|
55
|
-
|
|
66
|
+
org_id = self._teamspace._org.id if self._teamspace._org is not None else None
|
|
67
|
+
base_studio = self._base_studio_api.get_base_studio(name, org_id)
|
|
56
68
|
|
|
57
69
|
if base_studio is None:
|
|
58
|
-
raise ValueError(f"Base studio with name {name} does not exist
|
|
70
|
+
raise ValueError(f"Base studio with name {name} does not exist")
|
|
59
71
|
self._base_studio = base_studio
|
|
60
72
|
|
|
61
73
|
def update(
|
|
@@ -68,9 +80,11 @@ class BaseStudio:
|
|
|
68
80
|
machine_image_version: Optional[str] = None,
|
|
69
81
|
setup_script_text: Optional[str] = None,
|
|
70
82
|
) -> None:
|
|
83
|
+
org_id = self._teamspace._org.id if self._teamspace._org is not None else None
|
|
84
|
+
# TODO: if not in an org, can't update them
|
|
71
85
|
self._base_studio = self._base_studio_api.update_base_studio(
|
|
72
86
|
self._base_studio.id,
|
|
73
|
-
|
|
87
|
+
org_id,
|
|
74
88
|
name=name,
|
|
75
89
|
allowed_machines=allowed_machines,
|
|
76
90
|
default_machine=default_machine,
|
|
@@ -80,20 +94,30 @@ class BaseStudio:
|
|
|
80
94
|
disabled=disabled,
|
|
81
95
|
)
|
|
82
96
|
|
|
83
|
-
def list(self,
|
|
97
|
+
def list(self, include_disabled: bool = False) -> List[BaseStudioInfo]:
|
|
84
98
|
"""List all base studios in the organization.
|
|
85
99
|
|
|
100
|
+
Args:
|
|
101
|
+
managed: Whether to filter for managed base studios.
|
|
102
|
+
include_disabled: Whether to include disabled base studios in the results.
|
|
103
|
+
|
|
86
104
|
Returns:
|
|
87
|
-
List[
|
|
105
|
+
List[BaseStudioInfo]: A list of base studio templates.
|
|
88
106
|
"""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
org_id = self._teamspace._org.id if self._teamspace._org is not None else None
|
|
108
|
+
templates = self._base_studio_api.get_all_base_studios(org_id).templates
|
|
109
|
+
|
|
110
|
+
return [
|
|
111
|
+
BaseStudioInfo(
|
|
112
|
+
id=template.id,
|
|
113
|
+
name=template.name,
|
|
114
|
+
managed_id=template.managed_id,
|
|
115
|
+
description=template.description,
|
|
116
|
+
creator="⚡ Lightning AI"
|
|
117
|
+
if template.managed_id
|
|
118
|
+
else UserApi()._get_user_by_id(template.user_id).username,
|
|
119
|
+
enabled=not template.disabled,
|
|
98
120
|
)
|
|
99
|
-
|
|
121
|
+
for template in templates
|
|
122
|
+
if include_disabled or not template.disabled
|
|
123
|
+
]
|
lightning_sdk/cli/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Lightning SDK CLI module."""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Base Studio CLI commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def register_commands(group: click.Group) -> None:
|
|
7
|
+
"""Register base studio commands with the given group."""
|
|
8
|
+
from lightning_sdk.cli.base_studio.list import list_base_studios
|
|
9
|
+
|
|
10
|
+
group.add_command(list_base_studios)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Base Studio list command."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
|
|
6
|
+
from lightning_sdk.base_studio import BaseStudio
|
|
7
|
+
from lightning_sdk.cli.utils.richt_print import rich_to_str
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command("list")
|
|
11
|
+
@click.option("--include-disabled", help="Include disabled Base Studios in the list.", is_flag=True)
|
|
12
|
+
def list_base_studios(include_disabled: bool) -> None:
|
|
13
|
+
"""List Base Studios in an org.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
lightning base-studio list
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
return list_impl(include_disabled=include_disabled)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def list_impl(include_disabled: bool) -> None:
|
|
23
|
+
base_studio_cls = BaseStudio()
|
|
24
|
+
base_studios = base_studio_cls.list(include_disabled=include_disabled)
|
|
25
|
+
|
|
26
|
+
table = Table(
|
|
27
|
+
pad_edge=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
table.add_column("Name")
|
|
31
|
+
table.add_column("Description")
|
|
32
|
+
table.add_column("Creator")
|
|
33
|
+
table.add_column("Enabled")
|
|
34
|
+
|
|
35
|
+
for base_studio in base_studios:
|
|
36
|
+
table.add_row(
|
|
37
|
+
base_studio.name.lower().replace(" ", "-"),
|
|
38
|
+
base_studio.description or "",
|
|
39
|
+
base_studio.creator,
|
|
40
|
+
"Yes" if base_studio.enabled else "No",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
click.echo(rich_to_str(table), color=True)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Config CLI commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def register_commands(group: click.Group) -> None:
|
|
7
|
+
"""Register config commands with the given group."""
|
|
8
|
+
from lightning_sdk.cli.config.get import get
|
|
9
|
+
from lightning_sdk.cli.config.set import set_value
|
|
10
|
+
from lightning_sdk.cli.config.show import show
|
|
11
|
+
|
|
12
|
+
group.add_command(get)
|
|
13
|
+
group.add_command(set_value)
|
|
14
|
+
group.add_command(show)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from lightning_sdk.utils.config import Config, DefaultConfigKeys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.group("get")
|
|
7
|
+
def get() -> None:
|
|
8
|
+
"""Get configuration values."""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@get.command("user")
|
|
12
|
+
def get_user() -> None:
|
|
13
|
+
"""Get the default user name from the config."""
|
|
14
|
+
config = Config()
|
|
15
|
+
user = config.get_value(DefaultConfigKeys.user)
|
|
16
|
+
click.echo(user)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@get.command("org")
|
|
20
|
+
def get_org() -> None:
|
|
21
|
+
"""Get the default organization name from the config."""
|
|
22
|
+
config = Config()
|
|
23
|
+
org = config.get_value(DefaultConfigKeys.organization)
|
|
24
|
+
click.echo(org)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@get.command("teamspace")
|
|
28
|
+
def get_teamspace() -> None:
|
|
29
|
+
"""Get the default teamspace name from the config."""
|
|
30
|
+
config = Config()
|
|
31
|
+
teamspace_name = config.get_value(DefaultConfigKeys.teamspace_name)
|
|
32
|
+
teamspace_owner = config.get_value(DefaultConfigKeys.teamspace_owner)
|
|
33
|
+
click.echo(f"{teamspace_owner}/{teamspace_name}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@get.command("studio")
|
|
37
|
+
def get_studio() -> None:
|
|
38
|
+
"""Get the default sutdio name from the config."""
|
|
39
|
+
config = Config()
|
|
40
|
+
studio = config.get_value(DefaultConfigKeys.studio)
|
|
41
|
+
click.echo(studio)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@get.command("cloud-account")
|
|
45
|
+
def get_cloud_account() -> None:
|
|
46
|
+
"""Get the default cloud account name from the config."""
|
|
47
|
+
config = Config()
|
|
48
|
+
cloud_account = config.get_value(DefaultConfigKeys.cloud_account)
|
|
49
|
+
click.echo(cloud_account)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@get.command("cloud-provider")
|
|
53
|
+
def get_cloud_provider() -> None:
|
|
54
|
+
"""Get the default cloud provider name from the config."""
|
|
55
|
+
config = Config()
|
|
56
|
+
cloud_provider = config.get_value(DefaultConfigKeys.cloud_provider)
|
|
57
|
+
click.echo(cloud_provider)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from lightning_sdk.cli.utils.save_to_config import save_teamspace_to_config
|
|
4
|
+
from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
|
|
5
|
+
from lightning_sdk.machine import CloudProvider
|
|
6
|
+
from lightning_sdk.studio import Studio
|
|
7
|
+
from lightning_sdk.utils.config import Config, DefaultConfigKeys
|
|
8
|
+
from lightning_sdk.utils.resolve import _resolve_org, _resolve_user
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group("set")
|
|
12
|
+
def set_value() -> None:
|
|
13
|
+
"""Set configuration values."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@set_value.command("user")
|
|
17
|
+
@click.argument("user_name")
|
|
18
|
+
def set_user(user_name: str) -> None:
|
|
19
|
+
"""Set the default user name in the config."""
|
|
20
|
+
try:
|
|
21
|
+
_resolve_user(user_name)
|
|
22
|
+
except Exception:
|
|
23
|
+
# TODO: make this a generic CLI error
|
|
24
|
+
raise ValueError(f"Could not resolve user: '{user_name}'. Does the user exist?") from None
|
|
25
|
+
|
|
26
|
+
config = Config()
|
|
27
|
+
setattr(config, DefaultConfigKeys.user, user_name)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@set_value.command("org")
|
|
31
|
+
@click.argument("org_name")
|
|
32
|
+
def set_org(org_name: str) -> None:
|
|
33
|
+
"""Set the default organization name in the config."""
|
|
34
|
+
try:
|
|
35
|
+
_resolve_org(org_name)
|
|
36
|
+
except Exception:
|
|
37
|
+
# TODO: make this a generic CLI error
|
|
38
|
+
raise ValueError(f"Could not resolve organization: '{org_name}'. Does the organization exist?") from None
|
|
39
|
+
|
|
40
|
+
config = Config()
|
|
41
|
+
setattr(config, DefaultConfigKeys.organization, org_name)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@set_value.command("studio")
|
|
45
|
+
@click.argument("studio_name")
|
|
46
|
+
def set_studio(studio_name: str) -> None:
|
|
47
|
+
"""Set the default studio name in the config."""
|
|
48
|
+
try:
|
|
49
|
+
studio = Studio(studio_name)
|
|
50
|
+
except Exception:
|
|
51
|
+
# TODO: make this a generic CLI error
|
|
52
|
+
raise ValueError(f"Could not resolve studio: '{studio_name}'. Does the studio exist?") from None
|
|
53
|
+
|
|
54
|
+
config = Config()
|
|
55
|
+
setattr(config, DefaultConfigKeys.studio, studio.name)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@set_value.command("teamspace")
|
|
59
|
+
@click.argument("teamspace_name")
|
|
60
|
+
def set_teamspace(teamspace_name: str) -> None:
|
|
61
|
+
"""Set the default teamspace name in the config."""
|
|
62
|
+
menu = TeamspacesMenu()
|
|
63
|
+
teamspace_resolved = menu(teamspace=teamspace_name)
|
|
64
|
+
|
|
65
|
+
# explicit user action, so overwrite the config
|
|
66
|
+
save_teamspace_to_config(teamspace_resolved, overwrite=True)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@set_value.command("cloud-account")
|
|
70
|
+
@click.argument("cloud_account_name")
|
|
71
|
+
def set_cloud_account(cloud_account_name: str) -> None:
|
|
72
|
+
"""Set the default cloud account name in the config."""
|
|
73
|
+
config = Config()
|
|
74
|
+
setattr(config, DefaultConfigKeys.cloud_account, cloud_account_name)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@set_value.command("cloud-provider")
|
|
78
|
+
@click.argument("cloud_provider_name")
|
|
79
|
+
def set_cloud_provider(cloud_provider_name: str) -> None:
|
|
80
|
+
"""Set the default cloud provider name in the config."""
|
|
81
|
+
config = Config()
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
cloud_provider = CloudProvider(cloud_provider_name)
|
|
85
|
+
except ValueError:
|
|
86
|
+
# TODO: make this a generic CLI error
|
|
87
|
+
raise ValueError(
|
|
88
|
+
f"Could not resolve cloud provider: '{cloud_provider_name}'. "
|
|
89
|
+
f"Supported values are: {', '.join(m.name for m in list(CloudProvider))}"
|
|
90
|
+
) from None
|
|
91
|
+
|
|
92
|
+
setattr(config, DefaultConfigKeys.cloud_provider, cloud_provider.name)
|