lightning-sdk 0.2.18__py3-none-any.whl → 0.2.20__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 (68) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/api/deployment_api.py +2 -0
  3. lightning_sdk/api/license_api.py +28 -6
  4. lightning_sdk/cli/deploy/_auth.py +11 -19
  5. lightning_sdk/cli/entrypoint.py +20 -2
  6. lightning_sdk/deployment/deployment.py +2 -0
  7. lightning_sdk/lightning_cloud/login.py +2 -2
  8. lightning_sdk/lightning_cloud/openapi/__init__.py +10 -2
  9. lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
  10. lightning_sdk/lightning_cloud/openapi/api/blog_posts_service_api.py +533 -0
  11. lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +113 -0
  12. lightning_sdk/lightning_cloud/openapi/api/jobs_service_api.py +121 -0
  13. lightning_sdk/lightning_cloud/openapi/models/__init__.py +9 -2
  14. lightning_sdk/lightning_cloud/openapi/models/alertingevents_id_body.py +409 -0
  15. lightning_sdk/lightning_cloud/openapi/models/blogposts_id_body.py +253 -0
  16. lightning_sdk/lightning_cloud/openapi/models/deployments_id_body.py +27 -1
  17. lightning_sdk/lightning_cloud/openapi/models/id_codeconfig_body.py +29 -3
  18. lightning_sdk/lightning_cloud/openapi/models/id_transfer_body.py +123 -0
  19. lightning_sdk/lightning_cloud/openapi/models/orgs_id_body.py +157 -157
  20. lightning_sdk/lightning_cloud/openapi/models/projects_id_body.py +79 -1
  21. lightning_sdk/lightning_cloud/openapi/models/update.py +27 -1
  22. lightning_sdk/lightning_cloud/openapi/models/v1_author.py +201 -0
  23. lightning_sdk/lightning_cloud/openapi/models/v1_blog_post.py +383 -0
  24. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space.py +27 -1
  25. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template.py +27 -1
  26. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +27 -1
  27. lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_state.py +1 -0
  28. lightning_sdk/lightning_cloud/openapi/models/v1_create_blog_post_request.py +253 -0
  29. lightning_sdk/lightning_cloud/openapi/models/v1_create_cloud_space_environment_template_request.py +27 -1
  30. lightning_sdk/lightning_cloud/openapi/models/v1_daily_usage.py +81 -3
  31. lightning_sdk/lightning_cloud/openapi/models/v1_data_connection.py +79 -1
  32. lightning_sdk/lightning_cloud/openapi/models/v1_delete_blog_post_response.py +123 -0
  33. lightning_sdk/lightning_cloud/openapi/models/v1_deployment.py +27 -1
  34. lightning_sdk/lightning_cloud/openapi/models/v1_deployment_alerting_policy_type.py +1 -0
  35. lightning_sdk/lightning_cloud/openapi/models/v1_get_organization_storage_metadata_response.py +157 -1
  36. lightning_sdk/lightning_cloud/openapi/models/v1_get_project_storage_metadata_response.py +237 -3
  37. lightning_sdk/lightning_cloud/openapi/models/v1_get_user_storage_breakdown_response.py +53 -1
  38. lightning_sdk/lightning_cloud/openapi/models/v1_google_cloud_direct_v1.py +53 -1
  39. lightning_sdk/lightning_cloud/openapi/models/v1_list_blog_posts_response.py +175 -0
  40. lightning_sdk/lightning_cloud/openapi/models/v1_membership.py +27 -1
  41. lightning_sdk/lightning_cloud/openapi/models/v1_message.py +27 -1
  42. lightning_sdk/lightning_cloud/openapi/models/v1_notification_type.py +1 -0
  43. lightning_sdk/lightning_cloud/openapi/models/v1_organization.py +261 -157
  44. lightning_sdk/lightning_cloud/openapi/models/v1_product_license.py +27 -1
  45. lightning_sdk/lightning_cloud/openapi/models/v1_project.py +53 -1
  46. lightning_sdk/lightning_cloud/openapi/models/v1_project_membership.py +27 -1
  47. lightning_sdk/lightning_cloud/openapi/models/v1_project_settings.py +79 -1
  48. lightning_sdk/lightning_cloud/openapi/models/v1_project_storage.py +199 -17
  49. lightning_sdk/lightning_cloud/openapi/models/v1_rule_resource.py +1 -0
  50. lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset.py +27 -1
  51. lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset_type.py +4 -0
  52. lightning_sdk/lightning_cloud/openapi/models/v1_transaction.py +27 -1
  53. lightning_sdk/lightning_cloud/openapi/models/v1_transfer_cloud_space_response.py +97 -0
  54. lightning_sdk/lightning_cloud/openapi/models/v1_usage.py +105 -27
  55. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +249 -145
  56. lightning_sdk/lightning_cloud/openapi/models/v1_volume.py +499 -31
  57. lightning_sdk/lightning_cloud/rest_client.py +13 -11
  58. lightning_sdk/lightning_cloud/source_code/logs_socket_api.py +8 -3
  59. lightning_sdk/serve.py +1 -0
  60. lightning_sdk/services/license.py +148 -27
  61. {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/METADATA +1 -1
  62. {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/RECORD +66 -58
  63. lightning_sdk/lightning_cloud/openapi/models/v1_ebs.py +0 -279
  64. lightning_sdk/lightning_cloud/openapi/models/v1_reservation_billing_session.py +0 -279
  65. {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/LICENSE +0 -0
  66. {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/WHEEL +0 -0
  67. {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/entry_points.txt +0 -0
  68. {lightning_sdk-0.2.18.dist-info → lightning_sdk-0.2.20.dist-info}/top_level.txt +0 -0
@@ -3,11 +3,79 @@ import json
3
3
  import os
4
4
  import socket
5
5
  import threading
6
+ from contextlib import suppress
6
7
  from functools import partial
8
+ from importlib import metadata
7
9
  from pathlib import Path
8
- from typing import Optional
10
+ from typing import Optional, Tuple
9
11
 
10
- from lightning_sdk.api.license_api import LicenseApi
12
+ from lightning_sdk.api.license_api import LICENSE_SIGNING_URL, LicenseApi, generate_url_user_settings
13
+ from lightning_sdk.lightning_cloud.login import Auth
14
+
15
+ MESSAGE_NOT_AUTHENTICATED = (
16
+ "┌─────────────────────────────────────────────────────────────────────────┐\n"
17
+ "│ ⚠️ No authenticated user found or license API is not available. │\n"
18
+ "│ │\n"
19
+ "│ Please make sure you are logged in and have a valid license. │\n"
20
+ "│ If you're not logged in, you can use the following command: │\n"
21
+ "│ │\n"
22
+ "│ lightning login │\n"
23
+ "└─────────────────────────────────────────────────────────────────────────┘"
24
+ )
25
+ MESSAGE_AUTH_NO_LICENSE = (
26
+ "┌──────────────────────────────────────────────────────────────────────────────────────────────┐\n"
27
+ "│ ⚠️ No valid license found for the authenticated user for product '{self.product_name}'. │\n"
28
+ "│ │\n"
29
+ "│ Please ensure you have an approved license for this product. │\n"
30
+ "│ If you believe this is an error, please contact support. │\n"
31
+ "│ │\n"
32
+ "│ You can review or update your license settings here: │\n"
33
+ f"│ {LICENSE_SIGNING_URL:<89}│\n"
34
+ "└──────────────────────────────────────────────────────────────────────────────────────────────┘"
35
+ )
36
+ MESSAGE_GUIDE_SIGN_LICENSE = (
37
+ "┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n"
38
+ "│ ⚠️ {reason} │\n"
39
+ "│ Details: license key ({license_strats}...{license_ends}) for package {package_name:<56} │\n"
40
+ "│ Please make sure you have signed the license agreement and set the license key. │\n"
41
+ "│ │\n"
42
+ f"│ Sign the license agreement here (if you dont have Lightning account, you will asked to create one): │\n"
43
+ f"│ {generate_url_user_settings():<102}\n"
44
+ "│ │\n"
45
+ "│ Once you have the license key, you may need to reinstall this package to activate it. Use the commands: │\n"
46
+ "│ │\n"
47
+ "│ export LIGHTNING_LICENSE_KEY=<your_license_key> │\n"
48
+ "│ pip install --force-reinstall --no-deps {package_name:<63} │\n"
49
+ "│ │\n"
50
+ "│ For more information, please refer to the documentation. │\n"
51
+ "└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘"
52
+ )
53
+
54
+
55
+ def generate_message_guide_sign_license(package_name: str, reason: str, license_key: str = "") -> str:
56
+ """Generate a default message for signing the license agreement."""
57
+ if not license_key:
58
+ license_key = "." * 64
59
+ return MESSAGE_GUIDE_SIGN_LICENSE.format(
60
+ package_name=package_name,
61
+ reason=reason.ljust(102, " "),
62
+ license_strats=license_key[:5],
63
+ license_ends=license_key[-5:],
64
+ )
65
+
66
+
67
+ MESSAGE_WITH_KEY_OFFLINE = (
68
+ "┌──────────────────────────────────────────────────────────────────────────────────────┐\n"
69
+ "│ ⚠️ License key ({license_strats}...{license_ends}) is set, but the system is offline. │\n"
70
+ "│ │\n"
71
+ "│ Please ensure your license key is valid and that the system is connected online. │\n"
72
+ "└──────────────────────────────────────────────────────────────────────────────────────┘"
73
+ )
74
+
75
+
76
+ def generate_message_with_key_offline(license_key: str) -> str:
77
+ """Generate a message for when the license key is set but the system is offline."""
78
+ return MESSAGE_WITH_KEY_OFFLINE.format(license_strats=license_key[:5], license_ends=license_key[-5:])
11
79
 
12
80
 
13
81
  class LightningLicense:
@@ -33,19 +101,57 @@ class LightningLicense:
33
101
  self._license_api = None
34
102
  self._stream_messages = stream_messages
35
103
 
104
+ @property
105
+ def license_api(self) -> LicenseApi:
106
+ """Get the LicenseApi instance."""
107
+ if not self._license_api:
108
+ with suppress(ValueError):
109
+ self._license_api = LicenseApi()
110
+ return self._license_api
111
+
36
112
  def validate_license(self) -> bool:
37
113
  """Validate the license key."""
38
114
  if not self.is_online():
39
115
  raise ConnectionError("No internet connection.")
40
116
 
41
- self._license_api = LicenseApi()
42
- return self._license_api.valid_license(
117
+ return self.license_api.valid_license(
43
118
  license_key=self.license_key,
44
119
  product_name=self.product_name,
45
120
  product_version=self.product_version,
46
121
  product_type=self.product_type,
47
122
  )
48
123
 
124
+ def _auth_user_id(self) -> Tuple[Optional[str], Optional[str]]:
125
+ """Get the authenticated user ID."""
126
+ try:
127
+ auth = Auth()
128
+ except ValueError:
129
+ return None, "No user credentials found. Please run `lightning login` to authenticate."
130
+ return auth.user_id, None
131
+
132
+ def _check_user_license(self, user_id: Optional[str] = None) -> bool:
133
+ """Check if the authenticated user has a valid license for this product."""
134
+ if not user_id:
135
+ user_id, msg = self._auth_user_id()
136
+ if msg:
137
+ self._stream_messages(msg)
138
+ if not user_id:
139
+ return False
140
+ if not self.license_api:
141
+ self._stream_messages(MESSAGE_NOT_AUTHENTICATED)
142
+ return False
143
+
144
+ licenses = self.license_api.list_user_licenses(user_id=user_id)
145
+ for license_info in licenses:
146
+ if (
147
+ license_info.product_name == self.product_name
148
+ and license_info.product_type == self.product_type
149
+ and license_info.is_valid
150
+ ):
151
+ return True
152
+ self._stream_messages(MESSAGE_AUTH_NO_LICENSE)
153
+ return False
154
+
49
155
  @staticmethod
50
156
  def is_online(timeout: float = 2.0) -> bool:
51
157
  """Check if the system is online by attempting to connect to a public DNS server (Google's).
@@ -75,22 +181,33 @@ class LightningLicense:
75
181
  if isinstance(self._is_valid, bool):
76
182
  # if the license key is already validated, return the cached value
77
183
  return self._is_valid
78
- if not self.product_version:
79
- self._stream_messages("Product version is not set correctly, consider leave it empty for auto-determine.")
80
- if not self.license_key:
81
- self._stream_messages(
82
- "License key is not set neither cannot be found in the package root or user home."
83
- " Please make sure you have signed the license agreement and set the license key."
84
- " For more information, please refer to the documentation.",
85
- )
86
184
  is_online = self.is_online()
87
- if self.license_key and is_online:
88
- self._is_valid = self.validate_license()
89
- elif not is_online:
185
+ if is_online:
186
+ if self.license_key:
187
+ self._is_valid = self.validate_license()
188
+ else:
189
+ # try to check if the session has logged-in user and if the user has a valid license
190
+ self._stream_messages(
191
+ "Missing required license key for license validation."
192
+ f" Attempting to check if the authenticated user has a valid license for {self.product_name}."
193
+ )
194
+ user_id, auth_msg = self._auth_user_id()
195
+ if not user_id:
196
+ self._is_valid = False
197
+ if auth_msg:
198
+ self._stream_messages(auth_msg)
199
+ else:
200
+ self._is_valid = self._check_user_license(user_id=user_id)
201
+ elif self.license_key:
202
+ self._stream_messages(generate_message_with_key_offline(self.license_key))
203
+ else:
90
204
  self._stream_messages(
91
- "License key is set but the system is offline. "
92
- "Please make sure you have a valid license key and the system is online."
205
+ generate_message_guide_sign_license(
206
+ package_name=self.product_name,
207
+ reason="License key is not set neither cannot be found in the package root or user home.",
208
+ )
93
209
  )
210
+
94
211
  return self._is_valid
95
212
 
96
213
  @property
@@ -107,14 +224,17 @@ class LightningLicense:
107
224
  """
108
225
  if not package_name:
109
226
  return None
227
+ pkg_spec = importlib.util.find_spec(package_name)
228
+ if pkg_spec is None:
229
+ return None
230
+ pkg_locations = pkg_spec.submodule_search_locations
231
+ if not pkg_locations:
232
+ return None
110
233
  try:
111
- pkg_locations = importlib.util.find_spec(package_name).submodule_search_locations
112
- if not pkg_locations:
113
- return None
114
234
  license_file = os.path.join(pkg_locations[0], ".license_key")
115
235
  with open(license_file) as fp:
116
236
  return fp.read().strip()
117
- except (FileNotFoundError, ModuleNotFoundError):
237
+ except FileNotFoundError:
118
238
  return None
119
239
 
120
240
  @staticmethod
@@ -146,9 +266,8 @@ class LightningLicense:
146
266
  package_name: The name of the package. If not provided, it will be determined from the current module.
147
267
  """
148
268
  try:
149
- pkg = importlib.import_module(package_name)
150
- return getattr(pkg, "__version__", None)
151
- except ImportError:
269
+ return metadata.version(package_name)
270
+ except metadata.PackageNotFoundError:
152
271
  return None
153
272
 
154
273
  @property
@@ -200,9 +319,11 @@ def check_license(
200
319
  )
201
320
  if lit_license.is_valid is False:
202
321
  stream_messages(
203
- "License key is not valid.\n"
204
- f" Key: {lit_license.license_key}\n"
205
- " Please make sure you have a valid license key."
322
+ generate_message_guide_sign_license(
323
+ package_name=lit_license.product_name,
324
+ reason="License key is not valid or not set.",
325
+ license_key=lit_license.license_key,
326
+ )
206
327
  )
207
328
 
208
329
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.2.18
3
+ Version: 0.2.20
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License