lightning-sdk 2025.12.16__py3-none-any.whl → 2026.1.22__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 (141) hide show
  1. lightning_sdk/__version__.py +1 -1
  2. lightning_sdk/api/k8s_api.py +75 -29
  3. lightning_sdk/api/org_api.py +7 -0
  4. lightning_sdk/api/studio_api.py +223 -36
  5. lightning_sdk/api/teamspace_api.py +28 -9
  6. lightning_sdk/api/user_api.py +5 -0
  7. lightning_sdk/cli/cp/__init__.py +64 -0
  8. lightning_sdk/cli/entrypoint.py +2 -0
  9. lightning_sdk/cli/groups.py +22 -0
  10. lightning_sdk/cli/legacy/clusters_menu.py +2 -2
  11. lightning_sdk/cli/legacy/deploy/_auth.py +7 -6
  12. lightning_sdk/cli/legacy/download.py +2 -1
  13. lightning_sdk/cli/legacy/run.py +13 -2
  14. lightning_sdk/cli/legacy/studios_menu.py +8 -1
  15. lightning_sdk/cli/studio/__init__.py +4 -0
  16. lightning_sdk/cli/studio/cp.py +20 -64
  17. lightning_sdk/cli/studio/ls.py +57 -0
  18. lightning_sdk/cli/studio/rm.py +71 -0
  19. lightning_sdk/cli/utils/logging.py +2 -1
  20. lightning_sdk/cli/utils/studio_filesystem.py +65 -0
  21. lightning_sdk/cli/utils/teamspace_selection.py +5 -0
  22. lightning_sdk/exceptions.py +4 -0
  23. lightning_sdk/job/base.py +24 -5
  24. lightning_sdk/job/job.py +12 -5
  25. lightning_sdk/job/v1.py +5 -2
  26. lightning_sdk/job/v2.py +9 -1
  27. lightning_sdk/k8s_cluster.py +9 -10
  28. lightning_sdk/lightning_cloud/__version__.py +1 -1
  29. lightning_sdk/lightning_cloud/openapi/__init__.py +46 -3
  30. lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
  31. lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +118 -1
  32. lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +787 -125
  33. lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +5 -1
  34. lightning_sdk/lightning_cloud/openapi/api/file_system_service_api.py +11 -11
  35. lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +246 -19
  36. lightning_sdk/lightning_cloud/openapi/api/lightningwork_service_api.py +116 -11
  37. lightning_sdk/lightning_cloud/openapi/api/lit_logger_service_api.py +588 -2
  38. lightning_sdk/lightning_cloud/openapi/api/models_store_api.py +9 -1
  39. lightning_sdk/lightning_cloud/openapi/api/storage_service_api.py +5 -1
  40. lightning_sdk/lightning_cloud/openapi/api/virtual_machine_service_api.py +557 -0
  41. lightning_sdk/lightning_cloud/openapi/models/__init__.py +45 -3
  42. lightning_sdk/lightning_cloud/openapi/models/cloud_space_environment_template_service_update_cloud_space_environment_template_body.py +27 -1
  43. lightning_sdk/lightning_cloud/openapi/models/cluster_service_add_container_registry_body.py +123 -0
  44. lightning_sdk/lightning_cloud/openapi/models/cluster_service_create_cluster_capacity_reservation_body.py +53 -1
  45. lightning_sdk/lightning_cloud/openapi/models/cluster_service_create_machine_body.py +79 -1
  46. lightning_sdk/lightning_cloud/openapi/models/cluster_service_create_org_cluster_capacity_reservation_body.py +409 -0
  47. lightning_sdk/lightning_cloud/openapi/models/cluster_service_refresh_container_registry_credentials_body.py +97 -0
  48. lightning_sdk/lightning_cloud/openapi/models/cluster_service_report_machine_system_metrics_body.py +123 -0
  49. lightning_sdk/lightning_cloud/openapi/models/cluster_service_validate_container_registry_body.py +97 -0
  50. lightning_sdk/lightning_cloud/openapi/models/externalv1_cloud_space_instance_status.py +27 -1
  51. lightning_sdk/lightning_cloud/openapi/models/lit_logger_service_create_lit_logger_media_body.py +305 -0
  52. lightning_sdk/lightning_cloud/openapi/models/lit_logger_service_update_lit_logger_media_body.py +149 -0
  53. lightning_sdk/lightning_cloud/openapi/models/lit_logger_service_update_metrics_stream_body.py +53 -1
  54. lightning_sdk/lightning_cloud/openapi/models/v1_add_container_registry_response.py +123 -0
  55. lightning_sdk/lightning_cloud/openapi/models/v1_capacity_reservation_used_by.py +227 -0
  56. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_provider.py +1 -1
  57. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +27 -1
  58. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_type.py +1 -0
  59. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_specialized_view.py +1 -0
  60. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_accelerator.py +27 -1
  61. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_capacity_reservation.py +27 -1
  62. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_spec.py +53 -27
  63. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_type.py +0 -1
  64. lightning_sdk/lightning_cloud/openapi/models/v1_container_registry.py +253 -0
  65. lightning_sdk/lightning_cloud/openapi/models/v1_container_registry_info.py +281 -0
  66. lightning_sdk/lightning_cloud/openapi/models/v1_container_registry_integration.py +123 -0
  67. lightning_sdk/lightning_cloud/openapi/models/v1_container_registry_status.py +105 -0
  68. lightning_sdk/lightning_cloud/openapi/models/v1_create_cloud_space_environment_template_request.py +27 -1
  69. lightning_sdk/lightning_cloud/openapi/models/v1_create_lit_logger_media_response.py +149 -0
  70. lightning_sdk/lightning_cloud/openapi/models/v1_create_org_cluster_capacity_reservation_response.py +201 -0
  71. lightning_sdk/lightning_cloud/openapi/models/v1_create_sdk_command_history_request.py +29 -3
  72. lightning_sdk/lightning_cloud/openapi/models/v1_cudo_direct_v1.py +175 -0
  73. lightning_sdk/lightning_cloud/openapi/models/v1_delete_container_registry_response.py +97 -0
  74. lightning_sdk/lightning_cloud/openapi/models/v1_delete_lit_logger_media_response.py +97 -0
  75. lightning_sdk/lightning_cloud/openapi/models/v1_delete_virtual_machine_response.py +97 -0
  76. lightning_sdk/lightning_cloud/openapi/models/{v1_ai_pod_v1.py → v1_ecr_registry_config.py} +49 -49
  77. lightning_sdk/lightning_cloud/openapi/models/v1_ecr_registry_config_input.py +123 -0
  78. lightning_sdk/lightning_cloud/openapi/models/v1_ecr_registry_details.py +201 -0
  79. lightning_sdk/lightning_cloud/openapi/models/v1_external_cluster_spec.py +27 -27
  80. lightning_sdk/lightning_cloud/openapi/models/v1_external_search_user.py +27 -1
  81. lightning_sdk/lightning_cloud/openapi/models/v1_get_artifacts_page_response.py +29 -3
  82. lightning_sdk/lightning_cloud/openapi/models/v1_get_kubernetes_pod_logs_response.py +149 -0
  83. lightning_sdk/lightning_cloud/openapi/models/{v1_get_machine_response.py → v1_get_kubernetes_pod_response.py} +23 -23
  84. lightning_sdk/lightning_cloud/openapi/models/v1_get_user_response.py +27 -1
  85. lightning_sdk/lightning_cloud/openapi/models/v1_job_spec.py +27 -1
  86. lightning_sdk/lightning_cloud/openapi/models/v1_joinable_organization.py +27 -1
  87. lightning_sdk/lightning_cloud/openapi/models/v1_k8s_incident_setting.py +149 -0
  88. lightning_sdk/lightning_cloud/openapi/models/v1_k8s_incident_type.py +108 -0
  89. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_settings_v1.py +53 -1
  90. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_v1.py +105 -1
  91. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_pod.py +27 -1
  92. lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_pod_logs_page.py +227 -0
  93. lightning_sdk/lightning_cloud/openapi/models/v1_kubevirt_config.py +357 -0
  94. lightning_sdk/lightning_cloud/openapi/models/v1_list_container_registries_response.py +123 -0
  95. lightning_sdk/lightning_cloud/openapi/models/v1_list_kubernetes_pods_response.py +43 -17
  96. lightning_sdk/lightning_cloud/openapi/models/v1_list_kubernetes_pods_sort_order.py +104 -0
  97. lightning_sdk/lightning_cloud/openapi/models/v1_list_lit_logger_media_response.py +149 -0
  98. lightning_sdk/lightning_cloud/openapi/models/v1_list_models_response.py +55 -3
  99. lightning_sdk/lightning_cloud/openapi/models/v1_list_virtual_machines_response.py +123 -0
  100. lightning_sdk/lightning_cloud/openapi/models/v1_lit_logger_media.py +513 -0
  101. lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +53 -53
  102. lightning_sdk/lightning_cloud/openapi/models/v1_machine_direct_v1.py +107 -3
  103. lightning_sdk/lightning_cloud/openapi/models/v1_media_type.py +104 -0
  104. lightning_sdk/lightning_cloud/openapi/models/v1_nebius_direct_v1.py +29 -3
  105. lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +27 -1
  106. lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +27 -1
  107. lightning_sdk/lightning_cloud/openapi/models/v1_refresh_container_registry_credentials_response.py +123 -0
  108. lightning_sdk/lightning_cloud/openapi/models/v1_report_cloud_space_instance_idle_state_response.py +97 -0
  109. lightning_sdk/lightning_cloud/openapi/models/v1_report_machine_system_metrics_response.py +97 -0
  110. lightning_sdk/lightning_cloud/openapi/models/v1_search_user.py +27 -1
  111. lightning_sdk/lightning_cloud/openapi/models/v1_tenant_credentials.py +201 -0
  112. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +217 -113
  113. lightning_sdk/lightning_cloud/openapi/models/v1_validate_container_registry_response.py +149 -0
  114. lightning_sdk/lightning_cloud/openapi/models/v1_virtual_machine.py +409 -0
  115. lightning_sdk/lightning_cloud/openapi/models/v1_vm_configuration.py +149 -0
  116. lightning_sdk/lightning_cloud/openapi/models/v1_vm_provider_configuration.py +227 -0
  117. lightning_sdk/lightning_cloud/openapi/models/virtual_machine_service_create_virtual_machine_body.py +565 -0
  118. lightning_sdk/lightning_cloud/openapi/models/virtual_machine_service_update_virtual_machine_body.py +97 -0
  119. lightning_sdk/lightning_cloud/openapi/rest.py +2 -2
  120. lightning_sdk/lightning_cloud/rest_client.py +0 -2
  121. lightning_sdk/machine.py +3 -3
  122. lightning_sdk/mmt/base.py +26 -7
  123. lightning_sdk/mmt/mmt.py +11 -6
  124. lightning_sdk/mmt/v1.py +5 -2
  125. lightning_sdk/mmt/v2.py +5 -2
  126. lightning_sdk/organization.py +10 -1
  127. lightning_sdk/owner.py +4 -0
  128. lightning_sdk/plugin.py +2 -2
  129. lightning_sdk/studio.py +47 -6
  130. lightning_sdk/user.py +22 -2
  131. lightning_sdk/utils/logging.py +2 -1
  132. lightning_sdk/utils/resolve.py +9 -7
  133. {lightning_sdk-2025.12.16.dist-info → lightning_sdk-2026.1.22.dist-info}/METADATA +1 -5
  134. {lightning_sdk-2025.12.16.dist-info → lightning_sdk-2026.1.22.dist-info}/RECORD +139 -94
  135. {lightning_sdk-2025.12.16.dist-info → lightning_sdk-2026.1.22.dist-info}/WHEEL +1 -1
  136. lightning_sdk/lightning_cloud/cli/__main__.py +0 -29
  137. lightning_sdk/lightning_cloud/source_code/logs_socket_api.py +0 -103
  138. /lightning_sdk/lightning_cloud/openapi/models/{v1_list_filesystem_mm_ts_response.py → v1_list_filesystem_mmts_response.py} +0 -0
  139. {lightning_sdk-2025.12.16.dist-info → lightning_sdk-2026.1.22.dist-info}/LICENSE +0 -0
  140. {lightning_sdk-2025.12.16.dist-info → lightning_sdk-2026.1.22.dist-info}/entry_points.txt +0 -0
  141. {lightning_sdk-2025.12.16.dist-info → lightning_sdk-2026.1.22.dist-info}/top_level.txt +0 -0
lightning_sdk/machine.py CHANGED
@@ -162,12 +162,12 @@ Machine.CPU_X_4 = Machine(name="CPU_X_4", slug="cpu-4", family="CPU", accelerato
162
162
  Machine.CPU_X_8 = Machine(name="CPU_X_8", slug="cpu-8", family="CPU", accelerator_count=8)
163
163
  Machine.CPU_X_16 = Machine(name="CPU_X_16", slug="cpu-16", family="CPU", accelerator_count=16)
164
164
  # available data-prep (big disk) machines
165
- Machine.DATA_PREP = Machine(name="DATA_PREP", slug="data-prep-mid", family="DATA_PREP", accelerator_count=32)
165
+ Machine.DATA_PREP = Machine(name="DATA_PREP", slug="data-prep-mid", family="DATA-PREP", accelerator_count=32)
166
166
  Machine.DATA_PREP_MAX = Machine(
167
- name="DATA_PREP_MAX", slug="data-prep-max-large", family="DATA_PREP", accelerator_count=64
167
+ name="DATA_PREP_MAX", slug="data-prep-max-large", family="DATA-PREP", accelerator_count=64
168
168
  )
169
169
  Machine.DATA_PREP_ULTRA = Machine(
170
- name="DATA_PREP_ULTRA", slug="data-prep-ultra-extra-large", family="DATA_PREP", accelerator_count=96
170
+ name="DATA_PREP_ULTRA", slug="data-prep-ultra-extra-large", family="DATA-PREP", accelerator_count=96
171
171
  )
172
172
 
173
173
  # GPU machines
lightning_sdk/mmt/base.py CHANGED
@@ -69,7 +69,7 @@ class _BaseMMT(_BaseJob):
69
69
  interruptible: bool = False,
70
70
  image_credentials: Optional[str] = None,
71
71
  cloud_account_auth: bool = False,
72
- entrypoint: str = "sh -c",
72
+ entrypoint: Optional[str] = None,
73
73
  path_mappings: Optional[Dict[str, str]] = None,
74
74
  max_runtime: Optional[int] = None,
75
75
  artifacts_local: Optional[str] = None, # deprecated in favor of path_mappings
@@ -104,8 +104,10 @@ class _BaseMMT(_BaseJob):
104
104
  cloud_account_auth: Whether to authenticate with the cloud account to pull the image.
105
105
  Required if the registry is part of a cloud provider (e.g. ECR).
106
106
  entrypoint: The entrypoint of your docker container. Defaults to `sh -c` which
107
- just runs the provided command in a standard shell.
108
- To use the pre-defined entrypoint of the provided image, set this to an empty string.
107
+ just runs the provided command in a standard shell if a command is provided.
108
+ If no command is provided, it will run the pre-defined entrypoint of the provided image.
109
+ To use the pre-defined entrypoint of the provided image with a specified command,
110
+ set this to an empty string.
109
111
  Only applicable when submitting docker jobs.
110
112
  path_mappings: Dictionary of path mappings. The keys are the path inside the container whereas the value
111
113
  represents the data-connection name and the path inside that connection.
@@ -173,7 +175,7 @@ class _BaseMMT(_BaseJob):
173
175
  "Other jobs will automatically persist artifacts to the teamspace distributed filesystem."
174
176
  )
175
177
 
176
- if entrypoint != "sh -c":
178
+ if entrypoint is not None:
177
179
  raise ValueError("Specifying the entrypoint has no effect for jobs with Studio envs.")
178
180
 
179
181
  else:
@@ -199,6 +201,20 @@ class _BaseMMT(_BaseJob):
199
201
  f"<CONNECTION_TYPE>:<CONNECTION_NAME>:<PATH_WITHIN_CONNECTION>, got {artifacts_local}"
200
202
  )
201
203
 
204
+ # command specified, so use the default entrypoint of sh -c
205
+ if command is not None and entrypoint is None:
206
+ entrypoint = "sh -c"
207
+
208
+ # entrypoint specifically set to empty string, so set to None here to fall back to the image entrypoint
209
+ elif entrypoint == "": # noqa: SIM114
210
+ entrypoint = None
211
+
212
+ # entrypoint not specified, but also no command specified, so use the image entrypoint
213
+ elif entrypoint is None:
214
+ entrypoint = None
215
+
216
+ # all other cases, the entrypoint has been specifically set, so use it as is
217
+
202
218
  inst = cls(name=name, teamspace=teamspace, org=org, user=user, _fetch_job=False)
203
219
  inst._submit(
204
220
  num_machines=num_machines,
@@ -235,7 +251,7 @@ class _BaseMMT(_BaseJob):
235
251
  cloud_provider: Optional[Union["CloudProvider", str]] = None,
236
252
  image_credentials: Optional[str] = None,
237
253
  cloud_account_auth: bool = False,
238
- entrypoint: str = "sh -c",
254
+ entrypoint: Optional[str] = None,
239
255
  path_mappings: Optional[Dict[str, str]] = None,
240
256
  artifacts_local: Optional[str] = None, # deprecated in favor of path_mappings
241
257
  artifacts_remote: Optional[str] = None, # deprecated in favor of path_mappings
@@ -260,8 +276,11 @@ class _BaseMMT(_BaseJob):
260
276
  This should be the name of the respective credentials secret created on the Lightning AI platform.
261
277
  cloud_account_auth: Whether to authenticate with the cloud account to pull the image.
262
278
  Required if the registry is part of a cloud provider (e.g. ECR).
263
- entrypoint: The entrypoint of your docker container. Defaults to sh -c.
264
- To use the pre-defined entrypoint of the provided image, set this to an empty string.
279
+ entrypoint: The entrypoint of your docker container. Defaults to `sh -c` which
280
+ just runs the provided command in a standard shell if a command is provided.
281
+ If no command is provided, it will run the pre-defined entrypoint of the provided image.
282
+ To use the pre-defined entrypoint of the provided image with a specified command,
283
+ set this to an empty string.
265
284
  Only applicable when submitting docker jobs.
266
285
  path_mappings: Dictionary of path mappings. The keys are the path inside the container whereas the value
267
286
  represents the data-connection name and the path inside that connection.
lightning_sdk/mmt/mmt.py CHANGED
@@ -100,7 +100,7 @@ class MMT(_BaseMMT):
100
100
  interruptible: bool = False,
101
101
  image_credentials: Optional[str] = None,
102
102
  cloud_account_auth: bool = False,
103
- entrypoint: str = "sh -c",
103
+ entrypoint: Optional[str] = None,
104
104
  path_mappings: Optional[Dict[str, str]] = None,
105
105
  max_runtime: Optional[int] = None,
106
106
  artifacts_local: Optional[str] = None,
@@ -134,8 +134,11 @@ class MMT(_BaseMMT):
134
134
  This should be the name of the respective credentials secret created on the Lightning AI platform.
135
135
  cloud_account_auth: Whether to authenticate with the cloud account to pull the image.
136
136
  Required if the registry is part of a cloud provider (e.g. ECR).
137
- entrypoint: The entrypoint of your docker container. Defaults to sh -c.
138
- To use the pre-defined entrypoint of the provided image, set this to an empty string.
137
+ entrypoint: The entrypoint of your docker container. Defaults to `sh -c` which
138
+ just runs the provided command in a standard shell if a command is provided.
139
+ If no command is provided, it will run the pre-defined entrypoint of the provided image.
140
+ To use the pre-defined entrypoint of the provided image with a specified command,
141
+ set this to an empty string.
139
142
  Only applicable when submitting docker jobs.
140
143
  path_mappings: Dictionary of path mappings. The keys are the path inside the container whereas the value
141
144
  represents the data-connection name and the path inside that connection.
@@ -194,7 +197,7 @@ class MMT(_BaseMMT):
194
197
  cloud_provider: Optional[Union["CloudProvider", str]] = None,
195
198
  image_credentials: Optional[str] = None,
196
199
  cloud_account_auth: bool = False,
197
- entrypoint: str = "sh -c",
200
+ entrypoint: Optional[str] = None,
198
201
  path_mappings: Optional[Dict[str, str]] = None,
199
202
  max_runtime: Optional[int] = None,
200
203
  artifacts_local: Optional[str] = None, # deprecated in favor of path_mappings
@@ -224,8 +227,10 @@ class MMT(_BaseMMT):
224
227
  cloud_account_auth: Whether to authenticate with the cloud account to pull the image.
225
228
  Required if the registry is part of a cloud provider (e.g. ECR).
226
229
  entrypoint: The entrypoint of your docker container. Defaults to `sh -c` which
227
- just runs the provided command in a standard shell.
228
- To use the pre-defined entrypoint of the provided image, set this to an empty string.
230
+ just runs the provided command in a standard shell if a command is provided.
231
+ If no command is provided, it will run the pre-defined entrypoint of the provided image.
232
+ To use the pre-defined entrypoint of the provided image with a specified command,
233
+ set this to an empty string.
229
234
  Only applicable when submitting docker jobs.
230
235
  path_mappings: Dictionary of path mappings. The keys are the path inside the container whereas the value
231
236
  represents the data-connection name and the path inside that connection.
lightning_sdk/mmt/v1.py CHANGED
@@ -53,7 +53,7 @@ class _MMTV1(_BaseMMT):
53
53
  cloud_provider: Optional[Union["CloudProvider", str]] = None,
54
54
  image_credentials: Optional[str] = None,
55
55
  cloud_account_auth: bool = False,
56
- entrypoint: str = "sh -c",
56
+ entrypoint: Optional[str] = None,
57
57
  path_mappings: Optional[Dict[str, str]] = None,
58
58
  max_runtime: Optional[int] = None,
59
59
  artifacts_local: Optional[str] = None,
@@ -89,7 +89,10 @@ class _MMTV1(_BaseMMT):
89
89
  Note that the connection needs to be added to the teamspace already in order for it to be found.
90
90
  Only supported for jobs with a docker image compute environment.
91
91
  entrypoint: The entrypoint of your docker container. Defaults to `sh -c` which
92
- just runs the provided command in a standard shell.
92
+ just runs the provided command in a standard shell if a command is provided.
93
+ If no command is provided, it will run the pre-defined entrypoint of the provided image.
94
+ To use the pre-defined entrypoint of the provided image with a specified command,
95
+ set this to an empty string.
93
96
  To use the pre-defined entrypoint of the provided image, set this to an empty string.
94
97
  Only applicable when submitting docker jobs.
95
98
  path_mappings: The mappings from data connection inside your container (not supported)
lightning_sdk/mmt/v2.py CHANGED
@@ -53,7 +53,7 @@ class _MMTV2(_BaseMMT):
53
53
  cloud_provider: Optional[Union["CloudProvider", str]] = None,
54
54
  image_credentials: Optional[str] = None,
55
55
  cloud_account_auth: bool = False,
56
- entrypoint: str = "sh -c",
56
+ entrypoint: Optional[str] = None,
57
57
  path_mappings: Optional[Dict[str, str]] = None,
58
58
  max_runtime: Optional[int] = None,
59
59
  artifacts_local: Optional[str] = None, # deprecated in favor of path_mappings
@@ -83,7 +83,10 @@ class _MMTV2(_BaseMMT):
83
83
  cloud_account_auth: Whether to authenticate with the cloud account to pull the image.
84
84
  Required if the registry is part of a cloud provider (e.g. ECR).
85
85
  entrypoint: The entrypoint of your docker container. Defaults to `sh -c` which
86
- just runs the provided command in a standard shell.
86
+ just runs the provided command in a standard shell if a command is provided.
87
+ If no command is provided, it will run the pre-defined entrypoint of the provided image.
88
+ To use the pre-defined entrypoint of the provided image with a specified command,
89
+ set this to an empty string.
87
90
  To use the pre-defined entrypoint of the provided image, set this to an empty string.
88
91
  Only applicable when submitting docker jobs.
89
92
  path_mappings: Dictionary of path mappings. The keys are the path inside the container whereas the value
@@ -1,9 +1,12 @@
1
- from typing import Optional
1
+ from typing import TYPE_CHECKING, Optional
2
2
 
3
3
  from lightning_sdk.api import OrgApi
4
4
  from lightning_sdk.owner import Owner
5
5
  from lightning_sdk.utils.resolve import _resolve_org_name
6
6
 
7
+ if TYPE_CHECKING:
8
+ from lightning_sdk.teamspace import Teamspace
9
+
7
10
 
8
11
  class Organization(Owner):
9
12
  """Represents an organization owner of teamspaces and studios.
@@ -44,6 +47,12 @@ class Organization(Owner):
44
47
  def default_cloud_account(self) -> Optional[str]:
45
48
  return self._org.preferred_cluster or None
46
49
 
50
+ def create_teamspace(self, name: str) -> "Teamspace":
51
+ from lightning_sdk.teamspace import Teamspace
52
+
53
+ self._org_api.create_teamspace(name, self.id)
54
+ return Teamspace(name=name, org=self)
55
+
47
56
  def __repr__(self) -> str:
48
57
  """Returns reader friendly representation."""
49
58
  return f"Organization(name={self.name})"
lightning_sdk/owner.py CHANGED
@@ -24,6 +24,10 @@ class Owner(ABC, metaclass=TrackCallsABCMeta):
24
24
  def id(self) -> str:
25
25
  """The owner's ID."""
26
26
 
27
+ @abstractmethod
28
+ def create_teamspace(self, name: str) -> "Teamspace":
29
+ """Creates a new teamspace."""
30
+
27
31
  @property
28
32
  def teamspaces(self) -> List["Teamspace"]:
29
33
  """All teamspaces by this owner."""
lightning_sdk/plugin.py CHANGED
@@ -411,12 +411,12 @@ class CustomPortPlugin(_Plugin):
411
411
  if name is None:
412
412
  name = _run_name("port")
413
413
 
414
- return self._studio._studio_api.start_new_port(
414
+ return self._studio._studio_api.add_port(
415
415
  teamspace_id=self._studio._teamspace.id,
416
416
  studio_id=self._studio._studio.id,
417
417
  name=name,
418
418
  port=port,
419
- )
419
+ ).urls[0]
420
420
 
421
421
 
422
422
  @runtime_checkable
lightning_sdk/studio.py CHANGED
@@ -2,7 +2,7 @@ import glob
2
2
  import os
3
3
  import threading
4
4
  import warnings
5
- from typing import TYPE_CHECKING, Any, Dict, Mapping, Optional, Tuple, Union
5
+ from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple, Union
6
6
 
7
7
  from tqdm.auto import tqdm
8
8
 
@@ -11,8 +11,8 @@ from lightning_sdk.api.studio_api import StudioApi
11
11
  from lightning_sdk.api.utils import AccessibleResource, raise_access_error_if_not_allowed
12
12
  from lightning_sdk.base_studio import BaseStudio
13
13
  from lightning_sdk.constants import _LIGHTNING_DEBUG
14
- from lightning_sdk.exceptions import OutOfCapacityError
15
- from lightning_sdk.lightning_cloud.openapi import V1ClusterType
14
+ from lightning_sdk.exceptions import NotSupportedError, OutOfCapacityError
15
+ from lightning_sdk.lightning_cloud.openapi import V1ClusterType, V1Endpoint
16
16
  from lightning_sdk.machine import DEFAULT_MACHINE, CloudProvider, Machine
17
17
  from lightning_sdk.organization import Organization
18
18
  from lightning_sdk.owner import Owner
@@ -341,12 +341,20 @@ class Studio(metaclass=TrackCallsMeta):
341
341
  if new_machine != self.machine:
342
342
  raise RuntimeError(
343
343
  f"Requested to start {self._cls_name} on {new_machine}, "
344
- "but {self._cls_name} is already running on {self.machine}."
344
+ f"but {self._cls_name} is already running on {self.machine}."
345
345
  " Consider switching instead!"
346
346
  )
347
347
  _logger.info(f"{self._cls_name} {self.name} is already running")
348
348
  return
349
349
 
350
+ if not self._studio_api.machine_is_supported(
351
+ new_machine, self._teamspace.id, self.cloud_account, _get_org_id(self._teamspace)
352
+ ):
353
+ raise NotSupportedError(
354
+ "Requested machine is not supported in the selected cloud account. "
355
+ "Try a different machine or cloud account by setting the `machine` or `cloud_account` argument."
356
+ )
357
+
350
358
  if not self._studio_api.machine_has_capacity(
351
359
  new_machine,
352
360
  self._teamspace.id,
@@ -548,7 +556,7 @@ class Studio(metaclass=TrackCallsMeta):
548
556
  if status != Status.Running:
549
557
  raise RuntimeError(
550
558
  f"Cannot run a command in a {self._cls_name} that is not running. "
551
- "{self._cls_name} {self.name} is {status}."
559
+ f"{self._cls_name} {self.name} is {status}."
552
560
  )
553
561
  output, exit_code = self._studio_api.run_studio_commands(self._studio.id, self._teamspace.id, *commands)
554
562
  output = output.strip()
@@ -605,11 +613,13 @@ class Studio(metaclass=TrackCallsMeta):
605
613
  progress_bar = tqdm(total=len(all_files), desc="Uploading files", unit="file")
606
614
  for local_file, remote_path in sorted(all_files, key=lambda p: p[1]):
607
615
  if progress_bar:
608
- progress_bar.set_description(f"Uploading {local_file}")
616
+ progress_bar.set_description("Uploading files")
609
617
  self.upload_file(local_file, remote_path=remote_path, progress_bar=False)
610
618
  if progress_bar:
611
619
  progress_bar.update(1)
612
620
  if progress_bar:
621
+ progress_bar.set_description("Upload complete")
622
+ progress_bar.refresh()
613
623
  progress_bar.close()
614
624
 
615
625
  def download_file(self, remote_path: str, file_path: Optional[str] = None) -> None:
@@ -707,6 +717,37 @@ class Studio(metaclass=TrackCallsMeta):
707
717
  interruptible=interruptible,
708
718
  )
709
719
 
720
+ def add_ports(self, ports: Union[int, List[int], Dict[str, int]]) -> List[V1Endpoint]:
721
+ """Add one or more ports to the studio and return their endpoints.
722
+
723
+ Args:
724
+ ports: Port to add. Can be:
725
+ - int: Single port (e.g., 8080)
726
+ - List[int]: Multiple ports ()
727
+ - dict[str, int]: Named ports (e.g., {"web": 8080})
728
+
729
+ Returns:
730
+ List of V1Endpoint objects. Access endpoint properties like:
731
+ - endpoint.name: Port name (None for unnamed ports)
732
+ - endpoint.ports: List of port numbers
733
+ - endpoint.urls: List of accessible URLs
734
+ """
735
+ if isinstance(ports, dict):
736
+ port_items = ports.items()
737
+ elif isinstance(ports, list):
738
+ port_items = ((None, port) for port in ports)
739
+ else:
740
+ port_items = [(None, ports)]
741
+
742
+ return [
743
+ self._studio_api.add_port(self._teamspace.id, self._studio.id, name=name, port=port)
744
+ for name, port in port_items
745
+ ]
746
+
747
+ def list_ports(self) -> List[V1Endpoint]:
748
+ """List ports that are exposed in the Studio."""
749
+ return self._studio_api.list_ports(self._teamspace.id, self._studio.id)
750
+
710
751
  def create_assistant(self, name: str, port: int) -> None:
711
752
  assistant = self._studio_api.create_assistant(
712
753
  studio_id=self._studio.id, teamspace_id=self._teamspace.id, port=port, assistant_name=name
lightning_sdk/user.py CHANGED
@@ -1,8 +1,12 @@
1
- from typing import Dict, Optional
1
+ from typing import TYPE_CHECKING, Dict, List, Optional
2
2
 
3
3
  from lightning_sdk.api import UserApi
4
4
  from lightning_sdk.owner import Owner
5
- from lightning_sdk.utils.resolve import _resolve_user_name
5
+ from lightning_sdk.utils.resolve import _get_authed_user, _get_organizations_for_authed_user, _resolve_user_name
6
+
7
+ if TYPE_CHECKING:
8
+ from lightning_sdk.organization import Organization
9
+ from lightning_sdk.teamspace import Teamspace
6
10
 
7
11
 
8
12
  class User(Owner):
@@ -55,6 +59,22 @@ class User(Owner):
55
59
 
56
60
  self._user_api.set_secret(key, value)
57
61
 
62
+ def create_teamspace(self, name: str) -> "Teamspace":
63
+ from lightning_sdk.teamspace import Teamspace
64
+
65
+ if not _get_authed_user().id == self.id:
66
+ raise ValueError("Can only create teamspaces for currently authenticated user")
67
+
68
+ self._user_api.create_teamspace(name)
69
+ return Teamspace(name=name, user=self)
70
+
71
+ @property
72
+ def organizations(self) -> List["Organization"]:
73
+ if not _get_authed_user().id == self.id:
74
+ raise ValueError("Can only list organizations for currently authenticated user")
75
+
76
+ return _get_organizations_for_authed_user(user_api=self._user_api)
77
+
58
78
  def __repr__(self) -> str:
59
79
  """Returns reader friendly representation."""
60
80
  return f"User(name={self.name})"
@@ -22,7 +22,7 @@ def track_calls() -> Callable[..., any]:
22
22
  bound_args.apply_defaults()
23
23
 
24
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} "
25
+ message = f"ARGS: {args_str} "
26
26
 
27
27
  body = V1CreateSDKCommandHistoryRequest(
28
28
  command=func.__qualname__,
@@ -30,6 +30,7 @@ def track_calls() -> Callable[..., any]:
30
30
  project_id=None,
31
31
  severity=V1SDKCommandHistorySeverity.INFO,
32
32
  type=V1SDKCommandHistoryType.SDK,
33
+ version=__version__,
33
34
  )
34
35
 
35
36
  try:
@@ -2,6 +2,7 @@ import logging
2
2
  import os
3
3
  import warnings
4
4
  from contextlib import contextmanager
5
+ from functools import lru_cache
5
6
  from typing import TYPE_CHECKING, Generator, List, Optional, Tuple, Union
6
7
 
7
8
  from lightning_sdk.api import TeamspaceApi, UserApi
@@ -222,25 +223,26 @@ def _resolve_teamspace(
222
223
  raise RuntimeError("Neither user nor org provided, but one of them needs to be provided")
223
224
 
224
225
 
225
- def _get_organizations_for_authed_user() -> List["Organization"]:
226
+ def _get_organizations_for_authed_user(user_api: Optional[UserApi] = None) -> List["Organization"]:
226
227
  """Returns Organizations the current Authed user is a member of."""
227
228
  from lightning_sdk.organization import Organization
228
229
 
229
- _orgs = UserApi()._get_organizations_for_authed_user()
230
+ _orgs = (user_api or UserApi())._get_organizations_for_authed_user()
230
231
  return [Organization(_org.name) for _org in _orgs]
231
232
 
232
233
 
233
- def _get_teamspace_names_for_authed_user() -> List[str]:
234
+ def _get_teamspace_names_for_authed_user(user_api: Optional[UserApi] = None) -> List[str]:
234
235
  """Returns Teamspace's names the current Authed user is a member of."""
235
- teamspaces = UserApi()._get_all_teamspace_memberships("")
236
+ teamspaces = (user_api or UserApi())._get_all_teamspace_memberships("")
236
237
  return sorted([ts.name for ts in teamspaces])
237
238
 
238
239
 
239
- def _get_authed_user() -> "User":
240
+ @lru_cache(maxsize=1)
241
+ def _get_authed_user(user_api: Optional[UserApi] = None, teamspace_api: Optional[TeamspaceApi] = None) -> "User":
240
242
  from lightning_sdk.user import User
241
243
 
242
- user_id = TeamspaceApi()._get_authed_user_id()
243
- _user = UserApi()._get_user_by_id(user_id)
244
+ user_id = (teamspace_api or TeamspaceApi())._get_authed_user_id()
245
+ _user = (user_api or UserApi())._get_user_by_id(user_id)
244
246
  return User(name=_user.username)
245
247
 
246
248
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 2025.12.16
3
+ Version: 2026.1.22
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License
@@ -38,8 +38,6 @@ Requires-Dist: click
38
38
  Requires-Dist: docker
39
39
  Requires-Dist: fastapi
40
40
  Requires-Dist: packaging
41
- Requires-Dist: pandas
42
- Requires-Dist: pyjwt
43
41
  Requires-Dist: pyyaml
44
42
  Requires-Dist: requests
45
43
  Requires-Dist: rich
@@ -48,8 +46,6 @@ Requires-Dist: six
48
46
  Requires-Dist: tqdm
49
47
  Requires-Dist: urllib3<=2.5.0
50
48
  Requires-Dist: uvicorn
51
- Requires-Dist: websocket-client
52
- Requires-Dist: wget
53
49
  Provides-Extra: serve
54
50
  Requires-Dist: litserve>=0.2.5; extra == "serve"
55
51