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/teamspace.py
CHANGED
|
@@ -1,35 +1,59 @@
|
|
|
1
1
|
import glob
|
|
2
2
|
import os
|
|
3
3
|
import warnings
|
|
4
|
+
from enum import Enum
|
|
4
5
|
from pathlib import Path
|
|
5
|
-
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
|
|
6
|
+
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
|
|
6
7
|
|
|
7
8
|
from tqdm.auto import tqdm
|
|
8
9
|
|
|
9
10
|
import lightning_sdk
|
|
10
11
|
from lightning_sdk.agents import Agent
|
|
11
|
-
from lightning_sdk.api import TeamspaceApi
|
|
12
|
-
from lightning_sdk.lightning_cloud.openapi import V1Model, V1ModelVersionArchive, V1ProjectClusterBinding
|
|
13
|
-
from lightning_sdk.machine import Machine
|
|
12
|
+
from lightning_sdk.api import CloudAccountApi, TeamspaceApi
|
|
13
|
+
from lightning_sdk.lightning_cloud.openapi import V1ClusterType, V1Model, V1ModelVersionArchive, V1ProjectClusterBinding
|
|
14
|
+
from lightning_sdk.machine import CloudProvider, Machine
|
|
14
15
|
from lightning_sdk.models import UploadedModelInfo
|
|
15
16
|
from lightning_sdk.organization import Organization
|
|
16
17
|
from lightning_sdk.owner import Owner
|
|
17
18
|
from lightning_sdk.user import User
|
|
19
|
+
from lightning_sdk.utils.logging import TrackCallsMeta
|
|
18
20
|
from lightning_sdk.utils.resolve import (
|
|
19
21
|
_get_organizations_for_authed_user,
|
|
20
22
|
_parse_model_and_version,
|
|
21
23
|
_resolve_org,
|
|
22
24
|
_resolve_teamspace_name,
|
|
23
25
|
_resolve_user,
|
|
26
|
+
skip_studio_init,
|
|
24
27
|
)
|
|
25
28
|
|
|
26
29
|
if TYPE_CHECKING:
|
|
27
30
|
from lightning_sdk.job import Job
|
|
28
31
|
from lightning_sdk.mmt import MMT
|
|
29
|
-
from lightning_sdk.studio import Studio
|
|
32
|
+
from lightning_sdk.studio import VM, Studio
|
|
30
33
|
|
|
31
34
|
|
|
32
|
-
class
|
|
35
|
+
class FolderLocation(Enum):
|
|
36
|
+
AWS = "AWS"
|
|
37
|
+
GCP = "GCP"
|
|
38
|
+
CLOUD_AGNOSTIC = "CLOUD_AGNOSTIC"
|
|
39
|
+
|
|
40
|
+
def __str__(self) -> str:
|
|
41
|
+
"""Converts the FolderLocation to a str."""
|
|
42
|
+
return self.value
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ConnectionType(Enum):
|
|
46
|
+
EFS = "EFS"
|
|
47
|
+
S3 = "S3"
|
|
48
|
+
GCS = "GCS"
|
|
49
|
+
FILESTORE = "FILESTORE"
|
|
50
|
+
|
|
51
|
+
def __str__(self) -> str:
|
|
52
|
+
"""Converts the FolderLocation to a str."""
|
|
53
|
+
return self.value
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Teamspace(metaclass=TrackCallsMeta):
|
|
33
57
|
"""A teamspace is a collection of Studios, Clusters, Members and an associated Budget.
|
|
34
58
|
|
|
35
59
|
Args:
|
|
@@ -53,6 +77,7 @@ class Teamspace:
|
|
|
53
77
|
user: Optional[Union[str, User]] = None,
|
|
54
78
|
) -> None:
|
|
55
79
|
self._teamspace_api = TeamspaceApi()
|
|
80
|
+
self._cloud_account_api = CloudAccountApi()
|
|
56
81
|
|
|
57
82
|
name = _resolve_teamspace_name(name)
|
|
58
83
|
|
|
@@ -70,6 +95,20 @@ class Teamspace:
|
|
|
70
95
|
self._user = _resolve_user(user)
|
|
71
96
|
self._org = _resolve_org(org)
|
|
72
97
|
|
|
98
|
+
# If still no user or org resolved, try config defaults
|
|
99
|
+
if self._user is None and self._org is None:
|
|
100
|
+
from lightning_sdk.utils.config import Config, DefaultConfigKeys
|
|
101
|
+
|
|
102
|
+
config = Config()
|
|
103
|
+
owner_type = config.get_value(DefaultConfigKeys.teamspace_owner_type)
|
|
104
|
+
owner_name = config.get_value(DefaultConfigKeys.teamspace_owner)
|
|
105
|
+
|
|
106
|
+
if owner_type and owner_name:
|
|
107
|
+
if owner_type.lower() == "organization":
|
|
108
|
+
self._org = _resolve_org(owner_name)
|
|
109
|
+
elif owner_type.lower() == "user":
|
|
110
|
+
self._user = _resolve_user(owner_name)
|
|
111
|
+
|
|
73
112
|
self._owner: Owner
|
|
74
113
|
if self._user is None and self._org is None:
|
|
75
114
|
raise RuntimeError(
|
|
@@ -106,12 +145,25 @@ class Teamspace:
|
|
|
106
145
|
"""All studios within that teamspace."""
|
|
107
146
|
from lightning_sdk.studio import Studio
|
|
108
147
|
|
|
148
|
+
return self._get_studios(Studio)
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def vms(self) -> List["VM"]:
|
|
152
|
+
from lightning_sdk.studio import VM
|
|
153
|
+
|
|
154
|
+
return [x for x in self._get_studios(VM) if isinstance(x, VM)]
|
|
155
|
+
|
|
156
|
+
def _get_studios(self, target_cls: type) -> List[Union["Studio", "VM"]]:
|
|
109
157
|
studios = []
|
|
110
158
|
cloud_accounts = self._teamspace_api.list_cloud_accounts(teamspace_id=self.id)
|
|
111
159
|
for cl in cloud_accounts:
|
|
112
160
|
_studios = self._teamspace_api.list_studios(teamspace_id=self.id, cloud_account=cl.cluster_id)
|
|
113
161
|
for s in _studios:
|
|
114
|
-
|
|
162
|
+
with skip_studio_init():
|
|
163
|
+
studio = target_cls(name=s.name, teamspace=self, cluster=cl.cluster_name, create_ok=False)
|
|
164
|
+
studio._studio = s
|
|
165
|
+
studio._teamspace = self
|
|
166
|
+
studios.append(studio)
|
|
115
167
|
|
|
116
168
|
return studios
|
|
117
169
|
|
|
@@ -195,6 +247,24 @@ class Teamspace:
|
|
|
195
247
|
|
|
196
248
|
return tuple(mmts)
|
|
197
249
|
|
|
250
|
+
@property
|
|
251
|
+
def secrets(self) -> Dict[str, str]:
|
|
252
|
+
"""All (encrypted) secrets for the teamspace.
|
|
253
|
+
|
|
254
|
+
Note:
|
|
255
|
+
Once created, the secret values are encrypted and cannot be viewed here anymore.
|
|
256
|
+
"""
|
|
257
|
+
return self._teamspace_api.get_secrets(self.id)
|
|
258
|
+
|
|
259
|
+
def set_secret(self, key: str, value: str) -> None:
|
|
260
|
+
"""Set the (encrypted) secrets for the teamspace."""
|
|
261
|
+
if not self._teamspace_api.verify_secret_name(key):
|
|
262
|
+
raise ValueError(
|
|
263
|
+
"Secret keys must only contain alphanumeric characters and underscores and not begin with a number."
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
self._teamspace_api.set_secret(self.id, key, value)
|
|
267
|
+
|
|
198
268
|
def list_machines(self, cloud_account: Optional[str] = None) -> List[Machine]:
|
|
199
269
|
if cloud_account is None:
|
|
200
270
|
cloud_account = os.getenv("LIGHTNING_CLUSTER_ID") or self.default_cloud_account
|
|
@@ -478,6 +548,96 @@ class Teamspace:
|
|
|
478
548
|
cloud_account=self.default_cloud_account,
|
|
479
549
|
)
|
|
480
550
|
|
|
551
|
+
def new_folder(
|
|
552
|
+
self, name: str, location: Optional[FolderLocation] = None, cloud_account: Optional[str] = None
|
|
553
|
+
) -> None:
|
|
554
|
+
"""Create a new folder in this Teamspace.
|
|
555
|
+
|
|
556
|
+
Args:
|
|
557
|
+
name: The name of the folder. Folders will be accesible under `/teamspace/folders/<name>`
|
|
558
|
+
location: The location of the folder. Defaults to cloud agnostic.
|
|
559
|
+
cloud_account: The cloud account to create the folder in. Not used for cloud agnostic folders.
|
|
560
|
+
"""
|
|
561
|
+
if cloud_account is None:
|
|
562
|
+
cloud_account = self.default_cloud_account
|
|
563
|
+
|
|
564
|
+
cloud_accounts = self._cloud_account_api.list_cloud_accounts(self.id)
|
|
565
|
+
resolved_cloud_accounts = [
|
|
566
|
+
external_cloud for external_cloud in cloud_accounts if external_cloud.id == cloud_account
|
|
567
|
+
]
|
|
568
|
+
|
|
569
|
+
if len(resolved_cloud_accounts) == 0:
|
|
570
|
+
raise ValueError(f"Cloud account not found: {cloud_account}")
|
|
571
|
+
|
|
572
|
+
resolved_cloud_account = resolved_cloud_accounts[0]
|
|
573
|
+
|
|
574
|
+
# if the cloud account is global, default to agnostic
|
|
575
|
+
if location is None and resolved_cloud_account.spec.cluster_type == V1ClusterType.GLOBAL:
|
|
576
|
+
location = FolderLocation.CLOUD_AGNOSTIC
|
|
577
|
+
|
|
578
|
+
# if it's global, then default to agnostic, and aws / gcp otherwise if set
|
|
579
|
+
if (
|
|
580
|
+
location is not None
|
|
581
|
+
and location != FolderLocation.CLOUD_AGNOSTIC
|
|
582
|
+
and resolved_cloud_account.spec.cluster_type == V1ClusterType.GLOBAL
|
|
583
|
+
):
|
|
584
|
+
providers = self._cloud_account_api.get_cloud_account_provider_mapping(self.id)
|
|
585
|
+
|
|
586
|
+
if location == FolderLocation.AWS:
|
|
587
|
+
resolved_cloud_account = providers[CloudProvider.AWS]
|
|
588
|
+
elif location == FolderLocation.GCP:
|
|
589
|
+
resolved_cloud_account = providers[CloudProvider.GCP]
|
|
590
|
+
|
|
591
|
+
if location == FolderLocation.CLOUD_AGNOSTIC:
|
|
592
|
+
self._teamspace_api.new_folder(self.id, name, None)
|
|
593
|
+
else:
|
|
594
|
+
self._teamspace_api.new_folder(self.id, name, resolved_cloud_account)
|
|
595
|
+
|
|
596
|
+
return
|
|
597
|
+
|
|
598
|
+
def new_connection(
|
|
599
|
+
self,
|
|
600
|
+
name: str,
|
|
601
|
+
source: str,
|
|
602
|
+
connection_type: ConnectionType,
|
|
603
|
+
writable: bool = True,
|
|
604
|
+
cloud_account: Optional[str] = None,
|
|
605
|
+
region: Optional[str] = None,
|
|
606
|
+
) -> None:
|
|
607
|
+
"""Add an existing data source to this Teamspace.
|
|
608
|
+
|
|
609
|
+
Args:
|
|
610
|
+
name: the name under which your data will be available in this Teamspace
|
|
611
|
+
source: the source spec of your data. Format depends on the type of data to connect.
|
|
612
|
+
For EFS, this should be the filsystem id
|
|
613
|
+
connection_type: the kind of data to connect to this Teamspace
|
|
614
|
+
writable: whether to support write-back to this data source. If False, the data is connected as read-only
|
|
615
|
+
cloud_account: which cloud-account to connect to the data source to.
|
|
616
|
+
If not specified, will retrieve the cloud-account that matches the required provider type
|
|
617
|
+
starting with private cloud accounts and falling back to public if necessary.
|
|
618
|
+
region: which provider region this data is in. Required for some connection types only.
|
|
619
|
+
"""
|
|
620
|
+
provider_for_connection = self._cloud_account_api.get_cloud_provider_for_connection_type(connection_type)
|
|
621
|
+
|
|
622
|
+
if connection_type == ConnectionType.EFS and region is None:
|
|
623
|
+
raise ValueError("Region must be specified")
|
|
624
|
+
|
|
625
|
+
cloud_account = self._cloud_account_api.resolve_cloud_account(
|
|
626
|
+
self.id, cloud_account, provider_for_connection, None
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
cloud_accounts = self._cloud_account_api.list_cloud_accounts(self.id)
|
|
630
|
+
resolved_cloud_accounts = [
|
|
631
|
+
external_cloud for external_cloud in cloud_accounts if external_cloud.id == cloud_account
|
|
632
|
+
]
|
|
633
|
+
|
|
634
|
+
if len(resolved_cloud_accounts) == 0:
|
|
635
|
+
raise ValueError(f"Cloud account not found: {cloud_account}")
|
|
636
|
+
|
|
637
|
+
resolved_cloud_account = resolved_cloud_accounts[0]
|
|
638
|
+
|
|
639
|
+
self._teamspace_api.new_connection(self.id, name, source, resolved_cloud_account, writable, region or "")
|
|
640
|
+
|
|
481
641
|
|
|
482
642
|
def _list_files(path: Union[str, Path]) -> Tuple[List[Path], List[str]]:
|
|
483
643
|
"""List all folders in a directory and return them as a list and relative path."""
|
lightning_sdk/user.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Dict, Optional
|
|
2
2
|
|
|
3
3
|
from lightning_sdk.api import UserApi
|
|
4
4
|
from lightning_sdk.owner import Owner
|
|
@@ -37,6 +37,24 @@ class User(Owner):
|
|
|
37
37
|
"""The user's ID."""
|
|
38
38
|
return self._user.id
|
|
39
39
|
|
|
40
|
+
@property
|
|
41
|
+
def secrets(self) -> Dict[str, str]:
|
|
42
|
+
"""All (encrypted) secrets for the user.
|
|
43
|
+
|
|
44
|
+
Note:
|
|
45
|
+
Once created, the secret values are encrypted and cannot be viewed here anymore.
|
|
46
|
+
"""
|
|
47
|
+
return self._user_api.get_secrets()
|
|
48
|
+
|
|
49
|
+
def set_secret(self, key: str, value: str) -> None:
|
|
50
|
+
"""Set a (encrypted) secret for the user."""
|
|
51
|
+
if not self._user_api.verify_secret_name(key):
|
|
52
|
+
raise ValueError(
|
|
53
|
+
"Secret keys must only contain alphanumeric characters and underscores and not begin with a number."
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
self._user_api.set_secret(key, value)
|
|
57
|
+
|
|
40
58
|
def __repr__(self) -> str:
|
|
41
59
|
"""Returns reader friendly representation."""
|
|
42
60
|
return f"User(name={self.name})"
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, Dict, Mapping, Optional, Sequence
|
|
4
|
+
|
|
5
|
+
import yaml
|
|
6
|
+
|
|
7
|
+
_DEFAULT_CONFIG_FILE_PATH = "~/.lightning/config.yaml"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class DefaultConfigKeys:
|
|
12
|
+
"""Default configuration keys for the Lightning SDK."""
|
|
13
|
+
|
|
14
|
+
organization: str = "organization.name"
|
|
15
|
+
user: str = "user.name"
|
|
16
|
+
|
|
17
|
+
teamspace_name: str = "teamspace.name"
|
|
18
|
+
teamspace_owner: str = "teamspace.owner"
|
|
19
|
+
teamspace_owner_type: str = "teamspace.owner_type"
|
|
20
|
+
|
|
21
|
+
machine: str = "machine.name"
|
|
22
|
+
|
|
23
|
+
studio: str = "studio.name"
|
|
24
|
+
|
|
25
|
+
cloud_account: str = "cloud_account.name"
|
|
26
|
+
cloud_provider: str = "cloud_provider.name"
|
|
27
|
+
|
|
28
|
+
license: str = "license"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ConfigProxy:
|
|
32
|
+
def __init__(self, root: "Config", *path: str) -> None:
|
|
33
|
+
self._root = root
|
|
34
|
+
self._path = path # list of keys from root
|
|
35
|
+
|
|
36
|
+
def __getattr__(self, name: str) -> "ConfigProxy":
|
|
37
|
+
"""Returns a reference to a nested ConfigProxy object a level deeper in the config hierarchy.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
name: the name of the attribute to access, which corresponds to a key in the config.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
ConfigProxy: the next ConfigProxy object for the attribute.
|
|
44
|
+
"""
|
|
45
|
+
# Build a deeper path and return a new proxy
|
|
46
|
+
return ConfigProxy(self._root, *self._path, name)
|
|
47
|
+
|
|
48
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
49
|
+
"""Sets the name attribute to value at the current hierarchy level.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
name: the attribute name to set, which corresponds to a key in the config.
|
|
53
|
+
value: the value to set for the given attribute name in the config.
|
|
54
|
+
"""
|
|
55
|
+
if name in ("_root", "_path"): # internal attributes
|
|
56
|
+
super().__setattr__(name, value)
|
|
57
|
+
else:
|
|
58
|
+
# Assign a nested value in the root config
|
|
59
|
+
self._root._set_nested([*self._path, name], value)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class Config:
|
|
63
|
+
def __init__(self, config_file: Optional[str] = None) -> None:
|
|
64
|
+
"""Config class to manage configuration settings for the lightning SDK and CLI.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
config_file: the file path where the configuration is stored.
|
|
68
|
+
If None, defaults to "~/.lightning/config.yaml".
|
|
69
|
+
"""
|
|
70
|
+
if config_file is None:
|
|
71
|
+
config_file = _DEFAULT_CONFIG_FILE_PATH
|
|
72
|
+
self._config_file = os.path.expanduser(config_file)
|
|
73
|
+
|
|
74
|
+
def _load_config(self) -> Dict[str, Any]:
|
|
75
|
+
if not os.path.exists(self._config_file):
|
|
76
|
+
return {} # Return empty dict if config doesn't exist
|
|
77
|
+
with open(self._config_file) as f:
|
|
78
|
+
return yaml.safe_load(f) or {}
|
|
79
|
+
|
|
80
|
+
def _save_config(self, config: Dict[str, Any]) -> None:
|
|
81
|
+
os.makedirs(os.path.dirname(self._config_file), exist_ok=True)
|
|
82
|
+
config = _unflatten_dict(config)
|
|
83
|
+
with open(self._config_file, "w") as f:
|
|
84
|
+
yaml.safe_dump(config, f, default_flow_style=False, sort_keys=True)
|
|
85
|
+
|
|
86
|
+
def _set_nested(self, keys: Sequence[str], value: str) -> None:
|
|
87
|
+
config = self._load_config()
|
|
88
|
+
curr = config
|
|
89
|
+
for k in keys[:-1]:
|
|
90
|
+
if k not in curr or not isinstance(curr[k], Dict):
|
|
91
|
+
curr[k] = {}
|
|
92
|
+
curr = curr[k]
|
|
93
|
+
curr[keys[-1]] = value
|
|
94
|
+
self._save_config(config)
|
|
95
|
+
|
|
96
|
+
def get_value(self, key_path: str) -> Optional[str]:
|
|
97
|
+
"""Gets a value from the config using dot notation.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
key_path: the dot-separated path to the config value (e.g. "teamspace.name")
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
The config value if found, None otherwise
|
|
104
|
+
"""
|
|
105
|
+
return self._get_value_type(key_path, str)
|
|
106
|
+
|
|
107
|
+
def get_sub_config(self, key_path: str) -> Optional[Mapping[str, Any]]:
|
|
108
|
+
"""Gets a subconfig from the config using dot notation.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
key_path: the dot-separated path to the subconfig (e.g. "license")
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
The subconfig if found, None otherwise
|
|
115
|
+
"""
|
|
116
|
+
return self._get_value_type(key_path, Mapping)
|
|
117
|
+
|
|
118
|
+
def _get_value_type(self, key_path: str, subtype: type) -> Optional[Any]:
|
|
119
|
+
config = self._load_config()
|
|
120
|
+
if not isinstance(config, Mapping):
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
keys = key_path.split(".")
|
|
124
|
+
curr = config
|
|
125
|
+
for k in keys:
|
|
126
|
+
if not isinstance(curr, dict) or k not in curr:
|
|
127
|
+
return None
|
|
128
|
+
curr = curr[k]
|
|
129
|
+
return curr if isinstance(curr, subtype) else None
|
|
130
|
+
|
|
131
|
+
def __getattr__(self, name: str) -> ConfigProxy:
|
|
132
|
+
"""Returns a proxy to the actual values to allow for nested access.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
name: the name of the value to retrieve.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
ConfigProxy: a proxy object that allows nested access to the configuration.
|
|
139
|
+
"""
|
|
140
|
+
return ConfigProxy(self, name)
|
|
141
|
+
|
|
142
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
143
|
+
"""Sets the name attribute to value at the root level."""
|
|
144
|
+
if name in ("_config_file",): # internal attributes
|
|
145
|
+
super().__setattr__(name, value)
|
|
146
|
+
else:
|
|
147
|
+
# Assign a value at the root level
|
|
148
|
+
self._set_nested([name], value)
|
|
149
|
+
|
|
150
|
+
def __repr__(self) -> str:
|
|
151
|
+
"""Returns a string representation of the config."""
|
|
152
|
+
return str(self)
|
|
153
|
+
|
|
154
|
+
def __str__(self) -> str:
|
|
155
|
+
"""Returns a string representation of the config."""
|
|
156
|
+
return yaml.dump(
|
|
157
|
+
{"Config": {"config_file": self._config_file, **self._load_config()}},
|
|
158
|
+
indent=4,
|
|
159
|
+
sort_keys=True,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def get(self, key: str) -> Optional[str]:
|
|
163
|
+
return self.get_value(key)
|
|
164
|
+
|
|
165
|
+
def set(self, key: str, value: str) -> None:
|
|
166
|
+
self._set_nested([key], value)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _unflatten_dict(flat_dict: Dict[str, Any]) -> Dict[str, Any]:
|
|
170
|
+
unflattened_dict = {}
|
|
171
|
+
for key, value in flat_dict.items():
|
|
172
|
+
keys = key.split(".")
|
|
173
|
+
curr = unflattened_dict
|
|
174
|
+
for k in keys[:-1]:
|
|
175
|
+
if k not in curr:
|
|
176
|
+
curr[k] = {}
|
|
177
|
+
curr = curr[k]
|
|
178
|
+
curr[keys[-1]] = value
|
|
179
|
+
return unflattened_dict
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from functools import lru_cache
|
|
2
|
+
|
|
3
|
+
from lightning_sdk.api.license_api import LicenseApi
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class License:
|
|
7
|
+
def __init__(self, license_key: str, product_name: str) -> None:
|
|
8
|
+
self.license_key = license_key
|
|
9
|
+
self.product_name = product_name
|
|
10
|
+
|
|
11
|
+
@lru_cache(maxsize=1) # noqa: B019
|
|
12
|
+
def validate(self) -> bool:
|
|
13
|
+
return LicenseApi(self.license_key).validate_license(self.license_key, self.product_name)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import inspect
|
|
3
|
+
import time
|
|
4
|
+
import traceback
|
|
5
|
+
from abc import ABCMeta
|
|
6
|
+
from contextlib import suppress
|
|
7
|
+
from typing import Callable, Dict, Tuple
|
|
8
|
+
|
|
9
|
+
from lightning_sdk.__version__ import __version__
|
|
10
|
+
from lightning_sdk.lightning_cloud.openapi import V1CreateSDKCommandHistoryRequest, V1SDKCommandHistorySeverity
|
|
11
|
+
from lightning_sdk.lightning_cloud.openapi.models.v1_sdk_command_history_type import V1SDKCommandHistoryType
|
|
12
|
+
from lightning_sdk.lightning_cloud.rest_client import LightningClient
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def track_calls() -> Callable[..., any]:
|
|
16
|
+
def decorator(func: Callable[..., any]) -> Callable[..., any]:
|
|
17
|
+
@functools.wraps(func)
|
|
18
|
+
def wrapper(*args: Tuple[any, ...], **kwargs: Dict[str, any]) -> any:
|
|
19
|
+
start_time = time.time()
|
|
20
|
+
sig = inspect.signature(func)
|
|
21
|
+
bound_args = sig.bind(*args, **kwargs)
|
|
22
|
+
bound_args.apply_defaults()
|
|
23
|
+
|
|
24
|
+
args_str = ", ".join(f"{k}: {v}" for k, v in bound_args.arguments.items() if k != "self")
|
|
25
|
+
message = f"VERSION: {__version__} | ARGS: {args_str} "
|
|
26
|
+
|
|
27
|
+
body = V1CreateSDKCommandHistoryRequest(
|
|
28
|
+
command=func.__qualname__,
|
|
29
|
+
message=message,
|
|
30
|
+
project_id=None,
|
|
31
|
+
severity=V1SDKCommandHistorySeverity.INFO,
|
|
32
|
+
type=V1SDKCommandHistoryType.SDK,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
return func(*args, **kwargs)
|
|
37
|
+
|
|
38
|
+
except Exception as e:
|
|
39
|
+
body.severity = V1SDKCommandHistorySeverity.ERROR
|
|
40
|
+
body.message += f" | Error: {type(e).__name__}: {e!s} | Traceback: {traceback.format_exc(limit=3)}"
|
|
41
|
+
body.duration = int(time.time() - start_time)
|
|
42
|
+
with suppress(Exception):
|
|
43
|
+
client = LightningClient(retry=False, max_tries=0)
|
|
44
|
+
client.s_dk_command_history_service_create_sdk_command_history(body=body)
|
|
45
|
+
raise
|
|
46
|
+
|
|
47
|
+
return wrapper
|
|
48
|
+
|
|
49
|
+
return decorator
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TrackCallsMeta(type):
|
|
53
|
+
def __new__(cls, name: any, bases: any, attrs: any) -> type.__new__:
|
|
54
|
+
for attr_name, attr_value in attrs.items():
|
|
55
|
+
if attr_name.startswith("__") and attr_name not in ("__init__", "__call__"):
|
|
56
|
+
attrs[attr_name] = attr_value
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
# Noisy
|
|
60
|
+
if attr_name in ("_cls_name"):
|
|
61
|
+
attrs[attr_name] = attr_value
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
if callable(attr_value):
|
|
65
|
+
attrs[attr_name] = track_calls()(attr_value)
|
|
66
|
+
|
|
67
|
+
elif isinstance(attr_value, property):
|
|
68
|
+
fget = track_calls()(attr_value.fget) if attr_value.fget else None
|
|
69
|
+
fset = track_calls()(attr_value.fset) if attr_value.fset else None
|
|
70
|
+
fdel = track_calls()(attr_value.fdel) if attr_value.fdel else None
|
|
71
|
+
attrs[attr_name] = property(fget, fset, fdel)
|
|
72
|
+
|
|
73
|
+
else:
|
|
74
|
+
attrs[attr_name] = attr_value
|
|
75
|
+
return super().__new__(cls, name, bases, attrs)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TrackCallsABCMeta(ABCMeta, TrackCallsMeta):
|
|
79
|
+
"""Combined metaclass for classes that need both ABC and TrackCalls functionality."""
|