lightning-sdk 2025.9.23__py3-none-any.whl → 2025.9.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/cli/entrypoint.py +3 -1
  3. lightning_sdk/cli/groups.py +8 -1
  4. lightning_sdk/cli/legacy/entrypoint.py +1 -1
  5. lightning_sdk/cli/studio/create.py +19 -5
  6. lightning_sdk/cli/studio/delete.py +9 -5
  7. lightning_sdk/cli/studio/list.py +5 -1
  8. lightning_sdk/cli/studio/ssh.py +9 -3
  9. lightning_sdk/cli/studio/start.py +26 -3
  10. lightning_sdk/cli/studio/stop.py +7 -3
  11. lightning_sdk/cli/studio/switch.py +21 -5
  12. lightning_sdk/cli/utils/studio_selection.py +22 -15
  13. lightning_sdk/cli/vm/__init__.py +20 -0
  14. lightning_sdk/cli/vm/create.py +33 -0
  15. lightning_sdk/cli/vm/delete.py +25 -0
  16. lightning_sdk/cli/vm/list.py +30 -0
  17. lightning_sdk/cli/vm/ssh.py +31 -0
  18. lightning_sdk/cli/vm/start.py +60 -0
  19. lightning_sdk/cli/vm/stop.py +25 -0
  20. lightning_sdk/cli/vm/switch.py +38 -0
  21. lightning_sdk/lightning_cloud/openapi/__init__.py +20 -1
  22. lightning_sdk/lightning_cloud/openapi/api/assistants_service_api.py +2 -95
  23. lightning_sdk/lightning_cloud/openapi/api/billing_service_api.py +24 -8
  24. lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +420 -0
  25. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +121 -0
  26. lightning_sdk/lightning_cloud/openapi/api/storage_service_api.py +655 -0
  27. lightning_sdk/lightning_cloud/openapi/models/__init__.py +20 -1
  28. lightning_sdk/lightning_cloud/openapi/models/create_machine_request_represents_the_request_to_create_a_machine.py +435 -0
  29. lightning_sdk/lightning_cloud/openapi/models/job_id_reportroutingtelemetry_body.py +123 -0
  30. lightning_sdk/lightning_cloud/openapi/models/project_id_storagetransfers_body.py +149 -0
  31. lightning_sdk/lightning_cloud/openapi/models/user_id_affiliatelinks_body.py +107 -3
  32. lightning_sdk/lightning_cloud/openapi/models/v1_abort_storage_transfer_response.py +97 -0
  33. lightning_sdk/lightning_cloud/openapi/models/v1_assistant_session_daily_aggregated.py +27 -1
  34. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_provider.py +2 -0
  35. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_accelerator.py +27 -1
  36. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +53 -1
  37. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_type.py +1 -0
  38. lightning_sdk/lightning_cloud/openapi/models/v1_create_machine_response.py +123 -0
  39. lightning_sdk/lightning_cloud/openapi/models/v1_create_project_request.py +27 -1
  40. lightning_sdk/lightning_cloud/openapi/models/v1_delete_machine_response.py +97 -0
  41. lightning_sdk/lightning_cloud/openapi/models/v1_external_cluster_spec.py +27 -1
  42. lightning_sdk/lightning_cloud/openapi/models/v1_get_machine_response.py +123 -0
  43. lightning_sdk/lightning_cloud/openapi/models/v1_get_user_response.py +27 -1
  44. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_v1.py +27 -1
  45. lightning_sdk/lightning_cloud/openapi/models/v1_lightning_elastic_cluster_v1.py +97 -0
  46. lightning_sdk/lightning_cloud/openapi/models/{v1_get_model_total_usage_metrics_response.py → v1_list_machines_response.py} +37 -37
  47. lightning_sdk/lightning_cloud/openapi/models/v1_list_storage_transfers_response.py +123 -0
  48. lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +539 -0
  49. lightning_sdk/lightning_cloud/openapi/models/v1_machine_direct_v1.py +123 -0
  50. lightning_sdk/lightning_cloud/openapi/models/v1_pause_storage_transfer_response.py +97 -0
  51. lightning_sdk/lightning_cloud/openapi/models/v1_purchase_annual_upsell_request.py +123 -0
  52. lightning_sdk/lightning_cloud/openapi/models/v1_report_deployment_routing_telemetry_response.py +97 -0
  53. lightning_sdk/lightning_cloud/openapi/models/v1_resume_storage_transfer_response.py +97 -0
  54. lightning_sdk/lightning_cloud/openapi/models/v1_routing_telemetry.py +79 -1
  55. lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
  56. lightning_sdk/lightning_cloud/openapi/models/v1_slack_notifier.py +149 -0
  57. lightning_sdk/lightning_cloud/openapi/models/v1_slack_notifier_type.py +105 -0
  58. lightning_sdk/lightning_cloud/openapi/models/v1_storage_transfer.py +435 -0
  59. lightning_sdk/lightning_cloud/openapi/models/v1_storage_transfer_status.py +108 -0
  60. lightning_sdk/lightning_cloud/openapi/models/v1_update_user_request.py +27 -1
  61. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +105 -79
  62. lightning_sdk/studio.py +55 -11
  63. lightning_sdk/teamspace.py +11 -2
  64. {lightning_sdk-2025.9.23.dist-info → lightning_sdk-2025.9.29.dist-info}/METADATA +1 -1
  65. {lightning_sdk-2025.9.23.dist-info → lightning_sdk-2025.9.29.dist-info}/RECORD +69 -42
  66. {lightning_sdk-2025.9.23.dist-info → lightning_sdk-2025.9.29.dist-info}/LICENSE +0 -0
  67. {lightning_sdk-2025.9.23.dist-info → lightning_sdk-2025.9.29.dist-info}/WHEEL +0 -0
  68. {lightning_sdk-2025.9.23.dist-info → lightning_sdk-2025.9.29.dist-info}/entry_points.txt +0 -0
  69. {lightning_sdk-2025.9.23.dist-info → lightning_sdk-2025.9.29.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,108 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ external/v1/auth_service.proto
5
+
6
+ No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501
7
+
8
+ OpenAPI spec version: version not set
9
+
10
+ Generated by: https://github.com/swagger-api/swagger-codegen.git
11
+
12
+ NOTE
13
+ ----
14
+ standard swagger-codegen-cli for this python client has been modified
15
+ by custom templates. The purpose of these templates is to include
16
+ typing information in the API and Model code. Please refer to the
17
+ main grid repository for more info
18
+ """
19
+
20
+ import pprint
21
+ import re # noqa: F401
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ import six
26
+
27
+ if TYPE_CHECKING:
28
+ from datetime import datetime
29
+ from lightning_sdk.lightning_cloud.openapi.models import *
30
+
31
+ class V1StorageTransferStatus(object):
32
+ """NOTE: This class is auto generated by the swagger code generator program.
33
+
34
+ Do not edit the class manually.
35
+ """
36
+
37
+ """
38
+ allowed enum values
39
+ """
40
+ QUEUED = "STATUS_QUEUED"
41
+ IN_PROGRESS = "STATUS_IN_PROGRESS"
42
+ FAILED = "STATUS_FAILED"
43
+ ABORTED = "STATUS_ABORTED"
44
+ PAUSED = "STATUS_PAUSED"
45
+ COMPLETED = "STATUS_COMPLETED"
46
+ UNSPECIFIED = "STATUS_UNSPECIFIED"
47
+ """
48
+ Attributes:
49
+ swagger_types (dict): The key is attribute name
50
+ and the value is attribute type.
51
+ attribute_map (dict): The key is attribute name
52
+ and the value is json key in definition.
53
+ """
54
+ swagger_types = {
55
+ }
56
+
57
+ attribute_map = {
58
+ }
59
+
60
+ def __init__(self): # noqa: E501
61
+ """V1StorageTransferStatus - a model defined in Swagger""" # noqa: E501
62
+ self.discriminator = None
63
+
64
+ def to_dict(self) -> dict:
65
+ """Returns the model properties as a dict"""
66
+ result = {}
67
+
68
+ for attr, _ in six.iteritems(self.swagger_types):
69
+ value = getattr(self, attr)
70
+ if isinstance(value, list):
71
+ result[attr] = list(map(
72
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
73
+ value
74
+ ))
75
+ elif hasattr(value, "to_dict"):
76
+ result[attr] = value.to_dict()
77
+ elif isinstance(value, dict):
78
+ result[attr] = dict(map(
79
+ lambda item: (item[0], item[1].to_dict())
80
+ if hasattr(item[1], "to_dict") else item,
81
+ value.items()
82
+ ))
83
+ else:
84
+ result[attr] = value
85
+ if issubclass(V1StorageTransferStatus, dict):
86
+ for key, value in self.items():
87
+ result[key] = value
88
+
89
+ return result
90
+
91
+ def to_str(self) -> str:
92
+ """Returns the string representation of the model"""
93
+ return pprint.pformat(self.to_dict())
94
+
95
+ def __repr__(self) -> str:
96
+ """For `print` and `pprint`"""
97
+ return self.to_str()
98
+
99
+ def __eq__(self, other: 'V1StorageTransferStatus') -> bool:
100
+ """Returns true if both objects are equal"""
101
+ if not isinstance(other, V1StorageTransferStatus):
102
+ return False
103
+
104
+ return self.__dict__ == other.__dict__
105
+
106
+ def __ne__(self, other: 'V1StorageTransferStatus') -> bool:
107
+ """Returns true if both objects are not equal"""
108
+ return not self == other
@@ -53,6 +53,7 @@ class V1UpdateUserRequest(object):
53
53
  'first_name': 'str',
54
54
  'general_audience_mode': 'bool',
55
55
  'last_name': 'str',
56
+ 'linux_username': 'str',
56
57
  'non_developer_mode': 'bool',
57
58
  'opted_in_marketing_emails': 'bool',
58
59
  'organization': 'str',
@@ -82,6 +83,7 @@ class V1UpdateUserRequest(object):
82
83
  'first_name': 'firstName',
83
84
  'general_audience_mode': 'generalAudienceMode',
84
85
  'last_name': 'lastName',
86
+ 'linux_username': 'linuxUsername',
85
87
  'non_developer_mode': 'nonDeveloperMode',
86
88
  'opted_in_marketing_emails': 'optedInMarketingEmails',
87
89
  'organization': 'organization',
@@ -98,7 +100,7 @@ class V1UpdateUserRequest(object):
98
100
  'website': 'website'
99
101
  }
100
102
 
101
- def __init__(self, agree_to_terms_and_conditions: 'bool' =None, allow_credits_auto_replenish: 'bool' =None, auto_replenish_amount: 'float' =None, auto_replenish_threshold: 'float' =None, complete_sign_up: 'bool' =None, completed_project_onboarding: 'bool' =None, country: 'str' =None, email: 'str' =None, experimentation_id: 'str' =None, first_name: 'str' =None, general_audience_mode: 'bool' =None, last_name: 'str' =None, non_developer_mode: 'bool' =None, opted_in_marketing_emails: 'bool' =None, organization: 'str' =None, preferred_color_scheme: 'str' =None, preferred_ide: 'str' =None, preferred_shell: 'str' =None, preferred_vscode_marketplace: 'str' =None, role: 'str' =None, saw_create_first_project_dialog: 'bool' =None, saw_forums_login_merge_dialog: 'bool' =None, saw_free_credits_notification: 'bool' =None, user_metadata: 'str' =None, username: 'str' =None, website: 'str' =None): # noqa: E501
103
+ def __init__(self, agree_to_terms_and_conditions: 'bool' =None, allow_credits_auto_replenish: 'bool' =None, auto_replenish_amount: 'float' =None, auto_replenish_threshold: 'float' =None, complete_sign_up: 'bool' =None, completed_project_onboarding: 'bool' =None, country: 'str' =None, email: 'str' =None, experimentation_id: 'str' =None, first_name: 'str' =None, general_audience_mode: 'bool' =None, last_name: 'str' =None, linux_username: 'str' =None, non_developer_mode: 'bool' =None, opted_in_marketing_emails: 'bool' =None, organization: 'str' =None, preferred_color_scheme: 'str' =None, preferred_ide: 'str' =None, preferred_shell: 'str' =None, preferred_vscode_marketplace: 'str' =None, role: 'str' =None, saw_create_first_project_dialog: 'bool' =None, saw_forums_login_merge_dialog: 'bool' =None, saw_free_credits_notification: 'bool' =None, user_metadata: 'str' =None, username: 'str' =None, website: 'str' =None): # noqa: E501
102
104
  """V1UpdateUserRequest - a model defined in Swagger""" # noqa: E501
103
105
  self._agree_to_terms_and_conditions = None
104
106
  self._allow_credits_auto_replenish = None
@@ -112,6 +114,7 @@ class V1UpdateUserRequest(object):
112
114
  self._first_name = None
113
115
  self._general_audience_mode = None
114
116
  self._last_name = None
117
+ self._linux_username = None
115
118
  self._non_developer_mode = None
116
119
  self._opted_in_marketing_emails = None
117
120
  self._organization = None
@@ -151,6 +154,8 @@ class V1UpdateUserRequest(object):
151
154
  self.general_audience_mode = general_audience_mode
152
155
  if last_name is not None:
153
156
  self.last_name = last_name
157
+ if linux_username is not None:
158
+ self.linux_username = linux_username
154
159
  if non_developer_mode is not None:
155
160
  self.non_developer_mode = non_developer_mode
156
161
  if opted_in_marketing_emails is not None:
@@ -432,6 +437,27 @@ class V1UpdateUserRequest(object):
432
437
 
433
438
  self._last_name = last_name
434
439
 
440
+ @property
441
+ def linux_username(self) -> 'str':
442
+ """Gets the linux_username of this V1UpdateUserRequest. # noqa: E501
443
+
444
+
445
+ :return: The linux_username of this V1UpdateUserRequest. # noqa: E501
446
+ :rtype: str
447
+ """
448
+ return self._linux_username
449
+
450
+ @linux_username.setter
451
+ def linux_username(self, linux_username: 'str'):
452
+ """Sets the linux_username of this V1UpdateUserRequest.
453
+
454
+
455
+ :param linux_username: The linux_username of this V1UpdateUserRequest. # noqa: E501
456
+ :type: str
457
+ """
458
+
459
+ self._linux_username = linux_username
460
+
435
461
  @property
436
462
  def non_developer_mode(self) -> 'bool':
437
463
  """Gets the non_developer_mode of this V1UpdateUserRequest. # noqa: E501
@@ -67,7 +67,6 @@ class V1UserFeatures(object):
67
67
  'f227': 'bool',
68
68
  'f234': 'bool',
69
69
  'f236': 'bool',
70
- 'f237': 'bool',
71
70
  'f239': 'bool',
72
71
  'f240': 'bool',
73
72
  'f241': 'bool',
@@ -75,14 +74,16 @@ class V1UserFeatures(object):
75
74
  'f245': 'bool',
76
75
  'f247': 'bool',
77
76
  'f248': 'bool',
78
- 'f249': 'bool',
79
77
  'f250': 'bool',
80
78
  'f251': 'bool',
81
79
  'f252': 'bool',
82
80
  'f253': 'bool',
81
+ 'f254': 'bool',
82
+ 'f255': 'bool',
83
+ 'f257': 'bool',
84
+ 'f258': 'bool',
83
85
  'fair_share': 'bool',
84
86
  'featured_studios_admin': 'bool',
85
- 'gcp_overprovisioning': 'bool',
86
87
  'gcs_connections_optimized': 'bool',
87
88
  'instant_capacity_reservation': 'bool',
88
89
  'job_artifacts_v2': 'bool',
@@ -155,7 +156,6 @@ class V1UserFeatures(object):
155
156
  'f227': 'f227',
156
157
  'f234': 'f234',
157
158
  'f236': 'f236',
158
- 'f237': 'f237',
159
159
  'f239': 'f239',
160
160
  'f240': 'f240',
161
161
  'f241': 'f241',
@@ -163,14 +163,16 @@ class V1UserFeatures(object):
163
163
  'f245': 'f245',
164
164
  'f247': 'f247',
165
165
  'f248': 'f248',
166
- 'f249': 'f249',
167
166
  'f250': 'f250',
168
167
  'f251': 'f251',
169
168
  'f252': 'f252',
170
169
  'f253': 'f253',
170
+ 'f254': 'f254',
171
+ 'f255': 'f255',
172
+ 'f257': 'f257',
173
+ 'f258': 'f258',
171
174
  'fair_share': 'fairShare',
172
175
  'featured_studios_admin': 'featuredStudiosAdmin',
173
- 'gcp_overprovisioning': 'gcpOverprovisioning',
174
176
  'gcs_connections_optimized': 'gcsConnectionsOptimized',
175
177
  'instant_capacity_reservation': 'instantCapacityReservation',
176
178
  'job_artifacts_v2': 'jobArtifactsV2',
@@ -216,7 +218,7 @@ class V1UserFeatures(object):
216
218
  'writable_s3_connections': 'writableS3Connections'
217
219
  }
218
220
 
219
- def __init__(self, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, byo_machine_type: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloudspace_schedules: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, control_center_monitoring: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_persistent_disk: 'bool' =None, drive_v2: 'bool' =None, enterprise_compute_admin: 'bool' =None, f227: 'bool' =None, f234: 'bool' =None, f236: 'bool' =None, f237: 'bool' =None, f239: 'bool' =None, f240: 'bool' =None, f241: 'bool' =None, f243: 'bool' =None, f245: 'bool' =None, f247: 'bool' =None, f248: 'bool' =None, f249: 'bool' =None, f250: 'bool' =None, f251: 'bool' =None, f252: 'bool' =None, f253: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, gcp_overprovisioning: 'bool' =None, gcs_connections_optimized: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, kubernetes_cluster_ui: 'bool' =None, kubernetes_clusters: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, model_api_dashboard: 'bool' =None, multiple_studio_versions: 'bool' =None, nerf_fs_nonpaying: 'bool' =None, org_level_member_permissions: 'bool' =None, org_usage_limits: 'bool' =None, persistent_disk: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_sweeps: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, product_license: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, reserved_machines_tab: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, single_wallet: 'bool' =None, slurm: 'bool' =None, specialised_studios: 'bool' =None, storage_overuse_deletion: 'bool' =None, studio_config: 'bool' =None, studio_sharing_v2: 'bool' =None, studio_version_visibility: 'bool' =None, trainium2: 'bool' =None, vultr: 'bool' =None, weka: 'bool' =None, writable_s3_connections: 'bool' =None): # noqa: E501
221
+ def __init__(self, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, byo_machine_type: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloudspace_schedules: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, control_center_monitoring: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_persistent_disk: 'bool' =None, drive_v2: 'bool' =None, enterprise_compute_admin: 'bool' =None, f227: 'bool' =None, f234: 'bool' =None, f236: 'bool' =None, f239: 'bool' =None, f240: 'bool' =None, f241: 'bool' =None, f243: 'bool' =None, f245: 'bool' =None, f247: 'bool' =None, f248: 'bool' =None, f250: 'bool' =None, f251: 'bool' =None, f252: 'bool' =None, f253: 'bool' =None, f254: 'bool' =None, f255: 'bool' =None, f257: 'bool' =None, f258: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, gcs_connections_optimized: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, kubernetes_cluster_ui: 'bool' =None, kubernetes_clusters: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, model_api_dashboard: 'bool' =None, multiple_studio_versions: 'bool' =None, nerf_fs_nonpaying: 'bool' =None, org_level_member_permissions: 'bool' =None, org_usage_limits: 'bool' =None, persistent_disk: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_sweeps: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, product_license: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, reserved_machines_tab: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, single_wallet: 'bool' =None, slurm: 'bool' =None, specialised_studios: 'bool' =None, storage_overuse_deletion: 'bool' =None, studio_config: 'bool' =None, studio_sharing_v2: 'bool' =None, studio_version_visibility: 'bool' =None, trainium2: 'bool' =None, vultr: 'bool' =None, weka: 'bool' =None, writable_s3_connections: 'bool' =None): # noqa: E501
220
222
  """V1UserFeatures - a model defined in Swagger""" # noqa: E501
221
223
  self._affiliate_links = None
222
224
  self._agents_v2 = None
@@ -244,7 +246,6 @@ class V1UserFeatures(object):
244
246
  self._f227 = None
245
247
  self._f234 = None
246
248
  self._f236 = None
247
- self._f237 = None
248
249
  self._f239 = None
249
250
  self._f240 = None
250
251
  self._f241 = None
@@ -252,14 +253,16 @@ class V1UserFeatures(object):
252
253
  self._f245 = None
253
254
  self._f247 = None
254
255
  self._f248 = None
255
- self._f249 = None
256
256
  self._f250 = None
257
257
  self._f251 = None
258
258
  self._f252 = None
259
259
  self._f253 = None
260
+ self._f254 = None
261
+ self._f255 = None
262
+ self._f257 = None
263
+ self._f258 = None
260
264
  self._fair_share = None
261
265
  self._featured_studios_admin = None
262
- self._gcp_overprovisioning = None
263
266
  self._gcs_connections_optimized = None
264
267
  self._instant_capacity_reservation = None
265
268
  self._job_artifacts_v2 = None
@@ -356,8 +359,6 @@ class V1UserFeatures(object):
356
359
  self.f234 = f234
357
360
  if f236 is not None:
358
361
  self.f236 = f236
359
- if f237 is not None:
360
- self.f237 = f237
361
362
  if f239 is not None:
362
363
  self.f239 = f239
363
364
  if f240 is not None:
@@ -372,8 +373,6 @@ class V1UserFeatures(object):
372
373
  self.f247 = f247
373
374
  if f248 is not None:
374
375
  self.f248 = f248
375
- if f249 is not None:
376
- self.f249 = f249
377
376
  if f250 is not None:
378
377
  self.f250 = f250
379
378
  if f251 is not None:
@@ -382,12 +381,18 @@ class V1UserFeatures(object):
382
381
  self.f252 = f252
383
382
  if f253 is not None:
384
383
  self.f253 = f253
384
+ if f254 is not None:
385
+ self.f254 = f254
386
+ if f255 is not None:
387
+ self.f255 = f255
388
+ if f257 is not None:
389
+ self.f257 = f257
390
+ if f258 is not None:
391
+ self.f258 = f258
385
392
  if fair_share is not None:
386
393
  self.fair_share = fair_share
387
394
  if featured_studios_admin is not None:
388
395
  self.featured_studios_admin = featured_studios_admin
389
- if gcp_overprovisioning is not None:
390
- self.gcp_overprovisioning = gcp_overprovisioning
391
396
  if gcs_connections_optimized is not None:
392
397
  self.gcs_connections_optimized = gcs_connections_optimized
393
398
  if instant_capacity_reservation is not None:
@@ -1021,27 +1026,6 @@ class V1UserFeatures(object):
1021
1026
 
1022
1027
  self._f236 = f236
1023
1028
 
1024
- @property
1025
- def f237(self) -> 'bool':
1026
- """Gets the f237 of this V1UserFeatures. # noqa: E501
1027
-
1028
-
1029
- :return: The f237 of this V1UserFeatures. # noqa: E501
1030
- :rtype: bool
1031
- """
1032
- return self._f237
1033
-
1034
- @f237.setter
1035
- def f237(self, f237: 'bool'):
1036
- """Sets the f237 of this V1UserFeatures.
1037
-
1038
-
1039
- :param f237: The f237 of this V1UserFeatures. # noqa: E501
1040
- :type: bool
1041
- """
1042
-
1043
- self._f237 = f237
1044
-
1045
1029
  @property
1046
1030
  def f239(self) -> 'bool':
1047
1031
  """Gets the f239 of this V1UserFeatures. # noqa: E501
@@ -1189,27 +1173,6 @@ class V1UserFeatures(object):
1189
1173
 
1190
1174
  self._f248 = f248
1191
1175
 
1192
- @property
1193
- def f249(self) -> 'bool':
1194
- """Gets the f249 of this V1UserFeatures. # noqa: E501
1195
-
1196
-
1197
- :return: The f249 of this V1UserFeatures. # noqa: E501
1198
- :rtype: bool
1199
- """
1200
- return self._f249
1201
-
1202
- @f249.setter
1203
- def f249(self, f249: 'bool'):
1204
- """Sets the f249 of this V1UserFeatures.
1205
-
1206
-
1207
- :param f249: The f249 of this V1UserFeatures. # noqa: E501
1208
- :type: bool
1209
- """
1210
-
1211
- self._f249 = f249
1212
-
1213
1176
  @property
1214
1177
  def f250(self) -> 'bool':
1215
1178
  """Gets the f250 of this V1UserFeatures. # noqa: E501
@@ -1294,6 +1257,90 @@ class V1UserFeatures(object):
1294
1257
 
1295
1258
  self._f253 = f253
1296
1259
 
1260
+ @property
1261
+ def f254(self) -> 'bool':
1262
+ """Gets the f254 of this V1UserFeatures. # noqa: E501
1263
+
1264
+
1265
+ :return: The f254 of this V1UserFeatures. # noqa: E501
1266
+ :rtype: bool
1267
+ """
1268
+ return self._f254
1269
+
1270
+ @f254.setter
1271
+ def f254(self, f254: 'bool'):
1272
+ """Sets the f254 of this V1UserFeatures.
1273
+
1274
+
1275
+ :param f254: The f254 of this V1UserFeatures. # noqa: E501
1276
+ :type: bool
1277
+ """
1278
+
1279
+ self._f254 = f254
1280
+
1281
+ @property
1282
+ def f255(self) -> 'bool':
1283
+ """Gets the f255 of this V1UserFeatures. # noqa: E501
1284
+
1285
+
1286
+ :return: The f255 of this V1UserFeatures. # noqa: E501
1287
+ :rtype: bool
1288
+ """
1289
+ return self._f255
1290
+
1291
+ @f255.setter
1292
+ def f255(self, f255: 'bool'):
1293
+ """Sets the f255 of this V1UserFeatures.
1294
+
1295
+
1296
+ :param f255: The f255 of this V1UserFeatures. # noqa: E501
1297
+ :type: bool
1298
+ """
1299
+
1300
+ self._f255 = f255
1301
+
1302
+ @property
1303
+ def f257(self) -> 'bool':
1304
+ """Gets the f257 of this V1UserFeatures. # noqa: E501
1305
+
1306
+
1307
+ :return: The f257 of this V1UserFeatures. # noqa: E501
1308
+ :rtype: bool
1309
+ """
1310
+ return self._f257
1311
+
1312
+ @f257.setter
1313
+ def f257(self, f257: 'bool'):
1314
+ """Sets the f257 of this V1UserFeatures.
1315
+
1316
+
1317
+ :param f257: The f257 of this V1UserFeatures. # noqa: E501
1318
+ :type: bool
1319
+ """
1320
+
1321
+ self._f257 = f257
1322
+
1323
+ @property
1324
+ def f258(self) -> 'bool':
1325
+ """Gets the f258 of this V1UserFeatures. # noqa: E501
1326
+
1327
+
1328
+ :return: The f258 of this V1UserFeatures. # noqa: E501
1329
+ :rtype: bool
1330
+ """
1331
+ return self._f258
1332
+
1333
+ @f258.setter
1334
+ def f258(self, f258: 'bool'):
1335
+ """Sets the f258 of this V1UserFeatures.
1336
+
1337
+
1338
+ :param f258: The f258 of this V1UserFeatures. # noqa: E501
1339
+ :type: bool
1340
+ """
1341
+
1342
+ self._f258 = f258
1343
+
1297
1344
  @property
1298
1345
  def fair_share(self) -> 'bool':
1299
1346
  """Gets the fair_share of this V1UserFeatures. # noqa: E501
@@ -1336,27 +1383,6 @@ class V1UserFeatures(object):
1336
1383
 
1337
1384
  self._featured_studios_admin = featured_studios_admin
1338
1385
 
1339
- @property
1340
- def gcp_overprovisioning(self) -> 'bool':
1341
- """Gets the gcp_overprovisioning of this V1UserFeatures. # noqa: E501
1342
-
1343
-
1344
- :return: The gcp_overprovisioning of this V1UserFeatures. # noqa: E501
1345
- :rtype: bool
1346
- """
1347
- return self._gcp_overprovisioning
1348
-
1349
- @gcp_overprovisioning.setter
1350
- def gcp_overprovisioning(self, gcp_overprovisioning: 'bool'):
1351
- """Sets the gcp_overprovisioning of this V1UserFeatures.
1352
-
1353
-
1354
- :param gcp_overprovisioning: The gcp_overprovisioning of this V1UserFeatures. # noqa: E501
1355
- :type: bool
1356
- """
1357
-
1358
- self._gcp_overprovisioning = gcp_overprovisioning
1359
-
1360
1386
  @property
1361
1387
  def gcs_connections_optimized(self) -> 'bool':
1362
1388
  """Gets the gcs_connections_optimized of this V1UserFeatures. # noqa: E501
lightning_sdk/studio.py CHANGED
@@ -102,6 +102,8 @@ class Studio:
102
102
  cloud_account = _resolve_deprecated_cluster(cloud_account, cluster)
103
103
  cloud_provider = _resolve_deprecated_provider(cloud_provider, provider)
104
104
 
105
+ cls_name = self._cls_name
106
+
105
107
  # if we're skipping init, we don't need to resolve the cloud account as then we're not creating a studio
106
108
  if self._teamspace is not None:
107
109
  _cloud_account = self._cloud_account_api.resolve_cloud_account(
@@ -126,7 +128,7 @@ class Studio:
126
128
  name = config.get_value(DefaultConfigKeys.studio)
127
129
  if name is None and not create_ok:
128
130
  raise ValueError(
129
- "Cannot autodetect Studio. Either use the SDK from within a Studio or pass a name!"
131
+ f"Cannot autodetect {cls_name}. Either use the SDK from within a {cls_name} or pass a name!"
130
132
  )
131
133
 
132
134
  if self._studio is None and not getattr(self._skip_init, "value", False):
@@ -136,7 +138,7 @@ class Studio:
136
138
  # if we don't have a name, raise an error to get
137
139
  # to the exception path and optionally create a studio
138
140
  raise ValueError(
139
- "Cannot autodetect Studio. Either use the SDK from within a Studio or pass a name!"
141
+ f"Cannot autodetect {cls_name}. Either use the SDK from within a {cls_name} or pass a name!"
140
142
  )
141
143
  self._studio = self._studio_api.get_studio(name, self._teamspace.id)
142
144
  except ValueError as e:
@@ -227,7 +229,9 @@ class Studio:
227
229
  @property
228
230
  def cluster(self) -> str:
229
231
  """Returns the cluster the Studio is running on."""
230
- warnings.warn("Studio.cluster is deprecated. Use Studio.cloud_account instead", DeprecationWarning)
232
+ warnings.warn(
233
+ f"{self._cls_name}.cluster is deprecated. Use {self._cls_name}.cloud_account instead", DeprecationWarning
234
+ )
231
235
  return self.cloud_account
232
236
 
233
237
  @property
@@ -266,14 +270,17 @@ class Studio:
266
270
  new_machine = Machine.from_str(machine)
267
271
  if new_machine != self.machine:
268
272
  raise RuntimeError(
269
- f"Requested to start studio on {new_machine}, but studio is already running on {self.machine}."
273
+ f"Requested to start {self._cls_name} on {new_machine}, "
274
+ "but {self._cls_name} is already running on {self.machine}."
270
275
  " Consider switching instead!"
271
276
  )
272
- _logger.info(f"Studio {self.name} is already running")
277
+ _logger.info(f"{self._cls_name} {self.name} is already running")
273
278
  return
274
279
 
275
280
  if status != Status.Stopped:
276
- raise RuntimeError(f"Cannot start a studio that is not stopped. Studio {self.name} is {status}.")
281
+ raise RuntimeError(
282
+ f"Cannot start a {self._cls_name} that is not stopped. {self._cls_name} {self.name} is {status}."
283
+ )
277
284
 
278
285
  # Show progress bar during startup
279
286
  if self.show_progress:
@@ -362,7 +369,8 @@ class Studio:
362
369
  status = self.status
363
370
  if status != Status.Running:
364
371
  raise RuntimeError(
365
- f"Cannot switch machine on a studio that is not running. Studio {self.name} is {status}."
372
+ f"Cannot switch machine on a {self._cls_name} that is not running. "
373
+ "{self._cls_name} {self.name} is {status}."
366
374
  )
367
375
 
368
376
  current_cloud = self._cloud_account_api.get_cloud_account_non_org(
@@ -420,7 +428,10 @@ class Studio:
420
428
  print(f"Running {commands=}")
421
429
  status = self.status
422
430
  if status != Status.Running:
423
- raise RuntimeError(f"Cannot run a command in a studio that is not running. Studio {self.name} is {status}.")
431
+ raise RuntimeError(
432
+ f"Cannot run a command in a {self._cls_name} that is not running. "
433
+ "{self._cls_name} {self.name} is {status}."
434
+ )
424
435
 
425
436
  iter_output = self._studio_api.run_studio_commands_and_yield(
426
437
  self._studio.id, self._teamspace.id, *commands, timeout=timeout, check_interval=check_interval
@@ -446,7 +457,10 @@ class Studio:
446
457
 
447
458
  status = self.status
448
459
  if status != Status.Running:
449
- raise RuntimeError(f"Cannot run a command in a studio that is not running. Studio {self.name} is {status}.")
460
+ raise RuntimeError(
461
+ f"Cannot run a command in a {self._cls_name} that is not running. "
462
+ "{self._cls_name} {self.name} is {status}."
463
+ )
450
464
  output, exit_code = self._studio_api.run_studio_commands(self._studio.id, self._teamspace.id, *commands)
451
465
  output = output.strip()
452
466
 
@@ -616,7 +630,7 @@ class Studio:
616
630
  @auto_sleep.setter
617
631
  def auto_sleep(self, value: bool) -> None:
618
632
  if not value and self.machine == Machine.CPU:
619
- warnings.warn("Disabling auto-sleep will convert the Studio from free to paid!")
633
+ warnings.warn(f"Disabling auto-sleep will convert the {self._cls_name} from free to paid!")
620
634
  self._studio_api.update_autoshutdown(self._studio.id, self._teamspace.id, enabled=value)
621
635
  self._update_studio_reference()
622
636
 
@@ -627,7 +641,7 @@ class Studio:
627
641
 
628
642
  @auto_sleep_time.setter
629
643
  def auto_sleep_time(self, value: int) -> None:
630
- warnings.warn("Setting auto-sleep time will convert the Studio from free to paid!")
644
+ warnings.warn(f"Setting auto-sleep time will convert the {self._cls_name} from free to paid!")
631
645
  self._studio_api.update_autoshutdown(self._studio.id, self._teamspace.id, idle_shutdown_seconds=value)
632
646
  self._update_studio_reference()
633
647
 
@@ -758,6 +772,36 @@ class Studio:
758
772
  def _update_studio_reference(self) -> None:
759
773
  self._studio = self._studio_api.get_studio_by_id(studio_id=self._studio.id, teamspace_id=self._teamspace.id)
760
774
 
775
+ @property
776
+ def _cls_name(self) -> str:
777
+ return self.__class__.__qualname__
778
+
779
+
780
+ class VM(Studio):
781
+ """A single Lightning AI VM.
782
+
783
+ Allows to fully control a vm, including retrieving the status, running commands
784
+ and switching machine types.
785
+
786
+ Args:
787
+ name: the name of the vm
788
+ teamspace: the name of the teamspace the vm is contained by
789
+ org: the name of the organization owning the :param`teamspace` in case it is owned by an org
790
+ user: the name of the user owning the :param`teamspace` in case it is owned directly by a user instead of an org
791
+ cloud_account: the name of the cloud account, the vm should be created on.
792
+ Doesn't matter when the vm already exists.
793
+ cloud_account_provider: The provider to select the cloud-account from.
794
+ If set, must be in agreement with the provider from the cloud_account (if specified).
795
+ If not specified, falls backto the teamspace default cloud account.
796
+ create_ok: whether the vm will be created if it does not yet exist. Defaults to True
797
+ provider: the provider of the machine, the vm should be created on.
798
+
799
+ Note:
800
+ Since a teamspace can either be owned by an org or by a user directly,
801
+ only one of the arguments can be provided.
802
+
803
+ """
804
+
761
805
 
762
806
  def _internal_status_to_external_status(internal_status: str) -> Status:
763
807
  """Converts internal status strings from HTTP requests to external enums."""
@@ -28,7 +28,7 @@ from lightning_sdk.utils.resolve import (
28
28
  if TYPE_CHECKING:
29
29
  from lightning_sdk.job import Job
30
30
  from lightning_sdk.mmt import MMT
31
- from lightning_sdk.studio import Studio
31
+ from lightning_sdk.studio import VM, Studio
32
32
 
33
33
 
34
34
  class FolderLocation(Enum):
@@ -144,13 +144,22 @@ class Teamspace:
144
144
  """All studios within that teamspace."""
145
145
  from lightning_sdk.studio import Studio
146
146
 
147
+ return self._get_studios(Studio)
148
+
149
+ @property
150
+ def vms(self) -> List["VM"]:
151
+ from lightning_sdk.studio import VM
152
+
153
+ return [x for x in self._get_studios(VM) if isinstance(x, VM)]
154
+
155
+ def _get_studios(self, target_cls: type) -> List[Union["Studio", "VM"]]:
147
156
  studios = []
148
157
  cloud_accounts = self._teamspace_api.list_cloud_accounts(teamspace_id=self.id)
149
158
  for cl in cloud_accounts:
150
159
  _studios = self._teamspace_api.list_studios(teamspace_id=self.id, cloud_account=cl.cluster_id)
151
160
  for s in _studios:
152
161
  with skip_studio_init():
153
- studio = Studio(name=s.name, teamspace=self, cluster=cl.cluster_name, create_ok=False)
162
+ studio = target_cls(name=s.name, teamspace=self, cluster=cl.cluster_name, create_ok=False)
154
163
  studio._studio = s
155
164
  studio._teamspace = self
156
165
  studios.append(studio)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 2025.9.23
3
+ Version: 2025.9.29
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License