lightning-sdk 0.2.7__py3-none-any.whl → 0.2.8__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.
lightning_sdk/__init__.py CHANGED
@@ -31,6 +31,6 @@ __all__ = [
31
31
  "User",
32
32
  ]
33
33
 
34
- __version__ = "0.2.7"
34
+ __version__ = "0.2.8"
35
35
  _check_version_and_prompt_upgrade(__version__)
36
36
  _set_tqdm_envvars_noninteractive()
@@ -7,7 +7,6 @@ import requests
7
7
  from rich.console import Console
8
8
 
9
9
  from lightning_sdk.api.utils import _get_registry_url
10
- from lightning_sdk.lightning_cloud.env import LIGHTNING_CLOUD_URL
11
10
  from lightning_sdk.lightning_cloud.openapi.models import V1DeleteLitRepositoryResponse
12
11
  from lightning_sdk.lightning_cloud.rest_client import LightningClient
13
12
  from lightning_sdk.teamspace import Teamspace
@@ -103,10 +102,11 @@ class LitContainerApi:
103
102
  """Lists containers of the project ID.
104
103
 
105
104
  :param project_id: The non-human readable project ID used internally to identify projects.
105
+ :param cloud_account: The cluster ID of the cloud account. If None, will use the default cluster.
106
106
  :return:
107
107
  """
108
108
  project = self._client.lit_registry_service_get_lit_project_registry(
109
- project_id, cluster_id=cloud_account
109
+ project_id, cluster_id="" if cloud_account is None else cloud_account
110
110
  ) # cloud account on the CLI is cluster_id
111
111
  return project.repositories
112
112
 
@@ -138,7 +138,7 @@ class LitContainerApi:
138
138
  Named cloud-account in the CLI options.
139
139
  :param platform: If empty will be linux/amd64. This is important because our entire deployment infra runs on
140
140
  linux/amd64. Will show user a warning otherwise.
141
- :return: Generator[dict, None, None]
141
+ :return: Generator[dict, None, dict]
142
142
  """
143
143
  try:
144
144
  self._docker_client.images.get(f"{container}:{tag}")
@@ -164,13 +164,6 @@ class LitContainerApi:
164
164
  raise ValueError(f"Could not tag container {container}:{tag} with {repository}:{tag}")
165
165
  yield from self._push_with_retry(repository, tag=tag)
166
166
 
167
- yield {
168
- "finish": True,
169
- "url": f"{LIGHTNING_CLOUD_URL}/{teamspace.owner.name}/{teamspace.name}/containers/{container_basename}"
170
- f"{f'?clusterId={cloud_account}' if cloud_account is not None else ''}",
171
- "repository": repository,
172
- }
173
-
174
167
  def _push_with_retry(self, repository: str, tag: str, max_retries: int = 3) -> Iterator[Dict[str, Any]]:
175
168
  def is_auth_error(error_msg: str) -> bool:
176
169
  auth_errors = ["unauthorized", "authentication required", "unauth"]
@@ -17,17 +17,26 @@ from lightning_sdk.serve import _LitServeDeployer, authenticate
17
17
  _MACHINE_VALUES = tuple([machine.name for machine in Machine.__dict__.values() if isinstance(machine, Machine)])
18
18
 
19
19
 
20
- @click.group("serve")
20
+ class _ServeGroup(click.Group):
21
+ def parse_args(self, ctx: click.Context, args: list) -> click.Group:
22
+ # Check if first arg is a file path and not a command name
23
+ if args and os.path.exists(args[0]) and args[0] not in self.commands:
24
+ # Insert the 'api' command before the file path
25
+ args.insert(0, "api")
26
+ return super().parse_args(ctx, args)
27
+
28
+
29
+ @click.group("serve", cls=_ServeGroup)
21
30
  def serve() -> None:
22
31
  """Serve a LitServe model.
23
32
 
24
33
  Example:
25
- lightning serve api server.py # serve locally
34
+ lightning serve server.py # serve locally
26
35
 
27
36
  Example:
28
- lightning serve api server.py --cloud --name litserve-api # deploy to the cloud
37
+ lightning serve server.py --cloud # deploy to the cloud
29
38
 
30
- You can deploy the API to the cloud by running `lightning serve api server.py --cloud`.
39
+ You can deploy the API to the cloud by running `lightning serve server.py --cloud`.
31
40
  This will build a docker container for the server.py script and deploy it to the Lightning AI platform.
32
41
  """
33
42
 
@@ -42,11 +51,11 @@ def serve() -> None:
42
51
  help="Generate a client for the model",
43
52
  )
44
53
  @click.option(
45
- "--cloud",
54
+ "--local",
46
55
  is_flag=True,
47
56
  default=False,
48
57
  flag_value=True,
49
- help="Deploy the model to the Lightning AI platform",
58
+ help="Run the model locally",
50
59
  )
51
60
  @click.option("--name", default=None, help="Name of the deployed API (e.g., 'classification-api', 'Llama-api')")
52
61
  @click.option(
@@ -107,7 +116,7 @@ def serve() -> None:
107
116
  def api(
108
117
  script_path: str,
109
118
  easy: bool,
110
- cloud: bool,
119
+ local: bool,
111
120
  name: Optional[str],
112
121
  non_interactive: bool,
113
122
  machine: str,
@@ -126,7 +135,7 @@ def api(
126
135
  return api_impl(
127
136
  script_path=script_path,
128
137
  easy=easy,
129
- cloud=cloud,
138
+ local=local,
130
139
  repository=name,
131
140
  non_interactive=non_interactive,
132
141
  machine=machine,
@@ -146,7 +155,7 @@ def api(
146
155
  def api_impl(
147
156
  script_path: Union[str, Path],
148
157
  easy: bool = False,
149
- cloud: bool = False,
158
+ local: bool = False,
150
159
  repository: [str] = None,
151
160
  tag: Optional[str] = None,
152
161
  non_interactive: bool = False,
@@ -176,7 +185,7 @@ def api_impl(
176
185
  timestr = datetime.now().strftime("%b-%d-%H_%M")
177
186
  repository = f"litserve-{timestr}".lower()
178
187
 
179
- if cloud:
188
+ if not local:
180
189
  repository = repository or "litserve-model"
181
190
  machine = Machine.from_str(machine)
182
191
  return _handle_cloud(
@@ -263,17 +272,31 @@ def _handle_cloud(
263
272
  transient=True,
264
273
  ) as progress:
265
274
  try:
266
- # TODO: @aniketmaurya improve the console prints here
267
- ls_deployer.build_container(path, repository, tag, console, progress)
268
- push_status = ls_deployer.push_container(
269
- repository, tag, resolved_teamspace, lit_cr, progress, cloud_account=cloud_account
270
- )
275
+ # Build the container
276
+ build_task = progress.add_task("Building Docker image", total=None)
277
+ for line in ls_deployer.build_container(path, repository, tag):
278
+ console.print(line.strip())
279
+ progress.update(build_task, advance=1)
280
+ progress.update(build_task, description="[green]Build completed![/green]", completed=1.0)
281
+ progress.remove_task(build_task)
282
+
283
+ # Push the container to the registry
284
+ console.print("\nPushing image to registry. It may take a while...", style="bold")
285
+ push_task = progress.add_task("Pushing to registry", total=None)
286
+ push_status = {}
287
+ for line in ls_deployer.push_container(
288
+ repository, tag, resolved_teamspace, lit_cr, cloud_account=cloud_account
289
+ ):
290
+ push_status = line
291
+ progress.update(push_task, advance=1)
292
+ if not ("Pushing" in line["status"] or "Waiting" in line["status"]):
293
+ console.print(line["status"])
294
+ progress.update(push_task, description="[green]Push completed![/green]")
271
295
  except Exception as e:
272
296
  console.print(f"❌ Deployment failed: {e}", style="red")
273
297
  return
274
298
  console.print(f"\n✅ Image pushed to {repository}:{tag}")
275
- console.print(f"🔗 You can access the container at: [i]{push_status.get('url')}[/i]")
276
- image = push_status.get("repository")
299
+ image = push_status.get("image")
277
300
 
278
301
  deployment_status = ls_deployer.run_on_cloud(
279
302
  deployment_name=deployment_name,
lightning_sdk/serve.py CHANGED
@@ -7,13 +7,13 @@ from urllib.parse import urlencode
7
7
 
8
8
  import docker
9
9
  from rich.console import Console
10
- from rich.progress import Progress
11
10
 
12
11
  from lightning_sdk import Deployment, Machine, Teamspace
13
12
  from lightning_sdk.api.deployment_api import AutoScaleConfig, DeploymentApi, Env, Secret
14
13
  from lightning_sdk.api.lit_container_api import LitContainerApi
15
- from lightning_sdk.api.utils import _get_cloud_url
14
+ from lightning_sdk.api.utils import _get_cloud_url, _get_registry_url
16
15
  from lightning_sdk.lightning_cloud import env
16
+ from lightning_sdk.lightning_cloud.env import LIGHTNING_CLOUD_URL
17
17
  from lightning_sdk.lightning_cloud.login import Auth, AuthServer
18
18
 
19
19
  _DOCKER_NOT_RUNNING_MSG = (
@@ -182,22 +182,14 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
182
182
 
183
183
  return log_generator()
184
184
 
185
- def build_container(self, path: str, repository: str, tag: str, console: Console, progress: Progress) -> None:
186
- build_task = progress.add_task("Building Docker image", total=None)
185
+ def build_container(self, path: str, repository: str, tag: str) -> Generator[str, None, None]:
187
186
  build_logs = self._docker_build_with_logs(path, repository, tag=tag)
188
187
 
189
188
  for line in build_logs:
190
189
  if "error" in line:
191
- progress.stop()
192
- console.print(f"\n[red]{line}[/red]")
193
190
  raise RuntimeError(f"Failed to build image: {line}")
194
191
  else:
195
- console.print(
196
- line.strip(),
197
- )
198
- progress.update(build_task, description="Building Docker image")
199
-
200
- progress.update(build_task, description="[green]Build completed![/green]")
192
+ yield line.strip()
201
193
 
202
194
  def push_container(
203
195
  self,
@@ -205,26 +197,31 @@ Update [underline]{os.path.abspath("Dockerfile")}[/underline] to add any additio
205
197
  tag: str,
206
198
  teamspace: Teamspace,
207
199
  lit_cr: LitContainerApi,
208
- progress: Progress,
209
200
  cloud_account: str,
210
- ) -> dict:
211
- console = self._console
212
- push_task = progress.add_task("Pushing to registry", total=None)
213
- console.print("\nPushing image...", style="bold blue")
201
+ ) -> Generator[dict, None, dict]:
214
202
  lit_cr.authenticate()
215
- push_status = lit_cr.upload_container(repository, teamspace, tag=tag, cloud_account=cloud_account)
216
- last_status = {}
203
+ push_status = lit_cr.upload_container(
204
+ repository, teamspace, tag=tag, cloud_account=cloud_account, platform=None
205
+ )
217
206
  for line in push_status:
218
- last_status = line
219
207
  if "error" in line:
220
- progress.stop()
221
- console.print(f"\n[red]{line}[/red]")
222
208
  raise RuntimeError(f"Failed to push image: {line}")
223
209
  if "status" in line:
224
- console.print(line["status"].strip())
225
- progress.update(push_task, description="Pushing to registry")
226
- progress.update(push_task, description="[green]Push completed![/green]")
227
- return last_status
210
+ yield {"status": line["status"].strip()}
211
+
212
+ registry_url = _get_registry_url()
213
+ container_basename = repository.split("/")[-1]
214
+ repository = (
215
+ f"{registry_url}/lit-container{f'-{cloud_account}' if cloud_account is not None else ''}/"
216
+ f"{teamspace.owner.name}/{teamspace.name}/{container_basename}"
217
+ )
218
+ yield {
219
+ "finish": True,
220
+ "status": "Container pushed successfully",
221
+ "url": f"{LIGHTNING_CLOUD_URL}/{teamspace.owner.name}/{teamspace.name}/containers/{container_basename}"
222
+ f"{f'?clusterId={cloud_account}' if cloud_account is not None else ''}",
223
+ "image": repository,
224
+ }
228
225
 
229
226
  def _update_deployment(
230
227
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: SDK to develop using Lightning AI Studios
5
5
  Author-email: Lightning-AI <justus@lightning.ai>
6
6
  License: MIT License
@@ -1,5 +1,5 @@
1
1
  docs/source/conf.py,sha256=r8yX20eC-4mHhMTd0SbQb5TlSWHhO6wnJ0VJ_FBFpag,13249
2
- lightning_sdk/__init__.py,sha256=2YlLVkcc_oSxRiBA9ZX7-ItwTff8JwvMihcSY8xDC-Q,1104
2
+ lightning_sdk/__init__.py,sha256=pERZUbSd9UKX5PCO6GMnFKZFWbSw_05kILfckZAZGxo,1104
3
3
  lightning_sdk/agents.py,sha256=ly6Ma1j0ZgGPFyvPvMN28JWiB9dATIstFa5XM8pMi6I,1577
4
4
  lightning_sdk/ai_hub.py,sha256=iI1vNhgcz_Ff1c3rN1ogN7dK-r-HXRj6NMtS2cA14UA,6925
5
5
  lightning_sdk/constants.py,sha256=ztl1PTUBULnqTf3DyKUSJaV_O20hNtUYT6XvAYIrmIk,749
@@ -10,7 +10,7 @@ lightning_sdk/models.py,sha256=5DCfv2M0b8iYKj8tAMIX7gIUXrk2CgALANX14N5OFgo,6255
10
10
  lightning_sdk/organization.py,sha256=WCfzdgjtvY1_A07DnxOpp74V2JR2gQwtXbIEcFDnoVU,1232
11
11
  lightning_sdk/owner.py,sha256=t5svD2it4C9pbSpVuG9WJL46CYi37JXNziwnXxhiU5U,1361
12
12
  lightning_sdk/plugin.py,sha256=_K0m-PSyXE86B-SFQVQm0JEvfdIVXeARmnlATCAiMdo,14632
13
- lightning_sdk/serve.py,sha256=F2vBWXG4HOoTO3-sEzrghvJ7vWSFNoNpcdTPtv5Ljs4,12287
13
+ lightning_sdk/serve.py,sha256=yuBPy4w8n2Es7O2dlQStUZ-HcI8H12pB16ZY8SFe4WA,12139
14
14
  lightning_sdk/status.py,sha256=lLGAuSvXBoXQFEEsEYwdCi0RcSNatUn5OPjJVjDtoM0,386
15
15
  lightning_sdk/studio.py,sha256=hyvAiVhkETAtbu0RRF1Aw6F8Y__E1SSAmsB8PHfmqHo,19935
16
16
  lightning_sdk/teamspace.py,sha256=EqMDDXtePCDD3JZHzx_qx7xn2tSxtH-LqwSc1JtIwEM,15073
@@ -20,7 +20,7 @@ lightning_sdk/api/agents_api.py,sha256=G47TbFo9kYqnBMqdw2RW-lfS1VAUBSXDmzs6fpIEM
20
20
  lightning_sdk/api/ai_hub_api.py,sha256=azqDZ-PzasVAcoQHno7k7OO_xFOHQ4NDozxF8jEh83Y,7864
21
21
  lightning_sdk/api/deployment_api.py,sha256=z_D7ZZAnsVe3Q_ZVx1azcLK2_pP5xj63tmU97qhgyOw,22583
22
22
  lightning_sdk/api/job_api.py,sha256=_mMAI_BG_48i-BLwCP_U72zgmM5zYa2KUZ7u66HWkIc,13568
23
- lightning_sdk/api/lit_container_api.py,sha256=lI66uqzVYuyCAQ1d9yCir67ir7t6fUKA7O_ML-Vj94A,10730
23
+ lightning_sdk/api/lit_container_api.py,sha256=m8X2uiM6Ze6qxuoAkfMgZEUNUyc93m8SnO0xDWt3O9E,10509
24
24
  lightning_sdk/api/mmt_api.py,sha256=-v7ATab-ThAM-HRClS92Ehxuu9MlBfdKWWFCGvVUHiM,8962
25
25
  lightning_sdk/api/org_api.py,sha256=Ze3z_ATVrukobujV5YdC42DKj45Vuwl7X52q_Vr-o3U,803
26
26
  lightning_sdk/api/pipeline_api.py,sha256=P5P9C6qOpyBGU0t5N68h1LuFAsAKmPPgkac6uObrYKw,1676
@@ -47,7 +47,7 @@ lightning_sdk/cli/list.py,sha256=dAZ94QPvE4IkH6GfL7171TMrMfcuWB53cvW6wk2eL4w,101
47
47
  lightning_sdk/cli/mmts_menu.py,sha256=HUXo3ZoZ3fWOCNWTQWoJgUlFXYq5uVm_6uFjAq7BDe8,2219
48
48
  lightning_sdk/cli/open.py,sha256=sgMLWBnkXdIq8H9XK_rph2bye3b07AKTJBQIk9fCGVc,1937
49
49
  lightning_sdk/cli/run.py,sha256=8JZiDrKwDhlaTOJd6qq2mCWJRqKm6shCWLzpbmFYIkE,13929
50
- lightning_sdk/cli/serve.py,sha256=BC8JsaN0QVmPT_W4x1QC93Yyur9w5czAJCcIt2UJx5Q,9654
50
+ lightning_sdk/cli/serve.py,sha256=kpegDpQVfBccXPR7Zhs0IG8A1CMx9ch17NFmcNLPk1s,10750
51
51
  lightning_sdk/cli/start.py,sha256=jUk52lkEFC_fqiEPkwM8GwE68WMNEtzBuzjkvr3POd0,1840
52
52
  lightning_sdk/cli/stop.py,sha256=5nCrUe1BONpX1nKNhbSFqLaXXKaRhSO7PvM1BVYLgn4,2864
53
53
  lightning_sdk/cli/studios_menu.py,sha256=TA9rO6_fFHGMz0Nt4rJ6iV80X5pZE4xShrSiyXoU-oQ,4129
@@ -992,9 +992,9 @@ lightning_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
992
992
  lightning_sdk/utils/dynamic.py,sha256=glUTO1JC9APtQ6Gr9SO02a3zr56-sPAXM5C3NrTpgyQ,1959
993
993
  lightning_sdk/utils/enum.py,sha256=h2JRzqoBcSlUdanFHmkj_j5DleBHAu1esQYUsdNI-hU,4106
994
994
  lightning_sdk/utils/resolve.py,sha256=uYAMAZ-emtFnjdg_sXbKRo3VTe5YWx7WEgCpNlHhHG8,6462
995
- lightning_sdk-0.2.7.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
996
- lightning_sdk-0.2.7.dist-info/METADATA,sha256=AfTdQ9ctYrQ5bNUh-yjMOxIwyHZZbLwizcAnqldNS6E,3991
997
- lightning_sdk-0.2.7.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
998
- lightning_sdk-0.2.7.dist-info/entry_points.txt,sha256=msB9PJWIJ784dX-OP8by51d4IbKYH3Fj1vCuA9oXjHY,68
999
- lightning_sdk-0.2.7.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
1000
- lightning_sdk-0.2.7.dist-info/RECORD,,
995
+ lightning_sdk-0.2.8.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
996
+ lightning_sdk-0.2.8.dist-info/METADATA,sha256=8arXcOw6kN0kchU9glNKNiLzAe0vuUrdjIPdl90C52k,3991
997
+ lightning_sdk-0.2.8.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
998
+ lightning_sdk-0.2.8.dist-info/entry_points.txt,sha256=msB9PJWIJ784dX-OP8by51d4IbKYH3Fj1vCuA9oXjHY,68
999
+ lightning_sdk-0.2.8.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
1000
+ lightning_sdk-0.2.8.dist-info/RECORD,,