lightning-sdk 0.2.0__py3-none-any.whl → 0.2.2__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 (23) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/api/lit_container_api.py +16 -0
  3. lightning_sdk/cli/docker.py +3 -58
  4. lightning_sdk/cli/download.py +28 -24
  5. lightning_sdk/cli/serve.py +17 -53
  6. lightning_sdk/lightning_cloud/openapi/__init__.py +2 -0
  7. lightning_sdk/lightning_cloud/openapi/api/pipelines_service_api.py +5 -1
  8. lightning_sdk/lightning_cloud/openapi/models/__init__.py +2 -0
  9. lightning_sdk/lightning_cloud/openapi/models/pipelines_id_body.py +41 -15
  10. lightning_sdk/lightning_cloud/openapi/models/project_id_pipelines_body.py +27 -1
  11. lightning_sdk/lightning_cloud/openapi/models/v1_filesystem_job.py +27 -1
  12. lightning_sdk/lightning_cloud/openapi/models/v1_filesystem_mmt.py +27 -1
  13. lightning_sdk/lightning_cloud/openapi/models/v1_job_artifacts_type.py +103 -0
  14. lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +53 -1
  15. lightning_sdk/lightning_cloud/openapi/models/v1_pipeline.py +41 -15
  16. lightning_sdk/lightning_cloud/openapi/models/v1_pipeline_schedule.py +149 -0
  17. lightning_sdk/serve.py +134 -0
  18. {lightning_sdk-0.2.0.dist-info → lightning_sdk-0.2.2.dist-info}/METADATA +1 -1
  19. {lightning_sdk-0.2.0.dist-info → lightning_sdk-0.2.2.dist-info}/RECORD +23 -20
  20. {lightning_sdk-0.2.0.dist-info → lightning_sdk-0.2.2.dist-info}/LICENSE +0 -0
  21. {lightning_sdk-0.2.0.dist-info → lightning_sdk-0.2.2.dist-info}/WHEEL +0 -0
  22. {lightning_sdk-0.2.0.dist-info → lightning_sdk-0.2.2.dist-info}/entry_points.txt +0 -0
  23. {lightning_sdk-0.2.0.dist-info → lightning_sdk-0.2.2.dist-info}/top_level.txt +0 -0
@@ -41,6 +41,7 @@ class V1FilesystemMMT(object):
41
41
  and the value is json key in definition.
42
42
  """
43
43
  swagger_types = {
44
+ 'artifacts_type': 'V1JobArtifactsType',
44
45
  'cloud_space_id': 'str',
45
46
  'id': 'str',
46
47
  'jobs': 'list[V1FilesystemJob]',
@@ -48,19 +49,23 @@ class V1FilesystemMMT(object):
48
49
  }
49
50
 
50
51
  attribute_map = {
52
+ 'artifacts_type': 'artifactsType',
51
53
  'cloud_space_id': 'cloudSpaceId',
52
54
  'id': 'id',
53
55
  'jobs': 'jobs',
54
56
  'name': 'name'
55
57
  }
56
58
 
57
- def __init__(self, cloud_space_id: 'str' =None, id: 'str' =None, jobs: 'list[V1FilesystemJob]' =None, name: 'str' =None): # noqa: E501
59
+ def __init__(self, artifacts_type: 'V1JobArtifactsType' =None, cloud_space_id: 'str' =None, id: 'str' =None, jobs: 'list[V1FilesystemJob]' =None, name: 'str' =None): # noqa: E501
58
60
  """V1FilesystemMMT - a model defined in Swagger""" # noqa: E501
61
+ self._artifacts_type = None
59
62
  self._cloud_space_id = None
60
63
  self._id = None
61
64
  self._jobs = None
62
65
  self._name = None
63
66
  self.discriminator = None
67
+ if artifacts_type is not None:
68
+ self.artifacts_type = artifacts_type
64
69
  if cloud_space_id is not None:
65
70
  self.cloud_space_id = cloud_space_id
66
71
  if id is not None:
@@ -70,6 +75,27 @@ class V1FilesystemMMT(object):
70
75
  if name is not None:
71
76
  self.name = name
72
77
 
78
+ @property
79
+ def artifacts_type(self) -> 'V1JobArtifactsType':
80
+ """Gets the artifacts_type of this V1FilesystemMMT. # noqa: E501
81
+
82
+
83
+ :return: The artifacts_type of this V1FilesystemMMT. # noqa: E501
84
+ :rtype: V1JobArtifactsType
85
+ """
86
+ return self._artifacts_type
87
+
88
+ @artifacts_type.setter
89
+ def artifacts_type(self, artifacts_type: 'V1JobArtifactsType'):
90
+ """Sets the artifacts_type of this V1FilesystemMMT.
91
+
92
+
93
+ :param artifacts_type: The artifacts_type of this V1FilesystemMMT. # noqa: E501
94
+ :type: V1JobArtifactsType
95
+ """
96
+
97
+ self._artifacts_type = artifacts_type
98
+
73
99
  @property
74
100
  def cloud_space_id(self) -> 'str':
75
101
  """Gets the cloud_space_id of this V1FilesystemMMT. # noqa: E501
@@ -0,0 +1,103 @@
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 V1JobArtifactsType(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
+ V1 = "V1"
41
+ V2 = "V2"
42
+ """
43
+ Attributes:
44
+ swagger_types (dict): The key is attribute name
45
+ and the value is attribute type.
46
+ attribute_map (dict): The key is attribute name
47
+ and the value is json key in definition.
48
+ """
49
+ swagger_types = {
50
+ }
51
+
52
+ attribute_map = {
53
+ }
54
+
55
+ def __init__(self): # noqa: E501
56
+ """V1JobArtifactsType - a model defined in Swagger""" # noqa: E501
57
+ self.discriminator = None
58
+
59
+ def to_dict(self) -> dict:
60
+ """Returns the model properties as a dict"""
61
+ result = {}
62
+
63
+ for attr, _ in six.iteritems(self.swagger_types):
64
+ value = getattr(self, attr)
65
+ if isinstance(value, list):
66
+ result[attr] = list(map(
67
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
68
+ value
69
+ ))
70
+ elif hasattr(value, "to_dict"):
71
+ result[attr] = value.to_dict()
72
+ elif isinstance(value, dict):
73
+ result[attr] = dict(map(
74
+ lambda item: (item[0], item[1].to_dict())
75
+ if hasattr(item[1], "to_dict") else item,
76
+ value.items()
77
+ ))
78
+ else:
79
+ result[attr] = value
80
+ if issubclass(V1JobArtifactsType, dict):
81
+ for key, value in self.items():
82
+ result[key] = value
83
+
84
+ return result
85
+
86
+ def to_str(self) -> str:
87
+ """Returns the string representation of the model"""
88
+ return pprint.pformat(self.to_dict())
89
+
90
+ def __repr__(self) -> str:
91
+ """For `print` and `pprint`"""
92
+ return self.to_str()
93
+
94
+ def __eq__(self, other: 'V1JobArtifactsType') -> bool:
95
+ """Returns true if both objects are equal"""
96
+ if not isinstance(other, V1JobArtifactsType):
97
+ return False
98
+
99
+ return self.__dict__ == other.__dict__
100
+
101
+ def __ne__(self, other: 'V1JobArtifactsType') -> bool:
102
+ """Returns true if both objects are not equal"""
103
+ return not self == other
@@ -57,6 +57,8 @@ class V1Organization(object):
57
57
  'domain': 'str',
58
58
  'email': 'str',
59
59
  'featured_gallery': 'bool',
60
+ 'full_story_end_date': 'datetime',
61
+ 'full_story_start_date': 'datetime',
60
62
  'id': 'str',
61
63
  'location': 'str',
62
64
  'name': 'str',
@@ -86,6 +88,8 @@ class V1Organization(object):
86
88
  'domain': 'domain',
87
89
  'email': 'email',
88
90
  'featured_gallery': 'featuredGallery',
91
+ 'full_story_end_date': 'fullStoryEndDate',
92
+ 'full_story_start_date': 'fullStoryStartDate',
89
93
  'id': 'id',
90
94
  'location': 'location',
91
95
  'name': 'name',
@@ -98,7 +102,7 @@ class V1Organization(object):
98
102
  'updated_at': 'updatedAt'
99
103
  }
100
104
 
101
- def __init__(self, allow_aws_saas: 'bool' =None, allow_gcp_saas: 'bool' =None, allow_guest: 'bool' =None, allow_lambda_saas: 'bool' =None, allow_member_invitations: 'bool' =None, allow_member_teamspace_creation: 'bool' =None, allow_vultr_saas: 'bool' =None, auto_invite_by_domain: 'bool' =None, auto_join_domain_validations: 'dict(str, V1AutoJoinDomainValidation)' =None, auto_join_domains: 'list[str]' =None, created_at: 'datetime' =None, description: 'str' =None, display_name: 'str' =None, domain: 'str' =None, email: 'str' =None, featured_gallery: 'bool' =None, id: 'str' =None, location: 'str' =None, name: 'str' =None, preferred_cluster: 'str' =None, preferred_deployment_provider: 'str' =None, preferred_studio_provider: 'str' =None, start_studios_on_spot_instance: 'bool' =None, teamspace_default_credits: 'float' =None, twitter_username: 'str' =None, updated_at: 'datetime' =None): # noqa: E501
105
+ def __init__(self, allow_aws_saas: 'bool' =None, allow_gcp_saas: 'bool' =None, allow_guest: 'bool' =None, allow_lambda_saas: 'bool' =None, allow_member_invitations: 'bool' =None, allow_member_teamspace_creation: 'bool' =None, allow_vultr_saas: 'bool' =None, auto_invite_by_domain: 'bool' =None, auto_join_domain_validations: 'dict(str, V1AutoJoinDomainValidation)' =None, auto_join_domains: 'list[str]' =None, created_at: 'datetime' =None, description: 'str' =None, display_name: 'str' =None, domain: 'str' =None, email: 'str' =None, featured_gallery: 'bool' =None, full_story_end_date: 'datetime' =None, full_story_start_date: 'datetime' =None, id: 'str' =None, location: 'str' =None, name: 'str' =None, preferred_cluster: 'str' =None, preferred_deployment_provider: 'str' =None, preferred_studio_provider: 'str' =None, start_studios_on_spot_instance: 'bool' =None, teamspace_default_credits: 'float' =None, twitter_username: 'str' =None, updated_at: 'datetime' =None): # noqa: E501
102
106
  """V1Organization - a model defined in Swagger""" # noqa: E501
103
107
  self._allow_aws_saas = None
104
108
  self._allow_gcp_saas = None
@@ -116,6 +120,8 @@ class V1Organization(object):
116
120
  self._domain = None
117
121
  self._email = None
118
122
  self._featured_gallery = None
123
+ self._full_story_end_date = None
124
+ self._full_story_start_date = None
119
125
  self._id = None
120
126
  self._location = None
121
127
  self._name = None
@@ -159,6 +165,10 @@ class V1Organization(object):
159
165
  self.email = email
160
166
  if featured_gallery is not None:
161
167
  self.featured_gallery = featured_gallery
168
+ if full_story_end_date is not None:
169
+ self.full_story_end_date = full_story_end_date
170
+ if full_story_start_date is not None:
171
+ self.full_story_start_date = full_story_start_date
162
172
  if id is not None:
163
173
  self.id = id
164
174
  if location is not None:
@@ -516,6 +526,48 @@ class V1Organization(object):
516
526
 
517
527
  self._featured_gallery = featured_gallery
518
528
 
529
+ @property
530
+ def full_story_end_date(self) -> 'datetime':
531
+ """Gets the full_story_end_date of this V1Organization. # noqa: E501
532
+
533
+
534
+ :return: The full_story_end_date of this V1Organization. # noqa: E501
535
+ :rtype: datetime
536
+ """
537
+ return self._full_story_end_date
538
+
539
+ @full_story_end_date.setter
540
+ def full_story_end_date(self, full_story_end_date: 'datetime'):
541
+ """Sets the full_story_end_date of this V1Organization.
542
+
543
+
544
+ :param full_story_end_date: The full_story_end_date of this V1Organization. # noqa: E501
545
+ :type: datetime
546
+ """
547
+
548
+ self._full_story_end_date = full_story_end_date
549
+
550
+ @property
551
+ def full_story_start_date(self) -> 'datetime':
552
+ """Gets the full_story_start_date of this V1Organization. # noqa: E501
553
+
554
+
555
+ :return: The full_story_start_date of this V1Organization. # noqa: E501
556
+ :rtype: datetime
557
+ """
558
+ return self._full_story_start_date
559
+
560
+ @full_story_start_date.setter
561
+ def full_story_start_date(self, full_story_start_date: 'datetime'):
562
+ """Sets the full_story_start_date of this V1Organization.
563
+
564
+
565
+ :param full_story_start_date: The full_story_start_date of this V1Organization. # noqa: E501
566
+ :type: datetime
567
+ """
568
+
569
+ self._full_story_start_date = full_story_start_date
570
+
519
571
  @property
520
572
  def id(self) -> 'str':
521
573
  """Gets the id of this V1Organization. # noqa: E501
@@ -48,8 +48,9 @@ class V1Pipeline(object):
48
48
  'id': 'str',
49
49
  'message': 'str',
50
50
  'name': 'str',
51
- 'parent_id': 'str',
51
+ 'parent_pipeline_id': 'str',
52
52
  'project_id': 'str',
53
+ 'schedules': 'list[V1PipelineSchedule]',
53
54
  'shared_filesystem': 'V1SharedFilesystem',
54
55
  'state': 'str',
55
56
  'statuses': 'list[V1PipelineStepStatus]',
@@ -66,8 +67,9 @@ class V1Pipeline(object):
66
67
  'id': 'id',
67
68
  'message': 'message',
68
69
  'name': 'name',
69
- 'parent_id': 'parentId',
70
+ 'parent_pipeline_id': 'parentPipelineId',
70
71
  'project_id': 'projectId',
72
+ 'schedules': 'schedules',
71
73
  'shared_filesystem': 'sharedFilesystem',
72
74
  'state': 'state',
73
75
  'statuses': 'statuses',
@@ -76,7 +78,7 @@ class V1Pipeline(object):
76
78
  'user_id': 'userId'
77
79
  }
78
80
 
79
- def __init__(self, cluster_id: 'str' =None, created_at: 'datetime' =None, display_name: 'str' =None, error: 'str' =None, id: 'str' =None, message: 'str' =None, name: 'str' =None, parent_id: 'str' =None, project_id: 'str' =None, shared_filesystem: 'V1SharedFilesystem' =None, state: 'str' =None, statuses: 'list[V1PipelineStepStatus]' =None, steps: 'list[V1PipelineStep]' =None, updated_at: 'datetime' =None, user_id: 'str' =None): # noqa: E501
81
+ def __init__(self, cluster_id: 'str' =None, created_at: 'datetime' =None, display_name: 'str' =None, error: 'str' =None, id: 'str' =None, message: 'str' =None, name: 'str' =None, parent_pipeline_id: 'str' =None, project_id: 'str' =None, schedules: 'list[V1PipelineSchedule]' =None, shared_filesystem: 'V1SharedFilesystem' =None, state: 'str' =None, statuses: 'list[V1PipelineStepStatus]' =None, steps: 'list[V1PipelineStep]' =None, updated_at: 'datetime' =None, user_id: 'str' =None): # noqa: E501
80
82
  """V1Pipeline - a model defined in Swagger""" # noqa: E501
81
83
  self._cluster_id = None
82
84
  self._created_at = None
@@ -85,8 +87,9 @@ class V1Pipeline(object):
85
87
  self._id = None
86
88
  self._message = None
87
89
  self._name = None
88
- self._parent_id = None
90
+ self._parent_pipeline_id = None
89
91
  self._project_id = None
92
+ self._schedules = None
90
93
  self._shared_filesystem = None
91
94
  self._state = None
92
95
  self._statuses = None
@@ -108,10 +111,12 @@ class V1Pipeline(object):
108
111
  self.message = message
109
112
  if name is not None:
110
113
  self.name = name
111
- if parent_id is not None:
112
- self.parent_id = parent_id
114
+ if parent_pipeline_id is not None:
115
+ self.parent_pipeline_id = parent_pipeline_id
113
116
  if project_id is not None:
114
117
  self.project_id = project_id
118
+ if schedules is not None:
119
+ self.schedules = schedules
115
120
  if shared_filesystem is not None:
116
121
  self.shared_filesystem = shared_filesystem
117
122
  if state is not None:
@@ -273,25 +278,25 @@ class V1Pipeline(object):
273
278
  self._name = name
274
279
 
275
280
  @property
276
- def parent_id(self) -> 'str':
277
- """Gets the parent_id of this V1Pipeline. # noqa: E501
281
+ def parent_pipeline_id(self) -> 'str':
282
+ """Gets the parent_pipeline_id of this V1Pipeline. # noqa: E501
278
283
 
279
284
 
280
- :return: The parent_id of this V1Pipeline. # noqa: E501
285
+ :return: The parent_pipeline_id of this V1Pipeline. # noqa: E501
281
286
  :rtype: str
282
287
  """
283
- return self._parent_id
288
+ return self._parent_pipeline_id
284
289
 
285
- @parent_id.setter
286
- def parent_id(self, parent_id: 'str'):
287
- """Sets the parent_id of this V1Pipeline.
290
+ @parent_pipeline_id.setter
291
+ def parent_pipeline_id(self, parent_pipeline_id: 'str'):
292
+ """Sets the parent_pipeline_id of this V1Pipeline.
288
293
 
289
294
 
290
- :param parent_id: The parent_id of this V1Pipeline. # noqa: E501
295
+ :param parent_pipeline_id: The parent_pipeline_id of this V1Pipeline. # noqa: E501
291
296
  :type: str
292
297
  """
293
298
 
294
- self._parent_id = parent_id
299
+ self._parent_pipeline_id = parent_pipeline_id
295
300
 
296
301
  @property
297
302
  def project_id(self) -> 'str':
@@ -314,6 +319,27 @@ class V1Pipeline(object):
314
319
 
315
320
  self._project_id = project_id
316
321
 
322
+ @property
323
+ def schedules(self) -> 'list[V1PipelineSchedule]':
324
+ """Gets the schedules of this V1Pipeline. # noqa: E501
325
+
326
+
327
+ :return: The schedules of this V1Pipeline. # noqa: E501
328
+ :rtype: list[V1PipelineSchedule]
329
+ """
330
+ return self._schedules
331
+
332
+ @schedules.setter
333
+ def schedules(self, schedules: 'list[V1PipelineSchedule]'):
334
+ """Sets the schedules of this V1Pipeline.
335
+
336
+
337
+ :param schedules: The schedules of this V1Pipeline. # noqa: E501
338
+ :type: list[V1PipelineSchedule]
339
+ """
340
+
341
+ self._schedules = schedules
342
+
317
343
  @property
318
344
  def shared_filesystem(self) -> 'V1SharedFilesystem':
319
345
  """Gets the shared_filesystem of this V1Pipeline. # noqa: E501
@@ -0,0 +1,149 @@
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 V1PipelineSchedule(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
+ 'cron_expression': 'str',
45
+ 'id': 'str'
46
+ }
47
+
48
+ attribute_map = {
49
+ 'cron_expression': 'cronExpression',
50
+ 'id': 'id'
51
+ }
52
+
53
+ def __init__(self, cron_expression: 'str' =None, id: 'str' =None): # noqa: E501
54
+ """V1PipelineSchedule - a model defined in Swagger""" # noqa: E501
55
+ self._cron_expression = None
56
+ self._id = None
57
+ self.discriminator = None
58
+ if cron_expression is not None:
59
+ self.cron_expression = cron_expression
60
+ if id is not None:
61
+ self.id = id
62
+
63
+ @property
64
+ def cron_expression(self) -> 'str':
65
+ """Gets the cron_expression of this V1PipelineSchedule. # noqa: E501
66
+
67
+
68
+ :return: The cron_expression of this V1PipelineSchedule. # noqa: E501
69
+ :rtype: str
70
+ """
71
+ return self._cron_expression
72
+
73
+ @cron_expression.setter
74
+ def cron_expression(self, cron_expression: 'str'):
75
+ """Sets the cron_expression of this V1PipelineSchedule.
76
+
77
+
78
+ :param cron_expression: The cron_expression of this V1PipelineSchedule. # noqa: E501
79
+ :type: str
80
+ """
81
+
82
+ self._cron_expression = cron_expression
83
+
84
+ @property
85
+ def id(self) -> 'str':
86
+ """Gets the id of this V1PipelineSchedule. # noqa: E501
87
+
88
+
89
+ :return: The id of this V1PipelineSchedule. # noqa: E501
90
+ :rtype: str
91
+ """
92
+ return self._id
93
+
94
+ @id.setter
95
+ def id(self, id: 'str'):
96
+ """Sets the id of this V1PipelineSchedule.
97
+
98
+
99
+ :param id: The id of this V1PipelineSchedule. # noqa: E501
100
+ :type: str
101
+ """
102
+
103
+ self._id = id
104
+
105
+ def to_dict(self) -> dict:
106
+ """Returns the model properties as a dict"""
107
+ result = {}
108
+
109
+ for attr, _ in six.iteritems(self.swagger_types):
110
+ value = getattr(self, attr)
111
+ if isinstance(value, list):
112
+ result[attr] = list(map(
113
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
114
+ value
115
+ ))
116
+ elif hasattr(value, "to_dict"):
117
+ result[attr] = value.to_dict()
118
+ elif isinstance(value, dict):
119
+ result[attr] = dict(map(
120
+ lambda item: (item[0], item[1].to_dict())
121
+ if hasattr(item[1], "to_dict") else item,
122
+ value.items()
123
+ ))
124
+ else:
125
+ result[attr] = value
126
+ if issubclass(V1PipelineSchedule, dict):
127
+ for key, value in self.items():
128
+ result[key] = value
129
+
130
+ return result
131
+
132
+ def to_str(self) -> str:
133
+ """Returns the string representation of the model"""
134
+ return pprint.pformat(self.to_dict())
135
+
136
+ def __repr__(self) -> str:
137
+ """For `print` and `pprint`"""
138
+ return self.to_str()
139
+
140
+ def __eq__(self, other: 'V1PipelineSchedule') -> bool:
141
+ """Returns true if both objects are equal"""
142
+ if not isinstance(other, V1PipelineSchedule):
143
+ return False
144
+
145
+ return self.__dict__ == other.__dict__
146
+
147
+ def __ne__(self, other: 'V1PipelineSchedule') -> bool:
148
+ """Returns true if both objects are not equal"""
149
+ return not self == other
lightning_sdk/serve.py ADDED
@@ -0,0 +1,134 @@
1
+ import os
2
+ import warnings
3
+ from pathlib import Path
4
+
5
+ import docker
6
+ from rich.console import Console
7
+ from rich.progress import Progress
8
+
9
+ from lightning_sdk import Teamspace
10
+ from lightning_sdk.api.lit_container_api import LitContainerApi
11
+
12
+
13
+ class _LitServeDeployer:
14
+ def __init__(self) -> None:
15
+ self._console = Console()
16
+ self._client = None
17
+
18
+ @property
19
+ def client(self) -> docker.DockerClient:
20
+ if self._client is None:
21
+ try:
22
+ self._client = docker.from_env()
23
+ self._client.ping()
24
+ except docker.errors.DockerException as e:
25
+ raise RuntimeError(f"Failed to connect to Docker daemon: {e!s}. Is Docker running?") from None
26
+ return self._client
27
+
28
+ def dockerize_api(
29
+ self, server_filename: str, port: int = 8000, gpu: bool = False, tag: str = "litserve-model"
30
+ ) -> str:
31
+ import litserve as ls
32
+ from litserve import docker_builder
33
+
34
+ console = self._console
35
+ if os.path.exists("Dockerfile"):
36
+ console.print("Dockerfile already exists. Skipping generation.")
37
+ return os.path.abspath("Dockerfile")
38
+
39
+ requirements = ""
40
+ if os.path.exists("requirements.txt"):
41
+ requirements = "-r requirements.txt"
42
+ else:
43
+ warnings.warn(
44
+ f"requirements.txt not found at {os.getcwd()}. "
45
+ f"Make sure to install the required packages in the Dockerfile.",
46
+ UserWarning,
47
+ )
48
+ current_dir = Path.cwd()
49
+ if not (current_dir / server_filename).is_file():
50
+ raise FileNotFoundError(f"Server file `{server_filename}` must be in the current directory: {os.getcwd()}")
51
+
52
+ version = ls.__version__
53
+ if gpu:
54
+ run_cmd = f"docker run --gpus all -p {port}:{port} {tag}:latest"
55
+ docker_template = docker_builder.CUDA_DOCKER_TEMPLATE
56
+ else:
57
+ run_cmd = f"docker run -p {port}:{port} {tag}:latest"
58
+ docker_template = docker_builder.DOCKERFILE_TEMPLATE
59
+ dockerfile_content = docker_template.format(
60
+ server_filename=server_filename,
61
+ port=port,
62
+ version=version,
63
+ requirements=requirements,
64
+ )
65
+ with open("Dockerfile", "w") as f:
66
+ f.write(dockerfile_content)
67
+
68
+ success_msg = f"""[bold]Dockerfile created successfully[/bold]
69
+ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additional dependencies or commands.
70
+
71
+ [bold]Build the container with:[/bold]
72
+ > [underline]docker build -t {tag} .[/underline]
73
+
74
+ [bold]To run the Docker container on the machine:[/bold]
75
+ > [underline]{run_cmd}[/underline]
76
+
77
+ [bold]To push the container to a registry:[/bold]
78
+ > [underline]docker push {tag}[/underline]
79
+ """
80
+ console.print(success_msg)
81
+ return os.path.abspath("Dockerfile")
82
+
83
+ def generate_client(self) -> None:
84
+ console = self._console
85
+ try:
86
+ from litserve.python_client import client_template
87
+ except ImportError:
88
+ raise ImportError(
89
+ "litserve is not installed. Please install it with `pip install lightning_sdk[serve]`"
90
+ ) from None
91
+
92
+ client_path = Path("client.py")
93
+ if client_path.exists():
94
+ console.print("Skipping client generation: client.py already exists", style="blue")
95
+ else:
96
+ try:
97
+ client_path.write_text(client_template)
98
+ console.print("✅ Client generated at client.py", style="bold green")
99
+ except OSError as e:
100
+ raise OSError(f"Failed to generate client.py: {e!s}") from None
101
+
102
+ def _build_container(self, path: str, repository: str, tag: str, console: Console, progress: Progress) -> None:
103
+ build_task = progress.add_task("Building Docker image", total=None)
104
+ build_status = self.client.api.build(
105
+ path=os.path.dirname(path), dockerfile=path, tag=f"{repository}:{tag}", decode=True, quiet=False
106
+ )
107
+ for line in build_status:
108
+ if "error" in line:
109
+ progress.stop()
110
+ console.print(f"\n[red]{line}[/red]")
111
+ return
112
+ if "stream" in line and line["stream"].strip():
113
+ console.print(line["stream"].strip(), style="bright_black")
114
+ progress.update(build_task, description="Building Docker image")
115
+
116
+ progress.update(build_task, description="[green]Build completed![/green]")
117
+
118
+ def _push_container(
119
+ self, repository: str, tag: str, teamspace: Teamspace, lit_cr: LitContainerApi, progress: Progress
120
+ ) -> None:
121
+ console = self._console
122
+ push_task = progress.add_task("Pushing to registry", total=None)
123
+ console.print("\nPushing image...", style="bold blue")
124
+ lit_cr.authenticate()
125
+ push_status = lit_cr.upload_container(repository, teamspace, tag=tag)
126
+ for line in push_status:
127
+ if "error" in line:
128
+ progress.stop()
129
+ console.print(f"\n[red]{line}[/red]")
130
+ return
131
+ if "status" in line:
132
+ console.print(line["status"], style="bright_black")
133
+ progress.update(push_task, description="Pushing to registry")
134
+ progress.update(push_task, description="[green]Push completed![/green]")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License