lightning-sdk 0.1.55__py3-none-any.whl → 0.1.56__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 (53) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/ai_hub.py +22 -0
  3. lightning_sdk/api/ai_hub_api.py +21 -2
  4. lightning_sdk/api/deployment_api.py +4 -3
  5. lightning_sdk/api/job_api.py +5 -10
  6. lightning_sdk/api/mmt_api.py +1 -4
  7. lightning_sdk/api/studio_api.py +5 -7
  8. lightning_sdk/api/teamspace_api.py +7 -0
  9. lightning_sdk/api/utils.py +1 -27
  10. lightning_sdk/cli/configure.py +92 -0
  11. lightning_sdk/cli/connect.py +31 -0
  12. lightning_sdk/cli/delete.py +6 -4
  13. lightning_sdk/cli/download.py +1 -1
  14. lightning_sdk/cli/entrypoint.py +8 -1
  15. lightning_sdk/cli/generate.py +13 -36
  16. lightning_sdk/cli/inspect.py +4 -2
  17. lightning_sdk/cli/jobs_menu.py +2 -1
  18. lightning_sdk/cli/list.py +5 -10
  19. lightning_sdk/cli/mmts_menu.py +2 -1
  20. lightning_sdk/cli/run.py +3 -3
  21. lightning_sdk/cli/serve.py +1 -2
  22. lightning_sdk/cli/start.py +2 -2
  23. lightning_sdk/cli/stop.py +5 -3
  24. lightning_sdk/cli/studios_menu.py +24 -1
  25. lightning_sdk/cli/switch.py +2 -2
  26. lightning_sdk/cli/teamspace_menu.py +2 -1
  27. lightning_sdk/cli/upload.py +6 -4
  28. lightning_sdk/lightning_cloud/openapi/__init__.py +4 -0
  29. lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +105 -0
  30. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +113 -0
  31. lightning_sdk/lightning_cloud/openapi/api/lit_registry_service_api.py +7 -3
  32. lightning_sdk/lightning_cloud/openapi/api/projects_service_api.py +1 -5
  33. lightning_sdk/lightning_cloud/openapi/models/__init__.py +4 -0
  34. lightning_sdk/lightning_cloud/openapi/models/id_reportrestarttimings_body.py +123 -0
  35. lightning_sdk/lightning_cloud/openapi/models/project_id_litregistry_body.py +2 -0
  36. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_accelerator.py +27 -1
  37. lightning_sdk/lightning_cloud/openapi/models/v1_get_cluster_accelerator_demand_response.py +123 -0
  38. lightning_sdk/lightning_cloud/openapi/models/v1_job.py +27 -1
  39. lightning_sdk/lightning_cloud/openapi/models/v1_lit_registry_artifact.py +27 -1
  40. lightning_sdk/lightning_cloud/openapi/models/v1_lit_registry_project.py +8 -0
  41. lightning_sdk/lightning_cloud/openapi/models/v1_lit_repository.py +27 -1
  42. lightning_sdk/lightning_cloud/openapi/models/v1_report_restart_timings_response.py +97 -0
  43. lightning_sdk/lightning_cloud/openapi/models/v1_restart_timing.py +175 -0
  44. lightning_sdk/lightning_cloud/openapi/models/v1_validate_deployment_image_request.py +27 -1
  45. lightning_sdk/machine.py +59 -27
  46. lightning_sdk/studio.py +5 -1
  47. lightning_sdk/teamspace.py +25 -0
  48. {lightning_sdk-0.1.55.dist-info → lightning_sdk-0.1.56.dist-info}/METADATA +2 -1
  49. {lightning_sdk-0.1.55.dist-info → lightning_sdk-0.1.56.dist-info}/RECORD +53 -47
  50. {lightning_sdk-0.1.55.dist-info → lightning_sdk-0.1.56.dist-info}/LICENSE +0 -0
  51. {lightning_sdk-0.1.55.dist-info → lightning_sdk-0.1.56.dist-info}/WHEEL +0 -0
  52. {lightning_sdk-0.1.55.dist-info → lightning_sdk-0.1.56.dist-info}/entry_points.txt +0 -0
  53. {lightning_sdk-0.1.55.dist-info → lightning_sdk-0.1.56.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,97 @@
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 V1ReportRestartTimingsResponse(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
+ Attributes:
38
+ swagger_types (dict): The key is attribute name
39
+ and the value is attribute type.
40
+ attribute_map (dict): The key is attribute name
41
+ and the value is json key in definition.
42
+ """
43
+ swagger_types = {
44
+ }
45
+
46
+ attribute_map = {
47
+ }
48
+
49
+ def __init__(self): # noqa: E501
50
+ """V1ReportRestartTimingsResponse - a model defined in Swagger""" # noqa: E501
51
+ self.discriminator = None
52
+
53
+ def to_dict(self) -> dict:
54
+ """Returns the model properties as a dict"""
55
+ result = {}
56
+
57
+ for attr, _ in six.iteritems(self.swagger_types):
58
+ value = getattr(self, attr)
59
+ if isinstance(value, list):
60
+ result[attr] = list(map(
61
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
62
+ value
63
+ ))
64
+ elif hasattr(value, "to_dict"):
65
+ result[attr] = value.to_dict()
66
+ elif isinstance(value, dict):
67
+ result[attr] = dict(map(
68
+ lambda item: (item[0], item[1].to_dict())
69
+ if hasattr(item[1], "to_dict") else item,
70
+ value.items()
71
+ ))
72
+ else:
73
+ result[attr] = value
74
+ if issubclass(V1ReportRestartTimingsResponse, dict):
75
+ for key, value in self.items():
76
+ result[key] = value
77
+
78
+ return result
79
+
80
+ def to_str(self) -> str:
81
+ """Returns the string representation of the model"""
82
+ return pprint.pformat(self.to_dict())
83
+
84
+ def __repr__(self) -> str:
85
+ """For `print` and `pprint`"""
86
+ return self.to_str()
87
+
88
+ def __eq__(self, other: 'V1ReportRestartTimingsResponse') -> bool:
89
+ """Returns true if both objects are equal"""
90
+ if not isinstance(other, V1ReportRestartTimingsResponse):
91
+ return False
92
+
93
+ return self.__dict__ == other.__dict__
94
+
95
+ def __ne__(self, other: 'V1ReportRestartTimingsResponse') -> bool:
96
+ """Returns true if both objects are not equal"""
97
+ return not self == other
@@ -0,0 +1,175 @@
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 V1RestartTiming(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
+ Attributes:
38
+ swagger_types (dict): The key is attribute name
39
+ and the value is attribute type.
40
+ attribute_map (dict): The key is attribute name
41
+ and the value is json key in definition.
42
+ """
43
+ swagger_types = {
44
+ 'counter': 'int',
45
+ 'end': 'datetime',
46
+ 'start': 'datetime'
47
+ }
48
+
49
+ attribute_map = {
50
+ 'counter': 'counter',
51
+ 'end': 'end',
52
+ 'start': 'start'
53
+ }
54
+
55
+ def __init__(self, counter: 'int' =None, end: 'datetime' =None, start: 'datetime' =None): # noqa: E501
56
+ """V1RestartTiming - a model defined in Swagger""" # noqa: E501
57
+ self._counter = None
58
+ self._end = None
59
+ self._start = None
60
+ self.discriminator = None
61
+ if counter is not None:
62
+ self.counter = counter
63
+ if end is not None:
64
+ self.end = end
65
+ if start is not None:
66
+ self.start = start
67
+
68
+ @property
69
+ def counter(self) -> 'int':
70
+ """Gets the counter of this V1RestartTiming. # noqa: E501
71
+
72
+
73
+ :return: The counter of this V1RestartTiming. # noqa: E501
74
+ :rtype: int
75
+ """
76
+ return self._counter
77
+
78
+ @counter.setter
79
+ def counter(self, counter: 'int'):
80
+ """Sets the counter of this V1RestartTiming.
81
+
82
+
83
+ :param counter: The counter of this V1RestartTiming. # noqa: E501
84
+ :type: int
85
+ """
86
+
87
+ self._counter = counter
88
+
89
+ @property
90
+ def end(self) -> 'datetime':
91
+ """Gets the end of this V1RestartTiming. # noqa: E501
92
+
93
+
94
+ :return: The end of this V1RestartTiming. # noqa: E501
95
+ :rtype: datetime
96
+ """
97
+ return self._end
98
+
99
+ @end.setter
100
+ def end(self, end: 'datetime'):
101
+ """Sets the end of this V1RestartTiming.
102
+
103
+
104
+ :param end: The end of this V1RestartTiming. # noqa: E501
105
+ :type: datetime
106
+ """
107
+
108
+ self._end = end
109
+
110
+ @property
111
+ def start(self) -> 'datetime':
112
+ """Gets the start of this V1RestartTiming. # noqa: E501
113
+
114
+
115
+ :return: The start of this V1RestartTiming. # noqa: E501
116
+ :rtype: datetime
117
+ """
118
+ return self._start
119
+
120
+ @start.setter
121
+ def start(self, start: 'datetime'):
122
+ """Sets the start of this V1RestartTiming.
123
+
124
+
125
+ :param start: The start of this V1RestartTiming. # noqa: E501
126
+ :type: datetime
127
+ """
128
+
129
+ self._start = start
130
+
131
+ def to_dict(self) -> dict:
132
+ """Returns the model properties as a dict"""
133
+ result = {}
134
+
135
+ for attr, _ in six.iteritems(self.swagger_types):
136
+ value = getattr(self, attr)
137
+ if isinstance(value, list):
138
+ result[attr] = list(map(
139
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
140
+ value
141
+ ))
142
+ elif hasattr(value, "to_dict"):
143
+ result[attr] = value.to_dict()
144
+ elif isinstance(value, dict):
145
+ result[attr] = dict(map(
146
+ lambda item: (item[0], item[1].to_dict())
147
+ if hasattr(item[1], "to_dict") else item,
148
+ value.items()
149
+ ))
150
+ else:
151
+ result[attr] = value
152
+ if issubclass(V1RestartTiming, dict):
153
+ for key, value in self.items():
154
+ result[key] = value
155
+
156
+ return result
157
+
158
+ def to_str(self) -> str:
159
+ """Returns the string representation of the model"""
160
+ return pprint.pformat(self.to_dict())
161
+
162
+ def __repr__(self) -> str:
163
+ """For `print` and `pprint`"""
164
+ return self.to_str()
165
+
166
+ def __eq__(self, other: 'V1RestartTiming') -> bool:
167
+ """Returns true if both objects are equal"""
168
+ if not isinstance(other, V1RestartTiming):
169
+ return False
170
+
171
+ return self.__dict__ == other.__dict__
172
+
173
+ def __ne__(self, other: 'V1RestartTiming') -> bool:
174
+ """Returns true if both objects are not equal"""
175
+ return not self == other
@@ -42,21 +42,26 @@ class V1ValidateDeploymentImageRequest(object):
42
42
  """
43
43
  swagger_types = {
44
44
  'image': 'str',
45
+ 'project_id': 'str',
45
46
  'secret': 'str'
46
47
  }
47
48
 
48
49
  attribute_map = {
49
50
  'image': 'image',
51
+ 'project_id': 'projectId',
50
52
  'secret': 'secret'
51
53
  }
52
54
 
53
- def __init__(self, image: 'str' =None, secret: 'str' =None): # noqa: E501
55
+ def __init__(self, image: 'str' =None, project_id: 'str' =None, secret: 'str' =None): # noqa: E501
54
56
  """V1ValidateDeploymentImageRequest - a model defined in Swagger""" # noqa: E501
55
57
  self._image = None
58
+ self._project_id = None
56
59
  self._secret = None
57
60
  self.discriminator = None
58
61
  if image is not None:
59
62
  self.image = image
63
+ if project_id is not None:
64
+ self.project_id = project_id
60
65
  if secret is not None:
61
66
  self.secret = secret
62
67
 
@@ -81,6 +86,27 @@ class V1ValidateDeploymentImageRequest(object):
81
86
 
82
87
  self._image = image
83
88
 
89
+ @property
90
+ def project_id(self) -> 'str':
91
+ """Gets the project_id of this V1ValidateDeploymentImageRequest. # noqa: E501
92
+
93
+
94
+ :return: The project_id of this V1ValidateDeploymentImageRequest. # noqa: E501
95
+ :rtype: str
96
+ """
97
+ return self._project_id
98
+
99
+ @project_id.setter
100
+ def project_id(self, project_id: 'str'):
101
+ """Sets the project_id of this V1ValidateDeploymentImageRequest.
102
+
103
+
104
+ :param project_id: The project_id of this V1ValidateDeploymentImageRequest. # noqa: E501
105
+ :type: str
106
+ """
107
+
108
+ self._project_id = project_id
109
+
84
110
  @property
85
111
  def secret(self) -> 'str':
86
112
  """Gets the secret of this V1ValidateDeploymentImageRequest. # noqa: E501
lightning_sdk/machine.py CHANGED
@@ -1,32 +1,64 @@
1
- from lightning_sdk.utils.enum import DeprecationEnum
1
+ from dataclasses import dataclass
2
+ from typing import ClassVar, Optional
2
3
 
3
4
 
4
- class Machine(DeprecationEnum):
5
- """Enum holding all supported machine types for studios."""
5
+ @dataclass(frozen=True)
6
+ class Machine:
7
+ # Default Machines
8
+ CPU_SMALL: ClassVar["Machine"]
9
+ CPU: ClassVar["Machine"]
10
+ DATA_PREP: ClassVar["Machine"]
11
+ DATA_PREP_MAX: ClassVar["Machine"]
12
+ DATA_PREP_ULTRA: ClassVar["Machine"]
13
+ T4: ClassVar["Machine"]
14
+ T4_X_4: ClassVar["Machine"]
15
+ L4: ClassVar["Machine"]
16
+ L4_X_4: ClassVar["Machine"]
17
+ L4_X_8: ClassVar["Machine"]
18
+ A10G: ClassVar["Machine"]
19
+ A10G_X_4: ClassVar["Machine"]
20
+ A10G_X_8: ClassVar["Machine"]
21
+ L40S: ClassVar["Machine"]
22
+ L40S_X_4: ClassVar["Machine"]
23
+ L40S_X_8: ClassVar["Machine"]
24
+ A100_X_8: ClassVar["Machine"]
25
+ H100_X_8: ClassVar["Machine"]
26
+ H200_X_8: ClassVar["Machine"]
6
27
 
7
- CPU_SMALL = "CPU_SMALL"
8
- CPU = "CPU"
9
- DATA_PREP = "DATA_PREP"
10
- DATA_PREP_MAX = "DATA_PREP_MAX"
11
- DATA_PREP_ULTRA = "DATA_PREP_ULTRA"
12
- T4 = "T4"
13
- T4_X_4 = "T4_X_4"
14
- L4 = "L4"
15
- L4_X_4 = "L4_X_4"
16
- L4_X_8 = "L4_X_8"
17
- A10G = "A10G"
18
- A10G_X_4 = "A10G_X_4"
19
- A10G_X_8 = "A10G_X_8"
20
- L40S = "L40S"
21
- L40 = "L40", "L40S" # deprecated
22
- L40S_X_4 = "L40S_X_4"
23
- L40_X_4 = "L40_X_4", "L40S_X_4" # deprecated
24
- L40S_X_8 = "L40S_X_8"
25
- L40_X_8 = "L40_X_8", "L40S_X_8" # deprecated
26
- A100_X_8 = "A100_X_8"
27
- H100_X_8 = "H100_X_8"
28
- H200_X_8 = "H200_X_8"
28
+ name: str
29
+ instance_type: str
30
+ cost: Optional[float] = None
31
+ interruptible_cost: Optional[float] = None
32
+ wait_time: Optional[float] = None
33
+ interruptible_wait_time: Optional[float] = None
29
34
 
30
35
  def __str__(self) -> str:
31
- """String representation of the enum."""
32
- return str(self.value)
36
+ """String representation of the Machine."""
37
+ return str(self.name) if self.name else str(self.instance_type)
38
+
39
+ def __eq__(self, other: object) -> bool:
40
+ """Machines are equal if the instance type is equal."""
41
+ if isinstance(other, Machine):
42
+ return self.instance_type == other.instance_type
43
+ return False
44
+
45
+
46
+ Machine.CPU_SMALL = Machine(name="CPU_SMALL", instance_type="m3.medium")
47
+ Machine.CPU = Machine(name="CPU", instance_type="cpu-4")
48
+ Machine.DATA_PREP = Machine(name="DATA_PREP", instance_type="data-large")
49
+ Machine.DATA_PREP_MAX = Machine(name="DATA_PREP_MAX", instance_type="data-max")
50
+ Machine.DATA_PREP_ULTRA = Machine(name="DATA_PREP_ULTRA", instance_type="data-ultra")
51
+ Machine.T4 = Machine(name="T4", instance_type="g4dn.2xlarge")
52
+ Machine.T4_X_4 = Machine(name="T4_X_4", instance_type="g4dn.12xlarge")
53
+ Machine.L4 = Machine(name="L4", instance_type="g6.4xlarge")
54
+ Machine.L4_X_4 = Machine(name="L4_X_4", instance_type="g6.12xlarge")
55
+ Machine.L4_X_8 = Machine(name="L4_X_8", instance_type="g6.48xlarge")
56
+ Machine.A10G = Machine(name="A10G", instance_type="g5.8xlarge")
57
+ Machine.A10G_X_4 = Machine(name="A10G_X_4", instance_type="g5.12xlarge")
58
+ Machine.A10G_X_8 = Machine(name="A10G_X_8", instance_type="g5.48xlarge")
59
+ Machine.L40S = Machine(name="L40S", instance_type="g6e.4xlarge")
60
+ Machine.L40S_X_4 = Machine(name="L40S_X_4", instance_type="g6e.12xlarge")
61
+ Machine.L40S_X_8 = Machine(name="L40S_X_8", instance_type="g6e.48xlarge")
62
+ Machine.A100_X_8 = Machine(name="A100_X_8", instance_type="p4d.24xlarge")
63
+ Machine.H100_X_8 = Machine(name="H100_X_8", instance_type="p5.48xlarge")
64
+ Machine.H200_X_8 = Machine(name="H200_X_8", instance_type="p5e.48xlarge")
lightning_sdk/studio.py CHANGED
@@ -155,9 +155,13 @@ class Studio:
155
155
  def cloud_account(self) -> str:
156
156
  return self._studio.cluster_id
157
157
 
158
- def start(self, machine: Union[Machine, str] = Machine.CPU, interruptible: bool = False) -> None:
158
+ def start(self, machine: Union[Machine, str] = Machine.CPU, interruptible: Optional[bool] = None) -> None:
159
159
  """Starts a Studio on the specified machine type (default: CPU-4)."""
160
160
  status = self.status
161
+
162
+ if interruptible is None:
163
+ interruptible = self.teamspace.start_studions_on_interruptible
164
+
161
165
  if status == Status.Running:
162
166
  curr_machine = _machine_to_compute_name(self.machine) if self.machine is not None else None
163
167
  if curr_machine != _machine_to_compute_name(machine):
@@ -1,9 +1,11 @@
1
+ import os
1
2
  import warnings
2
3
  from pathlib import Path
3
4
  from typing import TYPE_CHECKING, List, Optional, Tuple, Union
4
5
 
5
6
  from lightning_sdk.agents import Agent
6
7
  from lightning_sdk.api import TeamspaceApi
8
+ from lightning_sdk.machine import Machine
7
9
  from lightning_sdk.models import UploadedModelInfo
8
10
  from lightning_sdk.organization import Organization
9
11
  from lightning_sdk.owner import Owner
@@ -112,6 +114,10 @@ class Teamspace:
112
114
  def default_cloud_account(self) -> str:
113
115
  return self._teamspace.project_settings.preferred_cluster
114
116
 
117
+ @property
118
+ def start_studions_on_interruptible(self) -> bool:
119
+ return self._teamspace.project_settings.start_studio_on_spot_instance
120
+
115
121
  @property
116
122
  def cloud_accounts(self) -> List[str]:
117
123
  """All cloud accounts associated with that teamspace."""
@@ -176,6 +182,25 @@ class Teamspace:
176
182
 
177
183
  return tuple(mmts)
178
184
 
185
+ def list_machines(self, cloud_account: Optional[str] = None) -> List[Machine]:
186
+ if cloud_account is None:
187
+ cloud_account = os.getenv("LIGHTNING_CLUSTER_ID") or self.default_cloud_account
188
+
189
+ cluster_machines = self._teamspace_api.list_machines(self.id, cloud_account=cloud_account)
190
+ return [
191
+ Machine(
192
+ cluster_machine.instance_id,
193
+ cluster_machine.instance_id,
194
+ cost=cluster_machine.cost,
195
+ interruptible_cost=cluster_machine.spot_price,
196
+ wait_time=float(cluster_machine.available_in_seconds) if cluster_machine.available_in_seconds else None,
197
+ interruptible_wait_time=float(cluster_machine.available_in_seconds_spot)
198
+ if cluster_machine.available_in_seconds_spot
199
+ else None,
200
+ )
201
+ for cluster_machine in cluster_machines
202
+ ]
203
+
179
204
  def __eq__(self, other: "Teamspace") -> bool:
180
205
  """Checks whether the provided other object is equal to this one."""
181
206
  return (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.1.55
3
+ Version: 0.1.56
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License
@@ -46,6 +46,7 @@ Requires-Dist: fire
46
46
  Requires-Dist: simple-term-menu
47
47
  Requires-Dist: lightning-utilities
48
48
  Requires-Dist: docker
49
+ Requires-Dist: wget
49
50
  Provides-Extra: serve
50
51
  Requires-Dist: litserve>=0.2.5; extra == "serve"
51
52