lightning-sdk 2025.8.26__py3-none-any.whl → 2025.8.28__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
@@ -32,6 +32,6 @@ __all__ = [
32
32
  "User",
33
33
  ]
34
34
 
35
- __version__ = "2025.08.26"
35
+ __version__ = "2025.08.28"
36
36
  _check_version_and_prompt_upgrade(__version__)
37
37
  _set_tqdm_envvars_noninteractive()
@@ -4,6 +4,7 @@ from typing import Optional
4
4
 
5
5
  import click
6
6
 
7
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
7
8
  from lightning_sdk.cli.utils.save_to_config import save_teamspace_to_config
8
9
  from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
9
10
  from lightning_sdk.lightning_cloud.openapi.rest import ApiException
@@ -56,4 +57,4 @@ def create_studio(
56
57
  raise ValueError(f"Could not create Studio: '{name}'. Does the Studio exist?") from None
57
58
  raise ValueError(f"Could not create Studio: '{name}'. Please provide a Studio name") from None
58
59
 
59
- click.echo(f"Studio '{studio.name}' created successfully")
60
+ click.echo(f"Studio {studio_name_link(studio)} created successfully")
@@ -6,21 +6,29 @@ import click
6
6
  from rich.table import Table
7
7
 
8
8
  from lightning_sdk.cli.utils.cloud_account_map import cloud_account_to_display_name
9
- from lightning_sdk.cli.utils.richt_print import rich_to_str
9
+ from lightning_sdk.cli.utils.richt_print import rich_to_str, studio_name_link
10
10
  from lightning_sdk.cli.utils.save_to_config import save_teamspace_to_config
11
11
  from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
12
12
  from lightning_sdk.studio import Studio
13
+ from lightning_sdk.utils.resolve import _get_authed_user, prevent_refetch_studio
13
14
 
14
15
 
15
16
  @click.command("list")
16
17
  @click.option("--teamspace", help="Override default teamspace (format: owner/teamspace)")
18
+ @click.option(
19
+ "--all",
20
+ is_flag=True,
21
+ flag_value=True,
22
+ default=False,
23
+ help="List all studios, not just the ones belonging to the authed user",
24
+ )
17
25
  @click.option(
18
26
  "--sort-by",
19
27
  default=None,
20
28
  type=click.Choice(["name", "teamspace", "status", "machine", "cloud-account"], case_sensitive=False),
21
29
  help="the attribute to sort the studios by.",
22
30
  )
23
- def list_studios(teamspace: Optional[str] = None, sort_by: Optional[str] = None) -> None:
31
+ def list_studios(teamspace: Optional[str] = None, all: bool = False, sort_by: Optional[str] = None) -> None: # noqa: A002
24
32
  """List Studios in a teamspace.
25
33
 
26
34
  Example:
@@ -31,6 +39,8 @@ def list_studios(teamspace: Optional[str] = None, sort_by: Optional[str] = None)
31
39
  teamspace_resolved = menu(teamspace=teamspace)
32
40
  save_teamspace_to_config(teamspace_resolved, overwrite=False)
33
41
 
42
+ user = _get_authed_user()
43
+
34
44
  studios = teamspace_resolved.studios
35
45
 
36
46
  table = Table(
@@ -42,14 +52,19 @@ def list_studios(teamspace: Optional[str] = None, sort_by: Optional[str] = None)
42
52
  table.add_column("Machine")
43
53
  table.add_column("Cloud account")
44
54
 
45
- for studio in sorted(studios, key=_sort_studios_key(sort_by)):
46
- table.add_row(
47
- studio.name,
48
- f"{studio.teamspace.owner.name}/{studio.teamspace.name}",
49
- str(studio.status),
50
- str(studio.machine) if studio.machine is not None else None, # when None the cell is empty
51
- str(cloud_account_to_display_name(studio.cloud_account, studio.teamspace.id)),
52
- )
55
+ for studio in sorted(
56
+ filter(lambda s: all or s._studio.user_id == user.id, studios), key=_sort_studios_key(sort_by)
57
+ ):
58
+ with prevent_refetch_studio(studio):
59
+ table.add_row(
60
+ # cannot convert to ascii here, as the final rich table has to be converted to ascii
61
+ # otherwise the lack of support for linking in some terminals causes formatting issues.
62
+ studio_name_link(studio, to_ascii=False),
63
+ f"{studio.teamspace.owner.name}/{studio.teamspace.name}",
64
+ str(studio.status),
65
+ str(studio.machine) if studio.machine is not None else None, # when None the cell is empty
66
+ str(cloud_account_to_display_name(studio.cloud_account, studio.teamspace.id)),
67
+ )
53
68
 
54
69
  click.echo(rich_to_str(table), color=True)
55
70
 
@@ -4,6 +4,7 @@ from typing import Optional
4
4
 
5
5
  import click
6
6
 
7
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
7
8
  from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
8
9
  from lightning_sdk.cli.utils.studio_selection import StudiosMenu
9
10
  from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
@@ -45,7 +46,7 @@ def start_studio(
45
46
  name: Optional[str] = None,
46
47
  teamspace: Optional[str] = None,
47
48
  create: bool = False,
48
- machine: Optional[str] = None,
49
+ machine: str = "CPU",
49
50
  interruptible: bool = False,
50
51
  cloud_provider: Optional[str] = None,
51
52
  cloud_account: Optional[str] = None,
@@ -78,4 +79,4 @@ def start_studio(
78
79
 
79
80
  Studio.show_progress = True
80
81
  studio.start(machine, interruptible=interruptible)
81
- click.echo(f"Studio '{studio.name}' started successfully")
82
+ click.echo(f"Studio {studio_name_link(studio)} started successfully")
@@ -4,6 +4,7 @@ from typing import Optional
4
4
 
5
5
  import click
6
6
 
7
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
7
8
  from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
8
9
  from lightning_sdk.cli.utils.studio_selection import StudiosMenu
9
10
  from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
@@ -37,4 +38,4 @@ def stop_studio(name: Optional[str] = None, teamspace: Optional[str] = None) ->
37
38
 
38
39
  save_studio_to_config(studio)
39
40
 
40
- click.echo(f"Studio '{studio.name}' stopped successfully")
41
+ click.echo(f"Studio {studio_name_link(studio)} stopped successfully")
@@ -4,6 +4,7 @@ from typing import Optional
4
4
 
5
5
  import click
6
6
 
7
+ from lightning_sdk.cli.utils.richt_print import studio_name_link
7
8
  from lightning_sdk.cli.utils.save_to_config import save_studio_to_config
8
9
  from lightning_sdk.cli.utils.studio_selection import StudiosMenu
9
10
  from lightning_sdk.cli.utils.teamspace_selection import TeamspacesMenu
@@ -46,4 +47,4 @@ def switch_studio(
46
47
 
47
48
  save_studio_to_config(studio)
48
49
 
49
- click.echo(f"Studio '{studio.name}' switched to machine '{resolved_machine}' successfully")
50
+ click.echo(f"Studio {studio_name_link(studio)} switched to machine '{resolved_machine}' successfully")
@@ -3,9 +3,33 @@ from typing import Any
3
3
 
4
4
  from rich.console import Console
5
5
 
6
+ from lightning_sdk.studio import Studio
7
+ from lightning_sdk.utils.resolve import _get_studio_url
8
+
6
9
 
7
10
  def rich_to_str(*renderables: Any) -> str:
8
11
  with open(os.devnull, "w") as f:
9
12
  console = Console(file=f, record=True)
10
13
  console.print(*renderables)
11
14
  return console.export_text(styles=True)
15
+
16
+
17
+ # not supported on all terminals (e.g. older ones). in that case it's a name without a link
18
+ # see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda#hyperlinks-aka-html-like-anchors-in-terminal-emulators
19
+ # for details and
20
+ # https://github.com/Alhadis/OSC8-Adoption/blob/main/README.md for status of OSC8 adoption
21
+ def studio_name_link(studio: Studio, to_ascii: bool = True) -> str:
22
+ """Hyperlink a studio name.
23
+
24
+ Args:
25
+ studio: the studio whose name to print and link to the studio url
26
+ to_ascii: whether return a plain ascii string with characters for linking converted to ascii as well.
27
+ if False, returns the rich markup directly.
28
+ """
29
+ url = _get_studio_url(studio)
30
+
31
+ studio_link_markup = f"[link={url}]{studio.name}[/link]"
32
+ if not to_ascii:
33
+ return studio_link_markup
34
+
35
+ return rich_to_str(studio_link_markup).strip("\n")
lightning_sdk/studio.py CHANGED
@@ -81,6 +81,7 @@ class Studio:
81
81
  self._studio_api = StudioApi()
82
82
  self._cloud_account_api = CloudAccountApi()
83
83
 
84
+ self._prevent_refetch = False
84
85
  self._teamspace = None
85
86
 
86
87
  # don't resolve anything if we're skipping init
@@ -265,6 +265,17 @@ def skip_studio_setup() -> Generator[None, None, None]:
265
265
  Studio._skip_setup.value = prev_studio_setup_state
266
266
 
267
267
 
268
+ @contextmanager
269
+ def prevent_refetch_studio(studio: "Studio") -> Generator[None, None, None]:
270
+ """Prevent refetching the studio based on current runtime."""
271
+ prev_prevent_refetch_state = getattr(studio, "_prevent_refetch", False)
272
+ studio._prevent_refetch = True
273
+
274
+ yield
275
+
276
+ studio._prevent_refetch = prev_prevent_refetch_state
277
+
278
+
268
279
  def _parse_model_and_version(name: str) -> Tuple[str, Optional[str]]:
269
280
  """Parse the model name and version from the given string.
270
281
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lightning_sdk
3
- Version: 2025.8.26
3
+ Version: 2025.8.28
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=h1e_QoNOLbPkgRajxV8cZgmQ1D1P4U6P_FkGYXx3mPo,1145
2
+ lightning_sdk/__init__.py,sha256=m4U-y4445WQpSE8meItjnzJIFiwx7THsNgH8aGqqAU4,1145
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/base_studio.py,sha256=_Pwwl37R9GRd7t-f2kO5aQXiLNrP4sUtUNht2ZkP8LE,3678
@@ -14,7 +14,7 @@ lightning_sdk/plugin.py,sha256=f3P5-xZY6x-MX0Fs2z_Q2erSxPSiHZARO0BVkCezHw4,15192
14
14
  lightning_sdk/sandbox.py,sha256=_NvnWotEXW2rBiVFZZ4krKXxVjuAqfNh04qELSM0-Pg,5786
15
15
  lightning_sdk/serve.py,sha256=uW7zLhQ3X90ifetpxzTb8FNxifv5vIs7qZlgfEjVKzk,11794
16
16
  lightning_sdk/status.py,sha256=lLGAuSvXBoXQFEEsEYwdCi0RcSNatUn5OPjJVjDtoM0,386
17
- lightning_sdk/studio.py,sha256=0FjD2POIBR7VHAG5RseiwBXn9P0Tpa44U3DKomGgVTQ,30328
17
+ lightning_sdk/studio.py,sha256=N6qxQMJXnaXJK8NXeRxdVg-4az63Tp8eMc-RvfhT8_o,30366
18
18
  lightning_sdk/teamspace.py,sha256=qYpIYgg3eyWj9vcqdfhQN-YCpS47tOc_xB3de07p4Y8,21630
19
19
  lightning_sdk/user.py,sha256=TSYh38rxoi7qKOfrK2JYh_Nknya2Kbz2ngDIY85fFOY,1778
20
20
  lightning_sdk/api/__init__.py,sha256=Qn2VVRvir_gO7w4yxGLkZY-R3T7kdiTPKgQ57BhIA9k,413
@@ -73,18 +73,18 @@ lightning_sdk/cli/legacy/deploy/devbox.py,sha256=SdOtYdGefzldn-WCa6sz31zysyf2nP5
73
73
  lightning_sdk/cli/legacy/deploy/serve.py,sha256=bxN04mHlArjHtxR_QkCM0S_RPmL3WIPsgnPgFadSXwI,15478
74
74
  lightning_sdk/cli/mmt/__init__.py,sha256=CLgr-ZHHLS6Db_JGqpxbn4G2pYrKi4Qn-uhi8e0kFNc,145
75
75
  lightning_sdk/cli/studio/__init__.py,sha256=Reb5a0iHJfNMxmnP30DAmYqpJ-YDQoJcgyVrD2cYDNo,823
76
- lightning_sdk/cli/studio/create.py,sha256=hXLPRkcVl8bIBT0zciSQ4rFOjOmLgjdy0Lg6jmf_EV4,1995
76
+ lightning_sdk/cli/studio/create.py,sha256=MK0OzRV81QgBSxmkQy6YVBJc1cOzq9FSTL2NG5KGI5A,2071
77
77
  lightning_sdk/cli/studio/delete.py,sha256=rzvzNviu9NVeITnCD84PzEEoizrggcq78yaOqrT6U_U,1289
78
- lightning_sdk/cli/studio/list.py,sha256=5cDQu6qH-fh7g48hqCzW10VBJWn93GlIzls7cS4Kitc,2375
78
+ lightning_sdk/cli/studio/list.py,sha256=FUt1SI-uDBWh-ghPFxQZAoxkVdQspGNhy33nkVhdB_o,3079
79
79
  lightning_sdk/cli/studio/ssh.py,sha256=Qlwyl4LISCzFYedhkXArTHqipl_6Yazq7vRcrsc_2ws,3654
80
- lightning_sdk/cli/studio/start.py,sha256=WFdDS4tinYioZY-1s2DnfuOVgEKgAMhj9bujv9Gp2zQ,2628
81
- lightning_sdk/cli/studio/stop.py,sha256=ydfKJMqSrzA_mzF2c5AHRzJJP-bYV-HfO1gsN61IpGs,1159
82
- lightning_sdk/cli/studio/switch.py,sha256=5FdjL1pTrst58jqgx_Jkjo6RtV8vCltmsyldjn_3iNs,1669
80
+ lightning_sdk/cli/studio/start.py,sha256=KuJDwwTnWMhhuihF9qNbcIXa_VPzPH_A8zz-Gck1sn0,2695
81
+ lightning_sdk/cli/studio/stop.py,sha256=d-54OzDYYiY5VNlwIK4oryCH8aafJ7RRBG-ARhcFc4o,1235
82
+ lightning_sdk/cli/studio/switch.py,sha256=qhWhLvjk-BbwU8Br3rXPQIMVQLTUTq21f0v2P-R8VfQ,1745
83
83
  lightning_sdk/cli/utils/__init__.py,sha256=0gHdWY3bqrIyiFiEh_uSBuxWpOykCjqUc8fPEV0z3no,186
84
84
  lightning_sdk/cli/utils/cloud_account_map.py,sha256=7oM7ns4ZJfkxxZhl-GMkxEkkinKbVkskx5dLcyEQiz4,414
85
85
  lightning_sdk/cli/utils/coloring.py,sha256=YEb1LiYb6CekVfCRb83-npAmNgd-7c1LzXuNDo4GLSc,2415
86
86
  lightning_sdk/cli/utils/resolve.py,sha256=RWQ8MgXEJCdsoY50y8Pa9B-A6NA_SvxOqL5pVKfvSr8,917
87
- lightning_sdk/cli/utils/richt_print.py,sha256=8IkTKLWqaE9_1bjJGyk3mNzHtGZZ0_YlmPGrLAtIm7U,276
87
+ lightning_sdk/cli/utils/richt_print.py,sha256=psSY65nLAQbxK_K0w93Qq9857aUUbm77FLS1sc3Oecg,1262
88
88
  lightning_sdk/cli/utils/save_to_config.py,sha256=mMjjfA4Yv1e7MtE03iADTXcTSAuUL0Ws9OZObx6ufo0,1164
89
89
  lightning_sdk/cli/utils/studio_selection.py,sha256=tjYTm4sY3NSQaa-6Ob9R0UQ60wIXiTNT2406BUJvJbU,3927
90
90
  lightning_sdk/cli/utils/teamspace_selection.py,sha256=ZWo_aZuEuLzBWRgQEykypEM1sE_deDKLDcCyLgFWaaQ,5188
@@ -1143,10 +1143,10 @@ lightning_sdk/utils/dynamic.py,sha256=glUTO1JC9APtQ6Gr9SO02a3zr56-sPAXM5C3NrTpgy
1143
1143
  lightning_sdk/utils/enum.py,sha256=h2JRzqoBcSlUdanFHmkj_j5DleBHAu1esQYUsdNI-hU,4106
1144
1144
  lightning_sdk/utils/names.py,sha256=1EuXbIh7wldkDp1FG10oz9vIOyWrpGWeFFVy-DQBgzA,18162
1145
1145
  lightning_sdk/utils/progress.py,sha256=IXfEcUF-rL5jIw0Hir6eSxN7VBZfR--1O2LaEhGAU70,12698
1146
- lightning_sdk/utils/resolve.py,sha256=yqv-0NOIG_qnSvlvOaGK11PG8RuKHkstiZMV8GAFnhM,10136
1147
- lightning_sdk-2025.8.26.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
1148
- lightning_sdk-2025.8.26.dist-info/METADATA,sha256=wTC_RLAWY2vOMdpikf-R7owxuIxY5QYDpQzJat_7LXo,4130
1149
- lightning_sdk-2025.8.26.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1150
- lightning_sdk-2025.8.26.dist-info/entry_points.txt,sha256=msB9PJWIJ784dX-OP8by51d4IbKYH3Fj1vCuA9oXjHY,68
1151
- lightning_sdk-2025.8.26.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
1152
- lightning_sdk-2025.8.26.dist-info/RECORD,,
1146
+ lightning_sdk/utils/resolve.py,sha256=4TyEnIgIrvkSvYk5i5PmcIogD_5Y9pBhiphRLfLMttc,10477
1147
+ lightning_sdk-2025.8.28.dist-info/LICENSE,sha256=uFIuZwj5z-4TeF2UuacPZ1o17HkvKObT8fY50qN84sg,1064
1148
+ lightning_sdk-2025.8.28.dist-info/METADATA,sha256=LLjYF3GZy05IhP4gHBgNfKxuZUMtAB-ujgvYzTEuT9o,4130
1149
+ lightning_sdk-2025.8.28.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1150
+ lightning_sdk-2025.8.28.dist-info/entry_points.txt,sha256=msB9PJWIJ784dX-OP8by51d4IbKYH3Fj1vCuA9oXjHY,68
1151
+ lightning_sdk-2025.8.28.dist-info/top_level.txt,sha256=ps8doKILFXmN7F1mHncShmnQoTxKBRPIcchC8TpoBw4,19
1152
+ lightning_sdk-2025.8.28.dist-info/RECORD,,